@casualoffice/sheets 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chrome.cjs +3339 -244
- package/dist/chrome.cjs.map +1 -1
- package/dist/chrome.js +3298 -203
- package/dist/chrome.js.map +1 -1
- package/dist/embed/embed-runtime.js +203 -157
- package/dist/index.cjs +5971 -1572
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5961 -1548
- package/dist/index.js.map +1 -1
- package/dist/sheets.cjs +4937 -538
- package/dist/sheets.cjs.map +1 -1
- package/dist/sheets.js +4945 -532
- package/dist/sheets.js.map +1 -1
- package/package.json +8 -7
- package/src/charts/ChartContextMenu.tsx +264 -0
- package/src/charts/ChartLayer.tsx +333 -0
- package/src/charts/ChartOverlay.tsx +293 -0
- package/src/charts/ChartsPanel.tsx +211 -0
- package/src/charts/FormatChartDialog.tsx +419 -0
- package/src/charts/InsertChartDialog.tsx +478 -0
- package/src/charts/build-option.ts +476 -0
- package/src/charts/charts-context.tsx +205 -0
- package/src/charts/echarts-init.ts +58 -0
- package/src/charts/hit-test.ts +130 -0
- package/src/charts/insert-chart.ts +106 -0
- package/src/charts/naming.ts +38 -0
- package/src/charts/render-to-png.ts +117 -0
- package/src/charts/resources.ts +108 -0
- package/src/charts/types.ts +239 -0
- package/src/charts/univer-dom.ts +102 -0
- package/src/chrome/CommentsPanel.tsx +427 -0
- package/src/chrome/ConditionalFormattingDialog.tsx +534 -0
- package/src/chrome/CustomSortDialog.tsx +357 -0
- package/src/chrome/DataValidationDialog.tsx +536 -0
- package/src/chrome/DeleteCellsDialog.tsx +183 -0
- package/src/chrome/GoalSeekDialog.tsx +370 -0
- package/src/chrome/HistoryPanel.tsx +319 -0
- package/src/chrome/InsertCellsDialog.tsx +185 -0
- package/src/chrome/InsertChartDialog.tsx +490 -0
- package/src/chrome/InsertFunctionDialog.tsx +493 -0
- package/src/chrome/InsertPivotDialog.tsx +488 -0
- package/src/chrome/InsertSparklineDialog.tsx +344 -0
- package/src/chrome/NameManagerDialog.tsx +378 -0
- package/src/chrome/PanelHost.tsx +55 -0
- package/src/chrome/PanelRail.tsx +90 -0
- package/src/chrome/PasteSpecialDialog.tsx +286 -0
- package/src/chrome/PivotFieldsPanel.tsx +1052 -0
- package/src/chrome/TablesPanel.tsx +301 -0
- package/src/chrome/dialog-context.tsx +24 -0
- package/src/chrome/panel-context.tsx +55 -0
- package/src/chrome/panel-registry.ts +48 -0
- package/src/sheets/CasualSheets.tsx +60 -34
package/dist/chrome.cjs
CHANGED
|
@@ -53,8 +53,8 @@ __export(chrome_exports, {
|
|
|
53
53
|
module.exports = __toCommonJS(chrome_exports);
|
|
54
54
|
|
|
55
55
|
// src/chrome/Toolbar.tsx
|
|
56
|
-
var
|
|
57
|
-
var
|
|
56
|
+
var import_react19 = require("react");
|
|
57
|
+
var import_core4 = require("@univerjs/core");
|
|
58
58
|
|
|
59
59
|
// src/chrome/Icon.tsx
|
|
60
60
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -580,7 +580,7 @@ function AutoSumPicker({ api }) {
|
|
|
580
580
|
}
|
|
581
581
|
|
|
582
582
|
// src/chrome/dialog-context.tsx
|
|
583
|
-
var
|
|
583
|
+
var import_react18 = require("react");
|
|
584
584
|
|
|
585
585
|
// src/chrome/FormatCellsDialog.tsx
|
|
586
586
|
var import_react5 = require("react");
|
|
@@ -1163,36 +1163,3131 @@ function FormatCellsDialog({ api, onClose }) {
|
|
|
1163
1163
|
)
|
|
1164
1164
|
] })
|
|
1165
1165
|
] }),
|
|
1166
|
-
tab === "fill" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1167
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Fill color" }),
|
|
1168
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1166
|
+
tab === "fill" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1167
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Fill color" }),
|
|
1168
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1169
|
+
"input",
|
|
1170
|
+
{
|
|
1171
|
+
style: COLOR_INPUT_STYLE,
|
|
1172
|
+
"data-testid": "cs-format-cells-fill-color",
|
|
1173
|
+
type: "color",
|
|
1174
|
+
value: state.fillColor,
|
|
1175
|
+
onChange: (e) => update("fillColor", e.target.value)
|
|
1176
|
+
}
|
|
1177
|
+
)
|
|
1178
|
+
] })
|
|
1179
|
+
] })
|
|
1180
|
+
]
|
|
1181
|
+
}
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// src/chrome/DataValidationDialog.tsx
|
|
1186
|
+
var import_react6 = require("react");
|
|
1187
|
+
var import_facade = require("@univerjs/sheets-data-validation/facade");
|
|
1188
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1189
|
+
var RULE_TYPE_OPTIONS = [
|
|
1190
|
+
{ value: "list", label: "List of items" },
|
|
1191
|
+
{ value: "number", label: "Whole number" },
|
|
1192
|
+
{ value: "decimal", label: "Decimal" },
|
|
1193
|
+
{ value: "date", label: "Date" },
|
|
1194
|
+
{ value: "textLength", label: "Text length" },
|
|
1195
|
+
{ value: "checkbox", label: "Checkbox" }
|
|
1196
|
+
];
|
|
1197
|
+
var OPERATOR_OPTIONS = [
|
|
1198
|
+
{ value: "between", label: "Between" },
|
|
1199
|
+
{ value: "notBetween", label: "Not between" },
|
|
1200
|
+
{ value: "equal", label: "Equal to" },
|
|
1201
|
+
{ value: "notEqual", label: "Not equal to" },
|
|
1202
|
+
{ value: "greater", label: "Greater than" },
|
|
1203
|
+
{ value: "greaterEqual", label: "Greater than or equal to" },
|
|
1204
|
+
{ value: "less", label: "Less than" },
|
|
1205
|
+
{ value: "lessEqual", label: "Less than or equal to" }
|
|
1206
|
+
];
|
|
1207
|
+
function isRangeOperator(op) {
|
|
1208
|
+
return op === "between" || op === "notBetween";
|
|
1209
|
+
}
|
|
1210
|
+
function usesOperator(type) {
|
|
1211
|
+
return type === "number" || type === "decimal" || type === "date" || type === "textLength";
|
|
1212
|
+
}
|
|
1213
|
+
var INITIAL_STATE = {
|
|
1214
|
+
ruleType: "list",
|
|
1215
|
+
operator: "between",
|
|
1216
|
+
operand1: "",
|
|
1217
|
+
operand2: "",
|
|
1218
|
+
listItems: "",
|
|
1219
|
+
ignoreBlank: true,
|
|
1220
|
+
showErrorMessage: false,
|
|
1221
|
+
errorMessage: "",
|
|
1222
|
+
showInputMessage: false,
|
|
1223
|
+
inputMessage: ""
|
|
1224
|
+
};
|
|
1225
|
+
function activeRange2(api) {
|
|
1226
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
1227
|
+
}
|
|
1228
|
+
function applyValidation(api, s, remove) {
|
|
1229
|
+
const range = activeRange2(api);
|
|
1230
|
+
if (!range) return false;
|
|
1231
|
+
const dvRange = range;
|
|
1232
|
+
if (remove) {
|
|
1233
|
+
dvRange.setDataValidation(null);
|
|
1234
|
+
return true;
|
|
1235
|
+
}
|
|
1236
|
+
const builder = api.univer.newDataValidation();
|
|
1237
|
+
const n1 = Number(s.operand1);
|
|
1238
|
+
const n2 = Number(s.operand2);
|
|
1239
|
+
const wholeNumber = s.ruleType === "number";
|
|
1240
|
+
switch (s.ruleType) {
|
|
1241
|
+
case "list": {
|
|
1242
|
+
const values = s.listItems.split(/[\n,]/).map((v) => v.trim()).filter((v) => v.length > 0);
|
|
1243
|
+
if (values.length === 0) return false;
|
|
1244
|
+
builder.requireValueInList(values, false, true);
|
|
1245
|
+
break;
|
|
1246
|
+
}
|
|
1247
|
+
case "number":
|
|
1248
|
+
case "decimal": {
|
|
1249
|
+
if (!Number.isFinite(n1)) return false;
|
|
1250
|
+
switch (s.operator) {
|
|
1251
|
+
case "between":
|
|
1252
|
+
if (!Number.isFinite(n2)) return false;
|
|
1253
|
+
builder.requireNumberBetween(n1, n2, wholeNumber);
|
|
1254
|
+
break;
|
|
1255
|
+
case "notBetween":
|
|
1256
|
+
if (!Number.isFinite(n2)) return false;
|
|
1257
|
+
builder.requireNumberNotBetween(n1, n2, wholeNumber);
|
|
1258
|
+
break;
|
|
1259
|
+
case "equal":
|
|
1260
|
+
builder.requireNumberEqualTo(n1, wholeNumber);
|
|
1261
|
+
break;
|
|
1262
|
+
case "notEqual":
|
|
1263
|
+
builder.requireNumberNotEqualTo(n1, wholeNumber);
|
|
1264
|
+
break;
|
|
1265
|
+
case "greater":
|
|
1266
|
+
builder.requireNumberGreaterThan(n1, wholeNumber);
|
|
1267
|
+
break;
|
|
1268
|
+
case "greaterEqual":
|
|
1269
|
+
builder.requireNumberGreaterThanOrEqualTo(n1, wholeNumber);
|
|
1270
|
+
break;
|
|
1271
|
+
case "less":
|
|
1272
|
+
builder.requireNumberLessThan(n1, wholeNumber);
|
|
1273
|
+
break;
|
|
1274
|
+
case "lessEqual":
|
|
1275
|
+
builder.requireNumberLessThanOrEqualTo(n1, wholeNumber);
|
|
1276
|
+
break;
|
|
1277
|
+
}
|
|
1278
|
+
break;
|
|
1279
|
+
}
|
|
1280
|
+
case "date": {
|
|
1281
|
+
const d1 = new Date(s.operand1);
|
|
1282
|
+
const d2 = new Date(s.operand2);
|
|
1283
|
+
if (Number.isNaN(d1.getTime())) return false;
|
|
1284
|
+
switch (s.operator) {
|
|
1285
|
+
case "between":
|
|
1286
|
+
if (Number.isNaN(d2.getTime())) return false;
|
|
1287
|
+
builder.requireDateBetween(d1, d2);
|
|
1288
|
+
break;
|
|
1289
|
+
case "notBetween":
|
|
1290
|
+
if (Number.isNaN(d2.getTime())) return false;
|
|
1291
|
+
builder.requireDateNotBetween(d1, d2);
|
|
1292
|
+
break;
|
|
1293
|
+
case "equal":
|
|
1294
|
+
builder.requireDateEqualTo(d1);
|
|
1295
|
+
break;
|
|
1296
|
+
// The builder has no requireDateNotEqualTo; map the remaining operators
|
|
1297
|
+
// to the closest available on/after / on/before methods.
|
|
1298
|
+
case "notEqual":
|
|
1299
|
+
case "greater":
|
|
1300
|
+
builder.requireDateAfter(d1);
|
|
1301
|
+
break;
|
|
1302
|
+
case "greaterEqual":
|
|
1303
|
+
builder.requireDateOnOrAfter(d1);
|
|
1304
|
+
break;
|
|
1305
|
+
case "less":
|
|
1306
|
+
builder.requireDateBefore(d1);
|
|
1307
|
+
break;
|
|
1308
|
+
case "lessEqual":
|
|
1309
|
+
builder.requireDateOnOrBefore(d1);
|
|
1310
|
+
break;
|
|
1311
|
+
}
|
|
1312
|
+
break;
|
|
1313
|
+
}
|
|
1314
|
+
case "textLength": {
|
|
1315
|
+
if (!Number.isFinite(n1)) return false;
|
|
1316
|
+
const anchor = dvRange.getA1Notation?.() ?? "A1";
|
|
1317
|
+
const cell = anchor.split(":")[0];
|
|
1318
|
+
const len = `LEN(${cell})`;
|
|
1319
|
+
let formula;
|
|
1320
|
+
switch (s.operator) {
|
|
1321
|
+
case "between":
|
|
1322
|
+
if (!Number.isFinite(n2)) return false;
|
|
1323
|
+
formula = `=AND(${len}>=${n1}, ${len}<=${n2})`;
|
|
1324
|
+
break;
|
|
1325
|
+
case "notBetween":
|
|
1326
|
+
if (!Number.isFinite(n2)) return false;
|
|
1327
|
+
formula = `=OR(${len}<${n1}, ${len}>${n2})`;
|
|
1328
|
+
break;
|
|
1329
|
+
case "equal":
|
|
1330
|
+
formula = `=${len}=${n1}`;
|
|
1331
|
+
break;
|
|
1332
|
+
case "notEqual":
|
|
1333
|
+
formula = `=${len}<>${n1}`;
|
|
1334
|
+
break;
|
|
1335
|
+
case "greater":
|
|
1336
|
+
formula = `=${len}>${n1}`;
|
|
1337
|
+
break;
|
|
1338
|
+
case "greaterEqual":
|
|
1339
|
+
formula = `=${len}>=${n1}`;
|
|
1340
|
+
break;
|
|
1341
|
+
case "less":
|
|
1342
|
+
formula = `=${len}<${n1}`;
|
|
1343
|
+
break;
|
|
1344
|
+
case "lessEqual":
|
|
1345
|
+
formula = `=${len}<=${n1}`;
|
|
1346
|
+
break;
|
|
1347
|
+
}
|
|
1348
|
+
builder.requireFormulaSatisfied(formula);
|
|
1349
|
+
break;
|
|
1350
|
+
}
|
|
1351
|
+
case "checkbox":
|
|
1352
|
+
builder.requireCheckbox();
|
|
1353
|
+
break;
|
|
1354
|
+
}
|
|
1355
|
+
builder.setAllowBlank(s.ignoreBlank);
|
|
1356
|
+
builder.setOptions({
|
|
1357
|
+
showErrorMessage: s.showErrorMessage,
|
|
1358
|
+
error: s.showErrorMessage ? s.errorMessage : void 0,
|
|
1359
|
+
showInputMessage: s.showInputMessage,
|
|
1360
|
+
prompt: s.showInputMessage ? s.inputMessage : void 0
|
|
1361
|
+
});
|
|
1362
|
+
dvRange.setDataValidation(builder.build());
|
|
1363
|
+
return true;
|
|
1364
|
+
}
|
|
1365
|
+
var CHECK_STYLE2 = {
|
|
1366
|
+
display: "flex",
|
|
1367
|
+
alignItems: "center",
|
|
1368
|
+
gap: 6,
|
|
1369
|
+
marginBottom: 8,
|
|
1370
|
+
cursor: "pointer"
|
|
1371
|
+
};
|
|
1372
|
+
var TEXTAREA_STYLE = {
|
|
1373
|
+
...DIALOG_INPUT_STYLE,
|
|
1374
|
+
height: "auto",
|
|
1375
|
+
minHeight: 64,
|
|
1376
|
+
padding: "6px 8px",
|
|
1377
|
+
resize: "vertical",
|
|
1378
|
+
lineHeight: 1.4
|
|
1379
|
+
};
|
|
1380
|
+
var RANGE_NOTE_STYLE = {
|
|
1381
|
+
fontSize: 12,
|
|
1382
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
1383
|
+
marginBottom: 12
|
|
1384
|
+
};
|
|
1385
|
+
var TWO_COL_STYLE = {
|
|
1386
|
+
display: "grid",
|
|
1387
|
+
gridTemplateColumns: "1fr 1fr",
|
|
1388
|
+
gap: 8
|
|
1389
|
+
};
|
|
1390
|
+
function DataValidationDialog({ api, onClose }) {
|
|
1391
|
+
const [state, setState] = (0, import_react6.useState)(INITIAL_STATE);
|
|
1392
|
+
const rangeLabel = (0, import_react6.useMemo)(() => {
|
|
1393
|
+
const fRange = activeRange2(api);
|
|
1394
|
+
return fRange?.getA1Notation?.() ?? null;
|
|
1395
|
+
}, [api]);
|
|
1396
|
+
const hasSelection = activeRange2(api) !== null;
|
|
1397
|
+
const update = (key, value) => setState((prev) => ({ ...prev, [key]: value }));
|
|
1398
|
+
const apply = () => {
|
|
1399
|
+
if (applyValidation(api, state, false)) onClose();
|
|
1400
|
+
};
|
|
1401
|
+
const removeRule = () => {
|
|
1402
|
+
applyValidation(api, state, true);
|
|
1403
|
+
onClose();
|
|
1404
|
+
};
|
|
1405
|
+
const showOperator = usesOperator(state.ruleType);
|
|
1406
|
+
const showSecondOperand = showOperator && isRangeOperator(state.operator);
|
|
1407
|
+
const operandType = state.ruleType === "date" ? "date" : "number";
|
|
1408
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1409
|
+
Dialog,
|
|
1410
|
+
{
|
|
1411
|
+
title: "Data validation",
|
|
1412
|
+
onClose,
|
|
1413
|
+
width: 440,
|
|
1414
|
+
"data-testid": "cs-data-validation-dialog",
|
|
1415
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1416
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1417
|
+
"button",
|
|
1418
|
+
{
|
|
1419
|
+
type: "button",
|
|
1420
|
+
style: DIALOG_BTN_SECONDARY_STYLE,
|
|
1421
|
+
"data-testid": "cs-data-validation-remove",
|
|
1422
|
+
onClick: removeRule,
|
|
1423
|
+
children: "Remove rule"
|
|
1424
|
+
}
|
|
1425
|
+
),
|
|
1426
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { flex: 1 } }),
|
|
1427
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1429
|
+
"button",
|
|
1430
|
+
{
|
|
1431
|
+
type: "button",
|
|
1432
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
1433
|
+
"data-testid": "cs-data-validation-apply",
|
|
1434
|
+
disabled: !hasSelection,
|
|
1435
|
+
onClick: apply,
|
|
1436
|
+
children: "Apply"
|
|
1437
|
+
}
|
|
1438
|
+
)
|
|
1439
|
+
] }),
|
|
1440
|
+
children: [
|
|
1441
|
+
hasSelection ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: RANGE_NOTE_STYLE, "data-testid": "cs-data-validation-range", children: [
|
|
1442
|
+
"Applies to ",
|
|
1443
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: rangeLabel ?? "the current selection" })
|
|
1444
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: RANGE_NOTE_STYLE, "data-testid": "cs-data-validation-no-selection", children: "Select one or more cells first, then reopen this dialog." }),
|
|
1445
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1446
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Criteria" }),
|
|
1447
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1448
|
+
"select",
|
|
1449
|
+
{
|
|
1450
|
+
style: DIALOG_INPUT_STYLE,
|
|
1451
|
+
"data-testid": "cs-data-validation-type",
|
|
1452
|
+
value: state.ruleType,
|
|
1453
|
+
onChange: (e) => update("ruleType", e.target.value),
|
|
1454
|
+
children: RULE_TYPE_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
|
|
1455
|
+
}
|
|
1456
|
+
)
|
|
1457
|
+
] }),
|
|
1458
|
+
state.ruleType === "list" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1459
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Items (one per line, or comma-separated)" }),
|
|
1460
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1461
|
+
"textarea",
|
|
1462
|
+
{
|
|
1463
|
+
style: TEXTAREA_STYLE,
|
|
1464
|
+
"data-testid": "cs-data-validation-list-items",
|
|
1465
|
+
value: state.listItems,
|
|
1466
|
+
placeholder: "Yes\nNo\nMaybe",
|
|
1467
|
+
onChange: (e) => update("listItems", e.target.value)
|
|
1468
|
+
}
|
|
1469
|
+
)
|
|
1470
|
+
] }),
|
|
1471
|
+
showOperator && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1472
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1473
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Condition" }),
|
|
1474
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1475
|
+
"select",
|
|
1476
|
+
{
|
|
1477
|
+
style: DIALOG_INPUT_STYLE,
|
|
1478
|
+
"data-testid": "cs-data-validation-operator",
|
|
1479
|
+
value: state.operator,
|
|
1480
|
+
onChange: (e) => update("operator", e.target.value),
|
|
1481
|
+
children: OPERATOR_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
|
|
1482
|
+
}
|
|
1483
|
+
)
|
|
1484
|
+
] }),
|
|
1485
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: showSecondOperand ? TWO_COL_STYLE : void 0, children: [
|
|
1486
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1487
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: DIALOG_LABEL_STYLE, children: showSecondOperand ? "Minimum" : "Value" }),
|
|
1488
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1489
|
+
"input",
|
|
1490
|
+
{
|
|
1491
|
+
style: DIALOG_INPUT_STYLE,
|
|
1492
|
+
"data-testid": "cs-data-validation-operand1",
|
|
1493
|
+
type: operandType,
|
|
1494
|
+
value: state.operand1,
|
|
1495
|
+
onChange: (e) => update("operand1", e.target.value)
|
|
1496
|
+
}
|
|
1497
|
+
)
|
|
1498
|
+
] }),
|
|
1499
|
+
showSecondOperand && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1500
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Maximum" }),
|
|
1501
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1502
|
+
"input",
|
|
1503
|
+
{
|
|
1504
|
+
style: DIALOG_INPUT_STYLE,
|
|
1505
|
+
"data-testid": "cs-data-validation-operand2",
|
|
1506
|
+
type: operandType,
|
|
1507
|
+
value: state.operand2,
|
|
1508
|
+
onChange: (e) => update("operand2", e.target.value)
|
|
1509
|
+
}
|
|
1510
|
+
)
|
|
1511
|
+
] })
|
|
1512
|
+
] })
|
|
1513
|
+
] }),
|
|
1514
|
+
state.ruleType === "checkbox" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: RANGE_NOTE_STYLE, children: "Each cell in the selection becomes a checkbox (checked = TRUE)." }),
|
|
1515
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: CHECK_STYLE2, "data-testid": "cs-data-validation-ignore-blank-label", children: [
|
|
1516
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1517
|
+
"input",
|
|
1518
|
+
{
|
|
1519
|
+
type: "checkbox",
|
|
1520
|
+
"data-testid": "cs-data-validation-ignore-blank",
|
|
1521
|
+
checked: state.ignoreBlank,
|
|
1522
|
+
onChange: (e) => update("ignoreBlank", e.target.checked)
|
|
1523
|
+
}
|
|
1524
|
+
),
|
|
1525
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Ignore blank cells" })
|
|
1526
|
+
] }),
|
|
1527
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: CHECK_STYLE2, children: [
|
|
1528
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1529
|
+
"input",
|
|
1530
|
+
{
|
|
1531
|
+
type: "checkbox",
|
|
1532
|
+
"data-testid": "cs-data-validation-show-input",
|
|
1533
|
+
checked: state.showInputMessage,
|
|
1534
|
+
onChange: (e) => update("showInputMessage", e.target.checked)
|
|
1535
|
+
}
|
|
1536
|
+
),
|
|
1537
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Show input message" })
|
|
1538
|
+
] }),
|
|
1539
|
+
state.showInputMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1540
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Input message" }),
|
|
1541
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1542
|
+
"input",
|
|
1543
|
+
{
|
|
1544
|
+
style: DIALOG_INPUT_STYLE,
|
|
1545
|
+
"data-testid": "cs-data-validation-input-message",
|
|
1546
|
+
value: state.inputMessage,
|
|
1547
|
+
onChange: (e) => update("inputMessage", e.target.value)
|
|
1548
|
+
}
|
|
1549
|
+
)
|
|
1550
|
+
] }),
|
|
1551
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: CHECK_STYLE2, children: [
|
|
1552
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1553
|
+
"input",
|
|
1554
|
+
{
|
|
1555
|
+
type: "checkbox",
|
|
1556
|
+
"data-testid": "cs-data-validation-show-error",
|
|
1557
|
+
checked: state.showErrorMessage,
|
|
1558
|
+
onChange: (e) => update("showErrorMessage", e.target.checked)
|
|
1559
|
+
}
|
|
1560
|
+
),
|
|
1561
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Show error message on invalid input" })
|
|
1562
|
+
] }),
|
|
1563
|
+
state.showErrorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1564
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Error message" }),
|
|
1565
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1566
|
+
"input",
|
|
1567
|
+
{
|
|
1568
|
+
style: DIALOG_INPUT_STYLE,
|
|
1569
|
+
"data-testid": "cs-data-validation-error-message",
|
|
1570
|
+
value: state.errorMessage,
|
|
1571
|
+
onChange: (e) => update("errorMessage", e.target.value)
|
|
1572
|
+
}
|
|
1573
|
+
)
|
|
1574
|
+
] })
|
|
1575
|
+
]
|
|
1576
|
+
}
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
// src/chrome/ConditionalFormattingDialog.tsx
|
|
1581
|
+
var import_react7 = require("react");
|
|
1582
|
+
var import_facade2 = require("@univerjs/sheets-conditional-formatting/facade");
|
|
1583
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1584
|
+
var RULE_TYPE_OPTIONS2 = [
|
|
1585
|
+
{ value: "cellValue", label: "Cell value" },
|
|
1586
|
+
{ value: "textContains", label: "Text contains" },
|
|
1587
|
+
{ value: "topN", label: "Top N" },
|
|
1588
|
+
{ value: "bottomN", label: "Bottom N" },
|
|
1589
|
+
{ value: "colorScale", label: "Color scale" }
|
|
1590
|
+
];
|
|
1591
|
+
var OPERATOR_OPTIONS2 = [
|
|
1592
|
+
{ value: "greater", label: "Greater than" },
|
|
1593
|
+
{ value: "greaterEqual", label: "Greater than or equal to" },
|
|
1594
|
+
{ value: "less", label: "Less than" },
|
|
1595
|
+
{ value: "lessEqual", label: "Less than or equal to" },
|
|
1596
|
+
{ value: "equal", label: "Equal to" },
|
|
1597
|
+
{ value: "notEqual", label: "Not equal to" },
|
|
1598
|
+
{ value: "between", label: "Between" },
|
|
1599
|
+
{ value: "notBetween", label: "Not between" }
|
|
1600
|
+
];
|
|
1601
|
+
function isRangeOperator2(op) {
|
|
1602
|
+
return op === "between" || op === "notBetween";
|
|
1603
|
+
}
|
|
1604
|
+
var INITIAL_STATE2 = {
|
|
1605
|
+
ruleType: "cellValue",
|
|
1606
|
+
operator: "greater",
|
|
1607
|
+
operand1: "",
|
|
1608
|
+
operand2: "",
|
|
1609
|
+
text: "",
|
|
1610
|
+
rankN: "10",
|
|
1611
|
+
rankPercent: false,
|
|
1612
|
+
fillColor: "#fce8b2",
|
|
1613
|
+
textColor: "#7f6000",
|
|
1614
|
+
scaleMinColor: "#ffffff",
|
|
1615
|
+
scaleMaxColor: "#57bb8a"
|
|
1616
|
+
};
|
|
1617
|
+
function activeRange3(api) {
|
|
1618
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
1619
|
+
}
|
|
1620
|
+
function activeSheet(api) {
|
|
1621
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet() ?? null;
|
|
1622
|
+
}
|
|
1623
|
+
function usesHighlight(type) {
|
|
1624
|
+
return type !== "colorScale";
|
|
1625
|
+
}
|
|
1626
|
+
function applyRule(api, s) {
|
|
1627
|
+
const range = activeRange3(api);
|
|
1628
|
+
const sheet = activeSheet(api);
|
|
1629
|
+
if (!range || !sheet) return false;
|
|
1630
|
+
const cfSheet = sheet;
|
|
1631
|
+
const iRange = range.getRange();
|
|
1632
|
+
const n1 = Number(s.operand1);
|
|
1633
|
+
const n2 = Number(s.operand2);
|
|
1634
|
+
const rankN = Number(s.rankN);
|
|
1635
|
+
let builder = cfSheet.newConditionalFormattingRule();
|
|
1636
|
+
switch (s.ruleType) {
|
|
1637
|
+
case "cellValue": {
|
|
1638
|
+
if (!Number.isFinite(n1)) return false;
|
|
1639
|
+
switch (s.operator) {
|
|
1640
|
+
case "greater":
|
|
1641
|
+
builder = builder.whenNumberGreaterThan(n1);
|
|
1642
|
+
break;
|
|
1643
|
+
case "greaterEqual":
|
|
1644
|
+
builder = builder.whenNumberGreaterThanOrEqualTo(n1);
|
|
1645
|
+
break;
|
|
1646
|
+
case "less":
|
|
1647
|
+
builder = builder.whenNumberLessThan(n1);
|
|
1648
|
+
break;
|
|
1649
|
+
case "lessEqual":
|
|
1650
|
+
builder = builder.whenNumberLessThanOrEqualTo(n1);
|
|
1651
|
+
break;
|
|
1652
|
+
case "equal":
|
|
1653
|
+
builder = builder.whenNumberEqualTo(n1);
|
|
1654
|
+
break;
|
|
1655
|
+
case "notEqual":
|
|
1656
|
+
builder = builder.whenNumberNotEqualTo(n1);
|
|
1657
|
+
break;
|
|
1658
|
+
case "between":
|
|
1659
|
+
if (!Number.isFinite(n2)) return false;
|
|
1660
|
+
builder = builder.whenNumberBetween(n1, n2);
|
|
1661
|
+
break;
|
|
1662
|
+
case "notBetween":
|
|
1663
|
+
if (!Number.isFinite(n2)) return false;
|
|
1664
|
+
builder = builder.whenNumberNotBetween(n1, n2);
|
|
1665
|
+
break;
|
|
1666
|
+
}
|
|
1667
|
+
break;
|
|
1668
|
+
}
|
|
1669
|
+
case "textContains": {
|
|
1670
|
+
const text = s.text.trim();
|
|
1671
|
+
if (text.length === 0) return false;
|
|
1672
|
+
builder = builder.whenTextContains(text);
|
|
1673
|
+
break;
|
|
1674
|
+
}
|
|
1675
|
+
case "topN":
|
|
1676
|
+
case "bottomN": {
|
|
1677
|
+
if (!Number.isFinite(rankN) || rankN <= 0) return false;
|
|
1678
|
+
builder = builder.setRank({
|
|
1679
|
+
isBottom: s.ruleType === "bottomN",
|
|
1680
|
+
isPercent: s.rankPercent,
|
|
1681
|
+
value: rankN
|
|
1682
|
+
});
|
|
1683
|
+
break;
|
|
1684
|
+
}
|
|
1685
|
+
case "colorScale": {
|
|
1686
|
+
builder = builder.setColorScale([
|
|
1687
|
+
{ index: 0, color: s.scaleMinColor, value: { type: "min" } },
|
|
1688
|
+
{ index: 1, color: s.scaleMaxColor, value: { type: "max" } }
|
|
1689
|
+
]);
|
|
1690
|
+
break;
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
if (usesHighlight(s.ruleType)) {
|
|
1694
|
+
builder = builder.setBackground(s.fillColor);
|
|
1695
|
+
builder = builder.setFontColor(s.textColor);
|
|
1696
|
+
}
|
|
1697
|
+
const rule = builder.setRanges([iRange]).build();
|
|
1698
|
+
cfSheet.addConditionalFormattingRule(rule);
|
|
1699
|
+
return true;
|
|
1700
|
+
}
|
|
1701
|
+
var RANGE_NOTE_STYLE2 = {
|
|
1702
|
+
fontSize: 12,
|
|
1703
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
1704
|
+
marginBottom: 12
|
|
1705
|
+
};
|
|
1706
|
+
var CHECK_STYLE3 = {
|
|
1707
|
+
display: "flex",
|
|
1708
|
+
alignItems: "center",
|
|
1709
|
+
gap: 6,
|
|
1710
|
+
marginBottom: 8,
|
|
1711
|
+
cursor: "pointer"
|
|
1712
|
+
};
|
|
1713
|
+
var COLOR_INPUT_STYLE2 = {
|
|
1714
|
+
width: 48,
|
|
1715
|
+
height: 30,
|
|
1716
|
+
padding: 2,
|
|
1717
|
+
border: "1px solid var(--cs-chrome-border, #cdd3db)",
|
|
1718
|
+
borderRadius: 6,
|
|
1719
|
+
background: "var(--cs-chrome-input-bg, #fff)",
|
|
1720
|
+
cursor: "pointer"
|
|
1721
|
+
};
|
|
1722
|
+
var TWO_COL_STYLE2 = {
|
|
1723
|
+
display: "grid",
|
|
1724
|
+
gridTemplateColumns: "1fr 1fr",
|
|
1725
|
+
gap: 8
|
|
1726
|
+
};
|
|
1727
|
+
function ConditionalFormattingDialog({ api, onClose }) {
|
|
1728
|
+
const [state, setState] = (0, import_react7.useState)(INITIAL_STATE2);
|
|
1729
|
+
const rangeLabel = (0, import_react7.useMemo)(() => {
|
|
1730
|
+
const fRange = activeRange3(api);
|
|
1731
|
+
return fRange?.getA1Notation?.() ?? null;
|
|
1732
|
+
}, [api]);
|
|
1733
|
+
const hasSelection = activeRange3(api) !== null;
|
|
1734
|
+
const update = (key, value) => setState((prev) => ({ ...prev, [key]: value }));
|
|
1735
|
+
const apply = () => {
|
|
1736
|
+
if (applyRule(api, state)) onClose();
|
|
1737
|
+
};
|
|
1738
|
+
const clearRules = () => {
|
|
1739
|
+
const sheet = activeSheet(api);
|
|
1740
|
+
sheet?.clearConditionalFormatRules?.();
|
|
1741
|
+
onClose();
|
|
1742
|
+
};
|
|
1743
|
+
const showOperator = state.ruleType === "cellValue";
|
|
1744
|
+
const showSecondOperand = showOperator && isRangeOperator2(state.operator);
|
|
1745
|
+
const isRank = state.ruleType === "topN" || state.ruleType === "bottomN";
|
|
1746
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1747
|
+
Dialog,
|
|
1748
|
+
{
|
|
1749
|
+
title: "Conditional formatting",
|
|
1750
|
+
onClose,
|
|
1751
|
+
width: 440,
|
|
1752
|
+
"data-testid": "cs-conditional-formatting-dialog",
|
|
1753
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1754
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1755
|
+
"button",
|
|
1756
|
+
{
|
|
1757
|
+
type: "button",
|
|
1758
|
+
style: DIALOG_BTN_SECONDARY_STYLE,
|
|
1759
|
+
"data-testid": "cs-conditional-formatting-clear",
|
|
1760
|
+
onClick: clearRules,
|
|
1761
|
+
children: "Clear rules"
|
|
1762
|
+
}
|
|
1763
|
+
),
|
|
1764
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { flex: 1 } }),
|
|
1765
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
1766
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1767
|
+
"button",
|
|
1768
|
+
{
|
|
1769
|
+
type: "button",
|
|
1770
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
1771
|
+
"data-testid": "cs-conditional-formatting-apply",
|
|
1772
|
+
disabled: !hasSelection,
|
|
1773
|
+
onClick: apply,
|
|
1774
|
+
children: "Apply"
|
|
1775
|
+
}
|
|
1776
|
+
)
|
|
1777
|
+
] }),
|
|
1778
|
+
children: [
|
|
1779
|
+
hasSelection ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: RANGE_NOTE_STYLE2, "data-testid": "cs-conditional-formatting-range", children: [
|
|
1780
|
+
"Applies to ",
|
|
1781
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: rangeLabel ?? "the current selection" })
|
|
1782
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: RANGE_NOTE_STYLE2, "data-testid": "cs-conditional-formatting-no-selection", children: "Select one or more cells first, then reopen this dialog." }),
|
|
1783
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1784
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Condition type" }),
|
|
1785
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1786
|
+
"select",
|
|
1787
|
+
{
|
|
1788
|
+
style: DIALOG_INPUT_STYLE,
|
|
1789
|
+
"data-testid": "cs-conditional-formatting-type",
|
|
1790
|
+
value: state.ruleType,
|
|
1791
|
+
onChange: (e) => update("ruleType", e.target.value),
|
|
1792
|
+
children: RULE_TYPE_OPTIONS2.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
|
|
1793
|
+
}
|
|
1794
|
+
)
|
|
1795
|
+
] }),
|
|
1796
|
+
showOperator && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1797
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1798
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Condition" }),
|
|
1799
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1800
|
+
"select",
|
|
1801
|
+
{
|
|
1802
|
+
style: DIALOG_INPUT_STYLE,
|
|
1803
|
+
"data-testid": "cs-conditional-formatting-operator",
|
|
1804
|
+
value: state.operator,
|
|
1805
|
+
onChange: (e) => update("operator", e.target.value),
|
|
1806
|
+
children: OPERATOR_OPTIONS2.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
|
|
1807
|
+
}
|
|
1808
|
+
)
|
|
1809
|
+
] }),
|
|
1810
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: showSecondOperand ? TWO_COL_STYLE2 : void 0, children: [
|
|
1811
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1812
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: DIALOG_LABEL_STYLE, children: showSecondOperand ? "Minimum" : "Value" }),
|
|
1813
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1814
|
+
"input",
|
|
1815
|
+
{
|
|
1816
|
+
style: DIALOG_INPUT_STYLE,
|
|
1817
|
+
"data-testid": "cs-conditional-formatting-operand1",
|
|
1818
|
+
type: "number",
|
|
1819
|
+
value: state.operand1,
|
|
1820
|
+
onChange: (e) => update("operand1", e.target.value)
|
|
1821
|
+
}
|
|
1822
|
+
)
|
|
1823
|
+
] }),
|
|
1824
|
+
showSecondOperand && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1825
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Maximum" }),
|
|
1826
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1827
|
+
"input",
|
|
1828
|
+
{
|
|
1829
|
+
style: DIALOG_INPUT_STYLE,
|
|
1830
|
+
"data-testid": "cs-conditional-formatting-operand2",
|
|
1831
|
+
type: "number",
|
|
1832
|
+
value: state.operand2,
|
|
1833
|
+
onChange: (e) => update("operand2", e.target.value)
|
|
1834
|
+
}
|
|
1835
|
+
)
|
|
1836
|
+
] })
|
|
1837
|
+
] })
|
|
1838
|
+
] }),
|
|
1839
|
+
state.ruleType === "textContains" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1840
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Text contains" }),
|
|
1841
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1842
|
+
"input",
|
|
1843
|
+
{
|
|
1844
|
+
style: DIALOG_INPUT_STYLE,
|
|
1845
|
+
"data-testid": "cs-conditional-formatting-text",
|
|
1846
|
+
value: state.text,
|
|
1847
|
+
placeholder: "e.g. urgent",
|
|
1848
|
+
onChange: (e) => update("text", e.target.value)
|
|
1849
|
+
}
|
|
1850
|
+
)
|
|
1851
|
+
] }),
|
|
1852
|
+
isRank && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1853
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1854
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { style: DIALOG_LABEL_STYLE, children: [
|
|
1855
|
+
state.ruleType === "topN" ? "Top" : "Bottom",
|
|
1856
|
+
" ",
|
|
1857
|
+
state.rankPercent ? "percent" : "count"
|
|
1858
|
+
] }),
|
|
1859
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1860
|
+
"input",
|
|
1861
|
+
{
|
|
1862
|
+
style: DIALOG_INPUT_STYLE,
|
|
1863
|
+
"data-testid": "cs-conditional-formatting-rank-n",
|
|
1864
|
+
type: "number",
|
|
1865
|
+
min: 1,
|
|
1866
|
+
value: state.rankN,
|
|
1867
|
+
onChange: (e) => update("rankN", e.target.value)
|
|
1868
|
+
}
|
|
1869
|
+
)
|
|
1870
|
+
] }),
|
|
1871
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: CHECK_STYLE3, children: [
|
|
1872
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1873
|
+
"input",
|
|
1874
|
+
{
|
|
1875
|
+
type: "checkbox",
|
|
1876
|
+
"data-testid": "cs-conditional-formatting-rank-percent",
|
|
1877
|
+
checked: state.rankPercent,
|
|
1878
|
+
onChange: (e) => update("rankPercent", e.target.checked)
|
|
1879
|
+
}
|
|
1880
|
+
),
|
|
1881
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Interpret as percent" })
|
|
1882
|
+
] })
|
|
1883
|
+
] }),
|
|
1884
|
+
state.ruleType === "colorScale" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: TWO_COL_STYLE2, children: [
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1886
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Min color" }),
|
|
1887
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1888
|
+
"input",
|
|
1889
|
+
{
|
|
1890
|
+
style: COLOR_INPUT_STYLE2,
|
|
1891
|
+
"data-testid": "cs-conditional-formatting-scale-min",
|
|
1892
|
+
type: "color",
|
|
1893
|
+
value: state.scaleMinColor,
|
|
1894
|
+
onChange: (e) => update("scaleMinColor", e.target.value)
|
|
1895
|
+
}
|
|
1896
|
+
)
|
|
1897
|
+
] }),
|
|
1898
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1899
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Max color" }),
|
|
1900
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1901
|
+
"input",
|
|
1902
|
+
{
|
|
1903
|
+
style: COLOR_INPUT_STYLE2,
|
|
1904
|
+
"data-testid": "cs-conditional-formatting-scale-max",
|
|
1905
|
+
type: "color",
|
|
1906
|
+
value: state.scaleMaxColor,
|
|
1907
|
+
onChange: (e) => update("scaleMaxColor", e.target.value)
|
|
1908
|
+
}
|
|
1909
|
+
)
|
|
1910
|
+
] })
|
|
1911
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: TWO_COL_STYLE2, children: [
|
|
1912
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1913
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Fill color" }),
|
|
1914
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1915
|
+
"input",
|
|
1916
|
+
{
|
|
1917
|
+
style: COLOR_INPUT_STYLE2,
|
|
1918
|
+
"data-testid": "cs-conditional-formatting-fill-color",
|
|
1919
|
+
type: "color",
|
|
1920
|
+
value: state.fillColor,
|
|
1921
|
+
onChange: (e) => update("fillColor", e.target.value)
|
|
1922
|
+
}
|
|
1923
|
+
)
|
|
1924
|
+
] }),
|
|
1925
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
1926
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Text color" }),
|
|
1927
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1928
|
+
"input",
|
|
1929
|
+
{
|
|
1930
|
+
style: COLOR_INPUT_STYLE2,
|
|
1931
|
+
"data-testid": "cs-conditional-formatting-text-color",
|
|
1932
|
+
type: "color",
|
|
1933
|
+
value: state.textColor,
|
|
1934
|
+
onChange: (e) => update("textColor", e.target.value)
|
|
1935
|
+
}
|
|
1936
|
+
)
|
|
1937
|
+
] })
|
|
1938
|
+
] })
|
|
1939
|
+
]
|
|
1940
|
+
}
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
// src/chrome/CustomSortDialog.tsx
|
|
1945
|
+
var import_react8 = require("react");
|
|
1946
|
+
var import_facade3 = require("@univerjs/sheets-sort/facade");
|
|
1947
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1948
|
+
function activeRange4(api) {
|
|
1949
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
1950
|
+
}
|
|
1951
|
+
function columnLetter(index) {
|
|
1952
|
+
let n = index;
|
|
1953
|
+
let label = "";
|
|
1954
|
+
do {
|
|
1955
|
+
label = String.fromCharCode(65 + n % 26) + label;
|
|
1956
|
+
n = Math.floor(n / 26) - 1;
|
|
1957
|
+
} while (n >= 0);
|
|
1958
|
+
return label;
|
|
1959
|
+
}
|
|
1960
|
+
function readRangeInfo(api) {
|
|
1961
|
+
const range = activeRange4(api);
|
|
1962
|
+
if (!range) return null;
|
|
1963
|
+
const values = range.getValues?.();
|
|
1964
|
+
return {
|
|
1965
|
+
startRow: range.getRow(),
|
|
1966
|
+
startColumn: range.getColumn(),
|
|
1967
|
+
width: range.getWidth(),
|
|
1968
|
+
height: range.getHeight(),
|
|
1969
|
+
a1: range.getA1Notation?.() ?? null,
|
|
1970
|
+
firstRow: values && values.length > 0 ? values[0] : null
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
function applySort(api, info, levels, hasHeader) {
|
|
1974
|
+
const worksheet = api.univer.getActiveWorkbook()?.getActiveSheet();
|
|
1975
|
+
if (!worksheet) return false;
|
|
1976
|
+
const bandStartRow = hasHeader ? info.startRow + 1 : info.startRow;
|
|
1977
|
+
const bandHeight = hasHeader ? info.height - 1 : info.height;
|
|
1978
|
+
if (bandHeight <= 0) return false;
|
|
1979
|
+
const band = worksheet.getRange(bandStartRow, info.startColumn, bandHeight, info.width);
|
|
1980
|
+
const specs = levels.filter((l) => l.column >= 0 && l.column < info.width).map((l) => ({ column: l.column, ascending: l.ascending }));
|
|
1981
|
+
if (specs.length === 0) return false;
|
|
1982
|
+
band.sort(specs);
|
|
1983
|
+
return true;
|
|
1984
|
+
}
|
|
1985
|
+
var RANGE_NOTE_STYLE3 = {
|
|
1986
|
+
fontSize: 12,
|
|
1987
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
1988
|
+
marginBottom: 12
|
|
1989
|
+
};
|
|
1990
|
+
var CHECK_STYLE4 = {
|
|
1991
|
+
display: "flex",
|
|
1992
|
+
alignItems: "center",
|
|
1993
|
+
gap: 6,
|
|
1994
|
+
marginBottom: 12,
|
|
1995
|
+
cursor: "pointer"
|
|
1996
|
+
};
|
|
1997
|
+
var LEVEL_ROW_STYLE = {
|
|
1998
|
+
display: "grid",
|
|
1999
|
+
gridTemplateColumns: "auto 1fr 130px 28px",
|
|
2000
|
+
alignItems: "center",
|
|
2001
|
+
gap: 8,
|
|
2002
|
+
marginBottom: 8
|
|
2003
|
+
};
|
|
2004
|
+
var LEVEL_PREFIX_STYLE = {
|
|
2005
|
+
fontSize: 12,
|
|
2006
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
2007
|
+
whiteSpace: "nowrap"
|
|
2008
|
+
};
|
|
2009
|
+
var REMOVE_BTN_STYLE = {
|
|
2010
|
+
width: 28,
|
|
2011
|
+
height: 30,
|
|
2012
|
+
display: "inline-flex",
|
|
2013
|
+
alignItems: "center",
|
|
2014
|
+
justifyContent: "center",
|
|
2015
|
+
border: "1px solid var(--cs-chrome-border, #cdd3db)",
|
|
2016
|
+
borderRadius: 6,
|
|
2017
|
+
background: "var(--cs-chrome-input-bg, #fff)",
|
|
2018
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
2019
|
+
cursor: "pointer",
|
|
2020
|
+
padding: 0,
|
|
2021
|
+
fontSize: 16,
|
|
2022
|
+
lineHeight: 1
|
|
2023
|
+
};
|
|
2024
|
+
var ADD_BTN_STYLE = {
|
|
2025
|
+
...DIALOG_BTN_SECONDARY_STYLE,
|
|
2026
|
+
marginTop: 4
|
|
2027
|
+
};
|
|
2028
|
+
function CustomSortDialog({ api, onClose }) {
|
|
2029
|
+
const info = (0, import_react8.useMemo)(() => readRangeInfo(api), [api]);
|
|
2030
|
+
const hasSelection = info !== null;
|
|
2031
|
+
const width = info?.width ?? 1;
|
|
2032
|
+
const [hasHeader, setHasHeader] = (0, import_react8.useState)(false);
|
|
2033
|
+
const [levels, setLevels] = (0, import_react8.useState)([{ column: 0, ascending: true }]);
|
|
2034
|
+
const columnOptions = (0, import_react8.useMemo)(() => {
|
|
2035
|
+
const startCol = info?.startColumn ?? 0;
|
|
2036
|
+
return Array.from({ length: width }, (_, offset) => {
|
|
2037
|
+
const headerCell = hasHeader ? info?.firstRow?.[offset] : void 0;
|
|
2038
|
+
const headerText = headerCell !== void 0 && headerCell !== null && String(headerCell).trim() !== "" ? String(headerCell) : null;
|
|
2039
|
+
const letter = columnLetter(startCol + offset);
|
|
2040
|
+
return {
|
|
2041
|
+
value: offset,
|
|
2042
|
+
label: headerText ? `${headerText} (${letter})` : `Column ${letter}`
|
|
2043
|
+
};
|
|
2044
|
+
});
|
|
2045
|
+
}, [width, hasHeader, info]);
|
|
2046
|
+
const updateLevel = (index, patch) => setLevels((prev) => prev.map((l, i) => i === index ? { ...l, ...patch } : l));
|
|
2047
|
+
const addLevel = () => {
|
|
2048
|
+
const used = new Set(levels.map((l) => l.column));
|
|
2049
|
+
let next = 0;
|
|
2050
|
+
for (let c = 0; c < width; c += 1) {
|
|
2051
|
+
if (!used.has(c)) {
|
|
2052
|
+
next = c;
|
|
2053
|
+
break;
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
setLevels((prev) => [...prev, { column: next, ascending: true }]);
|
|
2057
|
+
};
|
|
2058
|
+
const removeLevel = (index) => setLevels((prev) => prev.length <= 1 ? prev : prev.filter((_, i) => i !== index));
|
|
2059
|
+
const apply = () => {
|
|
2060
|
+
if (info && applySort(api, info, levels, hasHeader)) onClose();
|
|
2061
|
+
};
|
|
2062
|
+
const canApply = hasSelection && levels.length > 0;
|
|
2063
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2064
|
+
Dialog,
|
|
2065
|
+
{
|
|
2066
|
+
title: "Sort range",
|
|
2067
|
+
onClose,
|
|
2068
|
+
width: 480,
|
|
2069
|
+
"data-testid": "cs-custom-sort-dialog",
|
|
2070
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
2071
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
2072
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2073
|
+
"button",
|
|
2074
|
+
{
|
|
2075
|
+
type: "button",
|
|
2076
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
2077
|
+
"data-testid": "cs-custom-sort-apply",
|
|
2078
|
+
disabled: !canApply,
|
|
2079
|
+
onClick: apply,
|
|
2080
|
+
children: "Sort"
|
|
2081
|
+
}
|
|
2082
|
+
)
|
|
2083
|
+
] }),
|
|
2084
|
+
children: [
|
|
2085
|
+
hasSelection ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: RANGE_NOTE_STYLE3, "data-testid": "cs-custom-sort-range", children: [
|
|
2086
|
+
"Sort ",
|
|
2087
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: info?.a1 ?? "the current selection" })
|
|
2088
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: RANGE_NOTE_STYLE3, "data-testid": "cs-custom-sort-no-selection", children: "Select the range you want to sort first, then reopen this dialog." }),
|
|
2089
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { style: CHECK_STYLE4, "data-testid": "cs-custom-sort-has-header-label", children: [
|
|
2090
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2091
|
+
"input",
|
|
2092
|
+
{
|
|
2093
|
+
type: "checkbox",
|
|
2094
|
+
"data-testid": "cs-custom-sort-has-header",
|
|
2095
|
+
checked: hasHeader,
|
|
2096
|
+
onChange: (e) => setHasHeader(e.target.checked)
|
|
2097
|
+
}
|
|
2098
|
+
),
|
|
2099
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Data has header row" })
|
|
2100
|
+
] }),
|
|
2101
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: DIALOG_FIELD_STYLE, children: [
|
|
2102
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Sort by" }),
|
|
2103
|
+
levels.map((level, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: LEVEL_ROW_STYLE, "data-testid": `cs-custom-sort-level-${index}`, children: [
|
|
2104
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: LEVEL_PREFIX_STYLE, children: index === 0 ? "Sort by" : "then by" }),
|
|
2105
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2106
|
+
"select",
|
|
2107
|
+
{
|
|
2108
|
+
style: DIALOG_INPUT_STYLE,
|
|
2109
|
+
"data-testid": `cs-custom-sort-column-${index}`,
|
|
2110
|
+
value: level.column,
|
|
2111
|
+
onChange: (e) => updateLevel(index, { column: Number(e.target.value) }),
|
|
2112
|
+
children: columnOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
|
|
2113
|
+
}
|
|
2114
|
+
),
|
|
2115
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2116
|
+
"select",
|
|
2117
|
+
{
|
|
2118
|
+
style: DIALOG_INPUT_STYLE,
|
|
2119
|
+
"data-testid": `cs-custom-sort-order-${index}`,
|
|
2120
|
+
value: level.ascending ? "asc" : "desc",
|
|
2121
|
+
onChange: (e) => updateLevel(index, { ascending: e.target.value === "asc" }),
|
|
2122
|
+
children: [
|
|
2123
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "asc", children: "A \u2192 Z (ascending)" }),
|
|
2124
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "desc", children: "Z \u2192 A (descending)" })
|
|
2125
|
+
]
|
|
2126
|
+
}
|
|
2127
|
+
),
|
|
2128
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2129
|
+
"button",
|
|
2130
|
+
{
|
|
2131
|
+
type: "button",
|
|
2132
|
+
style: REMOVE_BTN_STYLE,
|
|
2133
|
+
"data-testid": `cs-custom-sort-remove-${index}`,
|
|
2134
|
+
"aria-label": "Remove sort level",
|
|
2135
|
+
disabled: levels.length <= 1,
|
|
2136
|
+
onClick: () => removeLevel(index),
|
|
2137
|
+
children: "\u2212"
|
|
2138
|
+
}
|
|
2139
|
+
)
|
|
2140
|
+
] }, index)),
|
|
2141
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2142
|
+
"button",
|
|
2143
|
+
{
|
|
2144
|
+
type: "button",
|
|
2145
|
+
style: ADD_BTN_STYLE,
|
|
2146
|
+
"data-testid": "cs-custom-sort-add-level",
|
|
2147
|
+
disabled: levels.length >= width,
|
|
2148
|
+
onClick: addLevel,
|
|
2149
|
+
children: "Add another sort level"
|
|
2150
|
+
}
|
|
2151
|
+
)
|
|
2152
|
+
] })
|
|
2153
|
+
]
|
|
2154
|
+
}
|
|
2155
|
+
);
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
// src/chrome/PasteSpecialDialog.tsx
|
|
2159
|
+
var import_react9 = require("react");
|
|
2160
|
+
var import_facade4 = require("@univerjs/sheets-ui/facade");
|
|
2161
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2162
|
+
var MODE_OPTIONS = [
|
|
2163
|
+
{
|
|
2164
|
+
value: "values",
|
|
2165
|
+
label: "Values only",
|
|
2166
|
+
hint: "Paste cell values, dropping formatting and formulas."
|
|
2167
|
+
},
|
|
2168
|
+
{
|
|
2169
|
+
value: "formats",
|
|
2170
|
+
label: "Formats only",
|
|
2171
|
+
hint: "Paste number formats, fonts, borders and fills \u2014 no values."
|
|
2172
|
+
},
|
|
2173
|
+
{
|
|
2174
|
+
value: "formulas",
|
|
2175
|
+
label: "Formulas only",
|
|
2176
|
+
hint: "Paste formulas, adjusting relative references."
|
|
2177
|
+
},
|
|
2178
|
+
{
|
|
2179
|
+
value: "transpose",
|
|
2180
|
+
label: "Transpose",
|
|
2181
|
+
hint: "Flip the current selection \u2014 rows become columns and columns become rows, in place."
|
|
2182
|
+
}
|
|
2183
|
+
];
|
|
2184
|
+
var PASTE_HOOK = {
|
|
2185
|
+
values: "special-paste-value",
|
|
2186
|
+
formats: "special-paste-format",
|
|
2187
|
+
formulas: "special-paste-formula"
|
|
2188
|
+
};
|
|
2189
|
+
var SHEET_PASTE_COMMAND = "sheet.command.paste";
|
|
2190
|
+
function activeRange5(api) {
|
|
2191
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
2192
|
+
}
|
|
2193
|
+
function transposeSelection(api) {
|
|
2194
|
+
const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
|
|
2195
|
+
const range = sheet?.getActiveRange();
|
|
2196
|
+
if (!sheet || !range) return false;
|
|
2197
|
+
const rows = range.getHeight();
|
|
2198
|
+
const cols = range.getWidth();
|
|
2199
|
+
if (rows <= 0 || cols <= 0) return false;
|
|
2200
|
+
const values = range.getValues();
|
|
2201
|
+
const transposed = [];
|
|
2202
|
+
for (let c = 0; c < cols; c++) {
|
|
2203
|
+
const newRow = [];
|
|
2204
|
+
for (let r = 0; r < rows; r++) {
|
|
2205
|
+
newRow.push(values[r]?.[c] ?? null);
|
|
2206
|
+
}
|
|
2207
|
+
transposed.push(newRow);
|
|
2208
|
+
}
|
|
2209
|
+
const target = sheet.getRange(range.getRow(), range.getColumn(), cols, rows);
|
|
2210
|
+
target.setValues(transposed);
|
|
2211
|
+
return true;
|
|
2212
|
+
}
|
|
2213
|
+
async function applyPasteSpecial(api, mode) {
|
|
2214
|
+
if (activeRange5(api) === null) return false;
|
|
2215
|
+
if (mode === "transpose") {
|
|
2216
|
+
return transposeSelection(api);
|
|
2217
|
+
}
|
|
2218
|
+
return api.executeCommand(SHEET_PASTE_COMMAND, { value: PASTE_HOOK[mode] });
|
|
2219
|
+
}
|
|
2220
|
+
var MODE_RADIO_ROW_STYLE = {
|
|
2221
|
+
display: "flex",
|
|
2222
|
+
alignItems: "flex-start",
|
|
2223
|
+
gap: 8,
|
|
2224
|
+
padding: "8px 10px",
|
|
2225
|
+
border: "1px solid var(--cs-chrome-border, #cdd3db)",
|
|
2226
|
+
borderRadius: 6,
|
|
2227
|
+
marginBottom: 8,
|
|
2228
|
+
cursor: "pointer"
|
|
2229
|
+
};
|
|
2230
|
+
var MODE_RADIO_ROW_ACTIVE_STYLE = {
|
|
2231
|
+
...MODE_RADIO_ROW_STYLE,
|
|
2232
|
+
borderColor: "var(--cs-chrome-active-fg, #0e7490)",
|
|
2233
|
+
background: "var(--cs-chrome-active-bg, rgba(14, 116, 144, 0.06))"
|
|
2234
|
+
};
|
|
2235
|
+
var MODE_LABEL_STYLE = {
|
|
2236
|
+
fontSize: 13,
|
|
2237
|
+
fontWeight: 500,
|
|
2238
|
+
color: "var(--cs-chrome-fg, #201f1e)"
|
|
2239
|
+
};
|
|
2240
|
+
var MODE_HINT_STYLE = {
|
|
2241
|
+
fontSize: 12,
|
|
2242
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
2243
|
+
marginTop: 2,
|
|
2244
|
+
lineHeight: 1.35
|
|
2245
|
+
};
|
|
2246
|
+
var RANGE_NOTE_STYLE4 = {
|
|
2247
|
+
fontSize: 12,
|
|
2248
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
2249
|
+
marginBottom: 12
|
|
2250
|
+
};
|
|
2251
|
+
function PasteSpecialDialog({ api, onClose }) {
|
|
2252
|
+
const [mode, setMode] = (0, import_react9.useState)("values");
|
|
2253
|
+
const rangeLabel = (0, import_react9.useMemo)(() => {
|
|
2254
|
+
const fRange = activeRange5(api);
|
|
2255
|
+
return fRange?.getA1Notation?.() ?? null;
|
|
2256
|
+
}, [api]);
|
|
2257
|
+
const hasSelection = activeRange5(api) !== null;
|
|
2258
|
+
const apply = () => {
|
|
2259
|
+
void applyPasteSpecial(api, mode).then((ok) => {
|
|
2260
|
+
if (ok) onClose();
|
|
2261
|
+
});
|
|
2262
|
+
};
|
|
2263
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2264
|
+
Dialog,
|
|
2265
|
+
{
|
|
2266
|
+
title: "Paste special",
|
|
2267
|
+
onClose,
|
|
2268
|
+
width: 440,
|
|
2269
|
+
"data-testid": "cs-paste-special-dialog",
|
|
2270
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
2271
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
2272
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2273
|
+
"button",
|
|
2274
|
+
{
|
|
2275
|
+
type: "button",
|
|
2276
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
2277
|
+
"data-testid": "cs-paste-special-apply",
|
|
2278
|
+
disabled: !hasSelection,
|
|
2279
|
+
onClick: apply,
|
|
2280
|
+
children: "Paste"
|
|
2281
|
+
}
|
|
2282
|
+
)
|
|
2283
|
+
] }),
|
|
2284
|
+
children: [
|
|
2285
|
+
hasSelection ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: RANGE_NOTE_STYLE4, "data-testid": "cs-paste-special-range", children: [
|
|
2286
|
+
mode === "transpose" ? "Transposes" : "Pastes into",
|
|
2287
|
+
" ",
|
|
2288
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: rangeLabel ?? "the current selection" })
|
|
2289
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: RANGE_NOTE_STYLE4, "data-testid": "cs-paste-special-no-selection", children: "Select the destination cell(s) first, then reopen this dialog." }),
|
|
2290
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: DIALOG_FIELD_STYLE, children: [
|
|
2291
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Paste" }),
|
|
2292
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "radiogroup", "aria-label": "Paste special mode", children: MODE_OPTIONS.map((opt) => {
|
|
2293
|
+
const active = mode === opt.value;
|
|
2294
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2295
|
+
"label",
|
|
2296
|
+
{
|
|
2297
|
+
style: active ? MODE_RADIO_ROW_ACTIVE_STYLE : MODE_RADIO_ROW_STYLE,
|
|
2298
|
+
"data-testid": `cs-paste-special-mode-${opt.value}`,
|
|
2299
|
+
children: [
|
|
2300
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2301
|
+
"input",
|
|
2302
|
+
{
|
|
2303
|
+
type: "radio",
|
|
2304
|
+
name: "cs-paste-special-mode",
|
|
2305
|
+
value: opt.value,
|
|
2306
|
+
checked: active,
|
|
2307
|
+
onChange: () => setMode(opt.value),
|
|
2308
|
+
style: { marginTop: 2 }
|
|
2309
|
+
}
|
|
2310
|
+
),
|
|
2311
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
2312
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: MODE_LABEL_STYLE, children: opt.label }),
|
|
2313
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: MODE_HINT_STYLE, children: opt.hint })
|
|
2314
|
+
] })
|
|
2315
|
+
]
|
|
2316
|
+
},
|
|
2317
|
+
opt.value
|
|
2318
|
+
);
|
|
2319
|
+
}) })
|
|
2320
|
+
] })
|
|
2321
|
+
]
|
|
2322
|
+
}
|
|
2323
|
+
);
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
// src/chrome/InsertFunctionDialog.tsx
|
|
2327
|
+
var import_react10 = require("react");
|
|
2328
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2329
|
+
var FUNCTIONS = [
|
|
2330
|
+
// Math
|
|
2331
|
+
{
|
|
2332
|
+
name: "SUM",
|
|
2333
|
+
category: "Math",
|
|
2334
|
+
description: "Sum of a set of numbers.",
|
|
2335
|
+
syntax: "SUM(value1, [value2, \u2026])"
|
|
2336
|
+
},
|
|
2337
|
+
{
|
|
2338
|
+
name: "PRODUCT",
|
|
2339
|
+
category: "Math",
|
|
2340
|
+
description: "Product of a set of numbers.",
|
|
2341
|
+
syntax: "PRODUCT(factor1, [factor2, \u2026])"
|
|
2342
|
+
},
|
|
2343
|
+
{
|
|
2344
|
+
name: "ROUND",
|
|
2345
|
+
category: "Math",
|
|
2346
|
+
description: "Round a number to a given number of places.",
|
|
2347
|
+
syntax: "ROUND(value, [places])"
|
|
2348
|
+
},
|
|
2349
|
+
{
|
|
2350
|
+
name: "ABS",
|
|
2351
|
+
category: "Math",
|
|
2352
|
+
description: "Absolute value of a number.",
|
|
2353
|
+
syntax: "ABS(value)"
|
|
2354
|
+
},
|
|
2355
|
+
{
|
|
2356
|
+
name: "MOD",
|
|
2357
|
+
category: "Math",
|
|
2358
|
+
description: "Remainder after division.",
|
|
2359
|
+
syntax: "MOD(dividend, divisor)"
|
|
2360
|
+
},
|
|
2361
|
+
{
|
|
2362
|
+
name: "POWER",
|
|
2363
|
+
category: "Math",
|
|
2364
|
+
description: "A number raised to a power.",
|
|
2365
|
+
syntax: "POWER(base, exponent)"
|
|
2366
|
+
},
|
|
2367
|
+
// Statistical
|
|
2368
|
+
{
|
|
2369
|
+
name: "AVERAGE",
|
|
2370
|
+
category: "Statistical",
|
|
2371
|
+
description: "Arithmetic mean of a set of numbers.",
|
|
2372
|
+
syntax: "AVERAGE(value1, [value2, \u2026])"
|
|
2373
|
+
},
|
|
2374
|
+
{
|
|
2375
|
+
name: "COUNT",
|
|
2376
|
+
category: "Statistical",
|
|
2377
|
+
description: "Count of numeric values in a range.",
|
|
2378
|
+
syntax: "COUNT(value1, [value2, \u2026])"
|
|
2379
|
+
},
|
|
2380
|
+
{
|
|
2381
|
+
name: "COUNTA",
|
|
2382
|
+
category: "Statistical",
|
|
2383
|
+
description: "Count of non-empty values in a range.",
|
|
2384
|
+
syntax: "COUNTA(value1, [value2, \u2026])"
|
|
2385
|
+
},
|
|
2386
|
+
{
|
|
2387
|
+
name: "MAX",
|
|
2388
|
+
category: "Statistical",
|
|
2389
|
+
description: "Largest value in a set.",
|
|
2390
|
+
syntax: "MAX(value1, [value2, \u2026])"
|
|
2391
|
+
},
|
|
2392
|
+
{
|
|
2393
|
+
name: "MIN",
|
|
2394
|
+
category: "Statistical",
|
|
2395
|
+
description: "Smallest value in a set.",
|
|
2396
|
+
syntax: "MIN(value1, [value2, \u2026])"
|
|
2397
|
+
},
|
|
2398
|
+
{
|
|
2399
|
+
name: "MEDIAN",
|
|
2400
|
+
category: "Statistical",
|
|
2401
|
+
description: "Median of a set of numbers.",
|
|
2402
|
+
syntax: "MEDIAN(value1, [value2, \u2026])"
|
|
2403
|
+
},
|
|
2404
|
+
// Logical
|
|
2405
|
+
{
|
|
2406
|
+
name: "IF",
|
|
2407
|
+
category: "Logical",
|
|
2408
|
+
description: "Return one value if a condition is true, another if false.",
|
|
2409
|
+
syntax: "IF(condition, value_if_true, value_if_false)"
|
|
2410
|
+
},
|
|
2411
|
+
{
|
|
2412
|
+
name: "IFS",
|
|
2413
|
+
category: "Logical",
|
|
2414
|
+
description: "Test multiple conditions, return the first match.",
|
|
2415
|
+
syntax: "IFS(condition1, value1, [condition2, value2, \u2026])"
|
|
2416
|
+
},
|
|
2417
|
+
{
|
|
2418
|
+
name: "AND",
|
|
2419
|
+
category: "Logical",
|
|
2420
|
+
description: "True when all arguments are true.",
|
|
2421
|
+
syntax: "AND(logical1, [logical2, \u2026])"
|
|
2422
|
+
},
|
|
2423
|
+
{
|
|
2424
|
+
name: "OR",
|
|
2425
|
+
category: "Logical",
|
|
2426
|
+
description: "True when any argument is true.",
|
|
2427
|
+
syntax: "OR(logical1, [logical2, \u2026])"
|
|
2428
|
+
},
|
|
2429
|
+
{
|
|
2430
|
+
name: "IFERROR",
|
|
2431
|
+
category: "Logical",
|
|
2432
|
+
description: "Return a fallback when a formula errors.",
|
|
2433
|
+
syntax: "IFERROR(value, value_if_error)"
|
|
2434
|
+
},
|
|
2435
|
+
// Lookup
|
|
2436
|
+
{
|
|
2437
|
+
name: "VLOOKUP",
|
|
2438
|
+
category: "Lookup",
|
|
2439
|
+
description: "Search a column for a key, return a value from the same row.",
|
|
2440
|
+
syntax: "VLOOKUP(search_key, range, index, [is_sorted])"
|
|
2441
|
+
},
|
|
2442
|
+
{
|
|
2443
|
+
name: "HLOOKUP",
|
|
2444
|
+
category: "Lookup",
|
|
2445
|
+
description: "Search a row for a key, return a value from the same column.",
|
|
2446
|
+
syntax: "HLOOKUP(search_key, range, index, [is_sorted])"
|
|
2447
|
+
},
|
|
2448
|
+
{
|
|
2449
|
+
name: "INDEX",
|
|
2450
|
+
category: "Lookup",
|
|
2451
|
+
description: "Value at a given row/column offset in a range.",
|
|
2452
|
+
syntax: "INDEX(reference, [row], [column])"
|
|
2453
|
+
},
|
|
2454
|
+
{
|
|
2455
|
+
name: "MATCH",
|
|
2456
|
+
category: "Lookup",
|
|
2457
|
+
description: "Position of a value within a range.",
|
|
2458
|
+
syntax: "MATCH(search_key, range, [search_type])"
|
|
2459
|
+
},
|
|
2460
|
+
{
|
|
2461
|
+
name: "XLOOKUP",
|
|
2462
|
+
category: "Lookup",
|
|
2463
|
+
description: "Search a range and return a corresponding value.",
|
|
2464
|
+
syntax: "XLOOKUP(search_key, lookup_range, result_range)"
|
|
2465
|
+
},
|
|
2466
|
+
// Text
|
|
2467
|
+
{
|
|
2468
|
+
name: "CONCATENATE",
|
|
2469
|
+
category: "Text",
|
|
2470
|
+
description: "Join strings end to end.",
|
|
2471
|
+
syntax: "CONCATENATE(string1, [string2, \u2026])"
|
|
2472
|
+
},
|
|
2473
|
+
{
|
|
2474
|
+
name: "LEFT",
|
|
2475
|
+
category: "Text",
|
|
2476
|
+
description: "Leftmost characters of a string.",
|
|
2477
|
+
syntax: "LEFT(string, [num_chars])"
|
|
2478
|
+
},
|
|
2479
|
+
{
|
|
2480
|
+
name: "RIGHT",
|
|
2481
|
+
category: "Text",
|
|
2482
|
+
description: "Rightmost characters of a string.",
|
|
2483
|
+
syntax: "RIGHT(string, [num_chars])"
|
|
2484
|
+
},
|
|
2485
|
+
{
|
|
2486
|
+
name: "MID",
|
|
2487
|
+
category: "Text",
|
|
2488
|
+
description: "Characters from the middle of a string.",
|
|
2489
|
+
syntax: "MID(string, start, length)"
|
|
2490
|
+
},
|
|
2491
|
+
{ name: "LEN", category: "Text", description: "Length of a string.", syntax: "LEN(string)" },
|
|
2492
|
+
{
|
|
2493
|
+
name: "TRIM",
|
|
2494
|
+
category: "Text",
|
|
2495
|
+
description: "Remove leading/trailing/duplicate spaces.",
|
|
2496
|
+
syntax: "TRIM(string)"
|
|
2497
|
+
},
|
|
2498
|
+
// Date
|
|
2499
|
+
{ name: "TODAY", category: "Date", description: "Today's date.", syntax: "TODAY()" },
|
|
2500
|
+
{ name: "NOW", category: "Date", description: "Current date and time.", syntax: "NOW()" },
|
|
2501
|
+
{
|
|
2502
|
+
name: "DATE",
|
|
2503
|
+
category: "Date",
|
|
2504
|
+
description: "Build a date from year, month, day.",
|
|
2505
|
+
syntax: "DATE(year, month, day)"
|
|
2506
|
+
},
|
|
2507
|
+
{
|
|
2508
|
+
name: "DATEDIF",
|
|
2509
|
+
category: "Date",
|
|
2510
|
+
description: "Difference between two dates in a chosen unit.",
|
|
2511
|
+
syntax: "DATEDIF(start_date, end_date, unit)"
|
|
2512
|
+
}
|
|
2513
|
+
];
|
|
2514
|
+
var CATEGORY_ORDER = ["Math", "Statistical", "Logical", "Lookup", "Text", "Date"];
|
|
2515
|
+
function activeRange6(api) {
|
|
2516
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
2517
|
+
}
|
|
2518
|
+
function insertFunction(api, fn) {
|
|
2519
|
+
const range = activeRange6(api);
|
|
2520
|
+
if (!range) return false;
|
|
2521
|
+
const zeroArg = fn.syntax.endsWith("()");
|
|
2522
|
+
const formula = zeroArg ? `=${fn.name}()` : `=${fn.name}(`;
|
|
2523
|
+
range.setValue(formula);
|
|
2524
|
+
api.focus();
|
|
2525
|
+
return true;
|
|
2526
|
+
}
|
|
2527
|
+
var SEARCH_STYLE = {
|
|
2528
|
+
...DIALOG_INPUT_STYLE,
|
|
2529
|
+
width: "100%",
|
|
2530
|
+
marginBottom: 12
|
|
2531
|
+
};
|
|
2532
|
+
var RANGE_NOTE_STYLE5 = {
|
|
2533
|
+
fontSize: 12,
|
|
2534
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
2535
|
+
marginBottom: 12
|
|
2536
|
+
};
|
|
2537
|
+
var LIST_STYLE = {
|
|
2538
|
+
maxHeight: 280,
|
|
2539
|
+
overflow: "auto",
|
|
2540
|
+
border: "1px solid var(--cs-chrome-border, #edeff3)",
|
|
2541
|
+
borderRadius: 8
|
|
2542
|
+
};
|
|
2543
|
+
var GROUP_HEADER_STYLE = {
|
|
2544
|
+
position: "sticky",
|
|
2545
|
+
top: 0,
|
|
2546
|
+
padding: "6px 12px",
|
|
2547
|
+
fontSize: 11,
|
|
2548
|
+
fontWeight: 600,
|
|
2549
|
+
letterSpacing: 0.4,
|
|
2550
|
+
textTransform: "uppercase",
|
|
2551
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
2552
|
+
background: "var(--cs-chrome-input-bg, #fff)",
|
|
2553
|
+
borderBottom: "1px solid var(--cs-chrome-border, #edeff3)"
|
|
2554
|
+
};
|
|
2555
|
+
function itemStyle(selected) {
|
|
2556
|
+
return {
|
|
2557
|
+
display: "block",
|
|
2558
|
+
width: "100%",
|
|
2559
|
+
textAlign: "left",
|
|
2560
|
+
padding: "8px 12px",
|
|
2561
|
+
border: "none",
|
|
2562
|
+
borderBottom: "1px solid var(--cs-chrome-border, #f3f4f6)",
|
|
2563
|
+
background: selected ? "var(--cs-chrome-hover-bg, #eef6f8)" : "transparent",
|
|
2564
|
+
color: "var(--cs-chrome-fg, #201f1e)",
|
|
2565
|
+
font: "inherit",
|
|
2566
|
+
fontSize: 13,
|
|
2567
|
+
cursor: "pointer"
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
var ITEM_NAME_STYLE = {
|
|
2571
|
+
fontWeight: 600,
|
|
2572
|
+
fontFamily: "var(--cs-chrome-mono, ui-monospace, SFMono-Regular, Menlo, monospace)"
|
|
2573
|
+
};
|
|
2574
|
+
var ITEM_DESC_STYLE = {
|
|
2575
|
+
fontSize: 12,
|
|
2576
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
2577
|
+
marginTop: 2
|
|
2578
|
+
};
|
|
2579
|
+
var PREVIEW_STYLE = {
|
|
2580
|
+
marginTop: 12,
|
|
2581
|
+
padding: "10px 12px",
|
|
2582
|
+
borderRadius: 8,
|
|
2583
|
+
background: "var(--cs-chrome-subtle-bg, #f6f8fa)",
|
|
2584
|
+
fontSize: 12,
|
|
2585
|
+
color: "var(--cs-chrome-fg, #201f1e)"
|
|
2586
|
+
};
|
|
2587
|
+
var PREVIEW_SYNTAX_STYLE = {
|
|
2588
|
+
fontFamily: "var(--cs-chrome-mono, ui-monospace, SFMono-Regular, Menlo, monospace)",
|
|
2589
|
+
fontWeight: 600,
|
|
2590
|
+
marginBottom: 4
|
|
2591
|
+
};
|
|
2592
|
+
function InsertFunctionDialog({ api, onClose }) {
|
|
2593
|
+
const [query, setQuery] = (0, import_react10.useState)("");
|
|
2594
|
+
const [selectedName, setSelectedName] = (0, import_react10.useState)(null);
|
|
2595
|
+
const rangeLabel = (0, import_react10.useMemo)(() => {
|
|
2596
|
+
const fRange = activeRange6(api);
|
|
2597
|
+
return fRange?.getA1Notation?.() ?? null;
|
|
2598
|
+
}, [api]);
|
|
2599
|
+
const hasSelection = activeRange6(api) !== null;
|
|
2600
|
+
const filtered = (0, import_react10.useMemo)(() => {
|
|
2601
|
+
const q = query.trim().toLowerCase();
|
|
2602
|
+
if (!q) return FUNCTIONS;
|
|
2603
|
+
return FUNCTIONS.filter(
|
|
2604
|
+
(fn) => fn.name.toLowerCase().includes(q) || fn.description.toLowerCase().includes(q) || fn.category.toLowerCase().includes(q)
|
|
2605
|
+
);
|
|
2606
|
+
}, [query]);
|
|
2607
|
+
const grouped = (0, import_react10.useMemo)(() => {
|
|
2608
|
+
const byCat = /* @__PURE__ */ new Map();
|
|
2609
|
+
for (const fn of filtered) {
|
|
2610
|
+
const list = byCat.get(fn.category);
|
|
2611
|
+
if (list) list.push(fn);
|
|
2612
|
+
else byCat.set(fn.category, [fn]);
|
|
2613
|
+
}
|
|
2614
|
+
return CATEGORY_ORDER.filter((c) => byCat.has(c)).map((c) => ({
|
|
2615
|
+
category: c,
|
|
2616
|
+
items: byCat.get(c)
|
|
2617
|
+
}));
|
|
2618
|
+
}, [filtered]);
|
|
2619
|
+
const selected = (0, import_react10.useMemo)(
|
|
2620
|
+
() => FUNCTIONS.find((fn) => fn.name === selectedName) ?? null,
|
|
2621
|
+
[selectedName]
|
|
2622
|
+
);
|
|
2623
|
+
const choose = (fn) => {
|
|
2624
|
+
if (insertFunction(api, fn)) onClose();
|
|
2625
|
+
};
|
|
2626
|
+
const insertSelected = () => {
|
|
2627
|
+
if (selected && insertFunction(api, selected)) onClose();
|
|
2628
|
+
};
|
|
2629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2630
|
+
Dialog,
|
|
2631
|
+
{
|
|
2632
|
+
title: "Insert function",
|
|
2633
|
+
onClose,
|
|
2634
|
+
width: 460,
|
|
2635
|
+
"data-testid": "cs-insert-function-dialog",
|
|
2636
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
2637
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
2638
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2639
|
+
"button",
|
|
2640
|
+
{
|
|
2641
|
+
type: "button",
|
|
2642
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
2643
|
+
"data-testid": "cs-insert-function-insert",
|
|
2644
|
+
disabled: !hasSelection || !selected,
|
|
2645
|
+
onClick: insertSelected,
|
|
2646
|
+
children: "Insert"
|
|
2647
|
+
}
|
|
2648
|
+
)
|
|
2649
|
+
] }),
|
|
2650
|
+
children: [
|
|
2651
|
+
hasSelection ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: RANGE_NOTE_STYLE5, "data-testid": "cs-insert-function-range", children: [
|
|
2652
|
+
"Inserts into ",
|
|
2653
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: rangeLabel ?? "the active cell" })
|
|
2654
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: RANGE_NOTE_STYLE5, "data-testid": "cs-insert-function-no-selection", children: "Select a cell first, then reopen this dialog." }),
|
|
2655
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2656
|
+
"input",
|
|
2657
|
+
{
|
|
2658
|
+
style: SEARCH_STYLE,
|
|
2659
|
+
"data-testid": "cs-insert-function-search",
|
|
2660
|
+
type: "search",
|
|
2661
|
+
placeholder: "Search functions (name, category, or description)",
|
|
2662
|
+
value: query,
|
|
2663
|
+
autoFocus: true,
|
|
2664
|
+
onChange: (e) => setQuery(e.target.value)
|
|
2665
|
+
}
|
|
2666
|
+
),
|
|
2667
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2668
|
+
"div",
|
|
2669
|
+
{
|
|
2670
|
+
style: LIST_STYLE,
|
|
2671
|
+
role: "listbox",
|
|
2672
|
+
"aria-label": "Functions",
|
|
2673
|
+
"data-testid": "cs-insert-function-list",
|
|
2674
|
+
children: [
|
|
2675
|
+
grouped.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { padding: "12px", fontSize: 13, color: "var(--cs-chrome-muted, #605e5c)" }, children: [
|
|
2676
|
+
"No functions match \u201C",
|
|
2677
|
+
query,
|
|
2678
|
+
"\u201D."
|
|
2679
|
+
] }),
|
|
2680
|
+
grouped.map((group) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
|
|
2681
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: GROUP_HEADER_STYLE, children: group.category }),
|
|
2682
|
+
group.items.map((fn) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2683
|
+
"button",
|
|
2684
|
+
{
|
|
2685
|
+
type: "button",
|
|
2686
|
+
role: "option",
|
|
2687
|
+
"aria-selected": selectedName === fn.name,
|
|
2688
|
+
"data-testid": `cs-insert-function-item-${fn.name}`,
|
|
2689
|
+
style: itemStyle(selectedName === fn.name),
|
|
2690
|
+
onClick: () => setSelectedName(fn.name),
|
|
2691
|
+
onDoubleClick: () => choose(fn),
|
|
2692
|
+
children: [
|
|
2693
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: ITEM_NAME_STYLE, children: fn.name }),
|
|
2694
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: ITEM_DESC_STYLE, children: fn.description })
|
|
2695
|
+
]
|
|
2696
|
+
},
|
|
2697
|
+
fn.name
|
|
2698
|
+
))
|
|
2699
|
+
] }, group.category))
|
|
2700
|
+
]
|
|
2701
|
+
}
|
|
2702
|
+
),
|
|
2703
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: PREVIEW_STYLE, "data-testid": "cs-insert-function-preview", children: [
|
|
2704
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: PREVIEW_SYNTAX_STYLE, children: selected.syntax }),
|
|
2705
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: selected.description })
|
|
2706
|
+
] })
|
|
2707
|
+
]
|
|
2708
|
+
}
|
|
2709
|
+
);
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
// src/chrome/NameManagerDialog.tsx
|
|
2713
|
+
var import_react11 = require("react");
|
|
2714
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2715
|
+
var NAME_RE = /^[A-Za-z_][A-Za-z0-9_.]*$/;
|
|
2716
|
+
function workbook(api) {
|
|
2717
|
+
return api.univer.getActiveWorkbook() ?? null;
|
|
2718
|
+
}
|
|
2719
|
+
function readRows(api) {
|
|
2720
|
+
const wb = workbook(api);
|
|
2721
|
+
if (!wb) return [];
|
|
2722
|
+
return wb.getDefinedNames().map((dn) => ({
|
|
2723
|
+
name: dn.getName(),
|
|
2724
|
+
refersTo: dn.getFormulaOrRefString()
|
|
2725
|
+
}));
|
|
2726
|
+
}
|
|
2727
|
+
function selectionRef(api) {
|
|
2728
|
+
const range = workbook(api)?.getActiveSheet()?.getActiveRange();
|
|
2729
|
+
return range?.getA1Notation(true) ?? "";
|
|
2730
|
+
}
|
|
2731
|
+
var ROW_STYLE4 = {
|
|
2732
|
+
display: "grid",
|
|
2733
|
+
gridTemplateColumns: "1fr 1.3fr auto",
|
|
2734
|
+
alignItems: "center",
|
|
2735
|
+
gap: 8,
|
|
2736
|
+
padding: "6px 8px",
|
|
2737
|
+
borderBottom: "1px solid var(--cs-chrome-border, #edeff3)"
|
|
2738
|
+
};
|
|
2739
|
+
var LIST_STYLE2 = {
|
|
2740
|
+
border: "1px solid var(--cs-chrome-border, #cdd3db)",
|
|
2741
|
+
borderRadius: 6,
|
|
2742
|
+
maxHeight: 200,
|
|
2743
|
+
overflow: "auto",
|
|
2744
|
+
marginBottom: 16
|
|
2745
|
+
};
|
|
2746
|
+
var EMPTY_STYLE = {
|
|
2747
|
+
padding: "16px 8px",
|
|
2748
|
+
fontSize: 13,
|
|
2749
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
2750
|
+
textAlign: "center"
|
|
2751
|
+
};
|
|
2752
|
+
var REF_CELL_STYLE = {
|
|
2753
|
+
fontSize: 12,
|
|
2754
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
2755
|
+
overflow: "hidden",
|
|
2756
|
+
textOverflow: "ellipsis",
|
|
2757
|
+
whiteSpace: "nowrap"
|
|
2758
|
+
};
|
|
2759
|
+
var ROW_ACTIONS_STYLE = {
|
|
2760
|
+
display: "flex",
|
|
2761
|
+
gap: 4
|
|
2762
|
+
};
|
|
2763
|
+
var SMALL_BTN_STYLE = {
|
|
2764
|
+
...DIALOG_BTN_SECONDARY_STYLE,
|
|
2765
|
+
height: 24,
|
|
2766
|
+
padding: "0 8px",
|
|
2767
|
+
fontSize: 12
|
|
2768
|
+
};
|
|
2769
|
+
var SECTION_TITLE_STYLE = {
|
|
2770
|
+
fontSize: 13,
|
|
2771
|
+
fontWeight: 600,
|
|
2772
|
+
color: "var(--cs-chrome-fg, #201f1e)",
|
|
2773
|
+
margin: "0 0 8px"
|
|
2774
|
+
};
|
|
2775
|
+
var ERROR_STYLE = {
|
|
2776
|
+
fontSize: 12,
|
|
2777
|
+
color: "var(--cs-chrome-danger, #b91c1c)",
|
|
2778
|
+
marginBottom: 8
|
|
2779
|
+
};
|
|
2780
|
+
var TWO_COL_STYLE3 = {
|
|
2781
|
+
display: "grid",
|
|
2782
|
+
gridTemplateColumns: "1fr 1.3fr",
|
|
2783
|
+
gap: 8
|
|
2784
|
+
};
|
|
2785
|
+
function NameManagerDialog({ api, onClose }) {
|
|
2786
|
+
const [rows, setRows] = (0, import_react11.useState)(() => readRows(api));
|
|
2787
|
+
const [editingOriginal, setEditingOriginal] = (0, import_react11.useState)(null);
|
|
2788
|
+
const [nameInput, setNameInput] = (0, import_react11.useState)("");
|
|
2789
|
+
const [refInput, setRefInput] = (0, import_react11.useState)("");
|
|
2790
|
+
const [error, setError] = (0, import_react11.useState)(null);
|
|
2791
|
+
const initialSelRef = (0, import_react11.useMemo)(() => selectionRef(api), [api]);
|
|
2792
|
+
const refresh = (0, import_react11.useCallback)(() => setRows(readRows(api)), [api]);
|
|
2793
|
+
const resetForm = (0, import_react11.useCallback)(() => {
|
|
2794
|
+
setEditingOriginal(null);
|
|
2795
|
+
setNameInput("");
|
|
2796
|
+
setRefInput("");
|
|
2797
|
+
setError(null);
|
|
2798
|
+
}, []);
|
|
2799
|
+
const startEdit = (row) => {
|
|
2800
|
+
setEditingOriginal(row.name);
|
|
2801
|
+
setNameInput(row.name);
|
|
2802
|
+
setRefInput(row.refersTo);
|
|
2803
|
+
setError(null);
|
|
2804
|
+
};
|
|
2805
|
+
const useSelection = () => {
|
|
2806
|
+
const ref = selectionRef(api);
|
|
2807
|
+
if (ref) setRefInput(ref);
|
|
2808
|
+
};
|
|
2809
|
+
const remove = (row) => {
|
|
2810
|
+
const wb = workbook(api);
|
|
2811
|
+
if (!wb) return;
|
|
2812
|
+
wb.deleteDefinedName(row.name);
|
|
2813
|
+
if (editingOriginal === row.name) resetForm();
|
|
2814
|
+
refresh();
|
|
2815
|
+
};
|
|
2816
|
+
const submit = () => {
|
|
2817
|
+
const wb = workbook(api);
|
|
2818
|
+
if (!wb) {
|
|
2819
|
+
setError("No active workbook.");
|
|
2820
|
+
return;
|
|
2821
|
+
}
|
|
2822
|
+
const name = nameInput.trim();
|
|
2823
|
+
const ref = refInput.trim();
|
|
2824
|
+
if (!name) {
|
|
2825
|
+
setError("Enter a name.");
|
|
2826
|
+
return;
|
|
2827
|
+
}
|
|
2828
|
+
if (!NAME_RE.test(name)) {
|
|
2829
|
+
setError("Names must start with a letter or underscore and contain no spaces.");
|
|
2830
|
+
return;
|
|
2831
|
+
}
|
|
2832
|
+
if (!ref) {
|
|
2833
|
+
setError("Enter a range or formula (e.g. Sheet1!A1:B2).");
|
|
2834
|
+
return;
|
|
2835
|
+
}
|
|
2836
|
+
const collides = rows.some(
|
|
2837
|
+
(r) => r.name.toLowerCase() === name.toLowerCase() && r.name !== editingOriginal
|
|
2838
|
+
);
|
|
2839
|
+
if (collides) {
|
|
2840
|
+
setError(`A defined name "${name}" already exists.`);
|
|
2841
|
+
return;
|
|
2842
|
+
}
|
|
2843
|
+
if (editingOriginal === null) {
|
|
2844
|
+
wb.insertDefinedName(name, ref);
|
|
2845
|
+
} else {
|
|
2846
|
+
const existing = wb.getDefinedName(editingOriginal);
|
|
2847
|
+
if (existing) {
|
|
2848
|
+
const param = existing.toBuilder().setName(name).setRef(ref).build();
|
|
2849
|
+
wb.updateDefinedNameBuilder(param);
|
|
2850
|
+
} else {
|
|
2851
|
+
wb.insertDefinedName(name, ref);
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
refresh();
|
|
2855
|
+
resetForm();
|
|
2856
|
+
};
|
|
2857
|
+
const isEditing = editingOriginal !== null;
|
|
2858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2859
|
+
Dialog,
|
|
2860
|
+
{
|
|
2861
|
+
title: "Name manager",
|
|
2862
|
+
onClose,
|
|
2863
|
+
width: 480,
|
|
2864
|
+
"data-testid": "cs-name-manager-dialog",
|
|
2865
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
2866
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { flex: 1 } }),
|
|
2867
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Close" })
|
|
2868
|
+
] }),
|
|
2869
|
+
children: [
|
|
2870
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { style: SECTION_TITLE_STYLE, children: "Defined names" }),
|
|
2871
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: LIST_STYLE2, "data-testid": "cs-name-manager-list", children: rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: EMPTY_STYLE, "data-testid": "cs-name-manager-empty", children: "No defined names yet. Add one below." }) : rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: ROW_STYLE4, "data-testid": "cs-name-manager-row", children: [
|
|
2872
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontWeight: 500 }, children: row.name }),
|
|
2873
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: REF_CELL_STYLE, title: row.refersTo, children: row.refersTo }),
|
|
2874
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { style: ROW_ACTIONS_STYLE, children: [
|
|
2875
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2876
|
+
"button",
|
|
2877
|
+
{
|
|
2878
|
+
type: "button",
|
|
2879
|
+
style: SMALL_BTN_STYLE,
|
|
2880
|
+
"data-testid": "cs-name-manager-edit",
|
|
2881
|
+
onClick: () => startEdit(row),
|
|
2882
|
+
children: "Edit"
|
|
2883
|
+
}
|
|
2884
|
+
),
|
|
2885
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2886
|
+
"button",
|
|
2887
|
+
{
|
|
2888
|
+
type: "button",
|
|
2889
|
+
style: SMALL_BTN_STYLE,
|
|
2890
|
+
"data-testid": "cs-name-manager-delete",
|
|
2891
|
+
onClick: () => remove(row),
|
|
2892
|
+
children: "Delete"
|
|
2893
|
+
}
|
|
2894
|
+
)
|
|
2895
|
+
] })
|
|
2896
|
+
] }, row.name)) }),
|
|
2897
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { style: SECTION_TITLE_STYLE, children: isEditing ? "Edit name" : "Add a name" }),
|
|
2898
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: ERROR_STYLE, "data-testid": "cs-name-manager-error", children: error }),
|
|
2899
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: TWO_COL_STYLE3, children: [
|
|
2900
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
2901
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Name" }),
|
|
2902
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2903
|
+
"input",
|
|
2904
|
+
{
|
|
2905
|
+
style: DIALOG_INPUT_STYLE,
|
|
2906
|
+
"data-testid": "cs-name-manager-name",
|
|
2907
|
+
value: nameInput,
|
|
2908
|
+
placeholder: "MyRange",
|
|
2909
|
+
onChange: (e) => setNameInput(e.target.value)
|
|
2910
|
+
}
|
|
2911
|
+
)
|
|
2912
|
+
] }),
|
|
2913
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
2914
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Refers to" }),
|
|
2915
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2916
|
+
"input",
|
|
2917
|
+
{
|
|
2918
|
+
style: DIALOG_INPUT_STYLE,
|
|
2919
|
+
"data-testid": "cs-name-manager-ref",
|
|
2920
|
+
value: refInput,
|
|
2921
|
+
placeholder: initialSelRef || "Sheet1!A1:B2",
|
|
2922
|
+
onChange: (e) => setRefInput(e.target.value)
|
|
2923
|
+
}
|
|
2924
|
+
)
|
|
2925
|
+
] })
|
|
2926
|
+
] }),
|
|
2927
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", gap: 8, marginTop: 4 }, children: [
|
|
2928
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2929
|
+
"button",
|
|
2930
|
+
{
|
|
2931
|
+
type: "button",
|
|
2932
|
+
style: DIALOG_BTN_SECONDARY_STYLE,
|
|
2933
|
+
"data-testid": "cs-name-manager-use-selection",
|
|
2934
|
+
onClick: useSelection,
|
|
2935
|
+
children: "Use selection"
|
|
2936
|
+
}
|
|
2937
|
+
),
|
|
2938
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { flex: 1 } }),
|
|
2939
|
+
isEditing && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2940
|
+
"button",
|
|
2941
|
+
{
|
|
2942
|
+
type: "button",
|
|
2943
|
+
style: DIALOG_BTN_SECONDARY_STYLE,
|
|
2944
|
+
"data-testid": "cs-name-manager-cancel-edit",
|
|
2945
|
+
onClick: resetForm,
|
|
2946
|
+
children: "Cancel"
|
|
2947
|
+
}
|
|
2948
|
+
),
|
|
2949
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2950
|
+
"button",
|
|
2951
|
+
{
|
|
2952
|
+
type: "button",
|
|
2953
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
2954
|
+
"data-testid": "cs-name-manager-submit",
|
|
2955
|
+
onClick: submit,
|
|
2956
|
+
children: isEditing ? "Update" : "Add"
|
|
2957
|
+
}
|
|
2958
|
+
)
|
|
2959
|
+
] })
|
|
2960
|
+
]
|
|
2961
|
+
}
|
|
2962
|
+
);
|
|
2963
|
+
}
|
|
2964
|
+
|
|
2965
|
+
// src/chrome/InsertCellsDialog.tsx
|
|
2966
|
+
var import_react12 = require("react");
|
|
2967
|
+
var import_core2 = require("@univerjs/core");
|
|
2968
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2969
|
+
var SHIFT_OPTIONS = [
|
|
2970
|
+
{ value: "right", label: "Shift cells right" },
|
|
2971
|
+
{ value: "down", label: "Shift cells down" },
|
|
2972
|
+
{ value: "row", label: "Entire row" },
|
|
2973
|
+
{ value: "column", label: "Entire column" }
|
|
2974
|
+
];
|
|
2975
|
+
function activeRange7(api) {
|
|
2976
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
2977
|
+
}
|
|
2978
|
+
function applyInsert(api, shift) {
|
|
2979
|
+
const range = activeRange7(api);
|
|
2980
|
+
if (!range) return false;
|
|
2981
|
+
switch (shift) {
|
|
2982
|
+
case "right":
|
|
2983
|
+
range.insertCells(import_core2.Dimension.COLUMNS);
|
|
2984
|
+
return true;
|
|
2985
|
+
case "down":
|
|
2986
|
+
range.insertCells(import_core2.Dimension.ROWS);
|
|
2987
|
+
return true;
|
|
2988
|
+
case "row": {
|
|
2989
|
+
const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
|
|
2990
|
+
if (!sheet) return false;
|
|
2991
|
+
const startRow = range.getRow();
|
|
2992
|
+
const rowCount = range.getLastRow() - startRow + 1;
|
|
2993
|
+
sheet.insertRows(startRow, rowCount);
|
|
2994
|
+
return true;
|
|
2995
|
+
}
|
|
2996
|
+
case "column": {
|
|
2997
|
+
const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
|
|
2998
|
+
if (!sheet) return false;
|
|
2999
|
+
const startColumn = range.getColumn();
|
|
3000
|
+
const colCount = range.getLastColumn() - startColumn + 1;
|
|
3001
|
+
sheet.insertColumns(startColumn, colCount);
|
|
3002
|
+
return true;
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
var RANGE_NOTE_STYLE6 = {
|
|
3007
|
+
fontSize: 12,
|
|
3008
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
3009
|
+
marginBottom: 14
|
|
3010
|
+
};
|
|
3011
|
+
var RADIO_STYLE = {
|
|
3012
|
+
display: "flex",
|
|
3013
|
+
alignItems: "center",
|
|
3014
|
+
gap: 8,
|
|
3015
|
+
marginBottom: 10,
|
|
3016
|
+
cursor: "pointer"
|
|
3017
|
+
};
|
|
3018
|
+
function InsertCellsDialog({ api, onClose }) {
|
|
3019
|
+
const [shift, setShift] = (0, import_react12.useState)("down");
|
|
3020
|
+
const rangeLabel = (0, import_react12.useMemo)(() => {
|
|
3021
|
+
const fRange = activeRange7(api);
|
|
3022
|
+
return fRange?.getA1Notation?.() ?? null;
|
|
3023
|
+
}, [api]);
|
|
3024
|
+
const hasSelection = activeRange7(api) !== null;
|
|
3025
|
+
const apply = () => {
|
|
3026
|
+
if (applyInsert(api, shift)) onClose();
|
|
3027
|
+
};
|
|
3028
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3029
|
+
Dialog,
|
|
3030
|
+
{
|
|
3031
|
+
title: "Insert cells",
|
|
3032
|
+
onClose,
|
|
3033
|
+
width: 380,
|
|
3034
|
+
"data-testid": "cs-insert-cells-dialog",
|
|
3035
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
3036
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
3037
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3038
|
+
"button",
|
|
3039
|
+
{
|
|
3040
|
+
type: "button",
|
|
3041
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
3042
|
+
"data-testid": "cs-insert-cells-apply",
|
|
3043
|
+
disabled: !hasSelection,
|
|
3044
|
+
onClick: apply,
|
|
3045
|
+
children: "Insert"
|
|
3046
|
+
}
|
|
3047
|
+
)
|
|
3048
|
+
] }),
|
|
3049
|
+
children: [
|
|
3050
|
+
hasSelection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: RANGE_NOTE_STYLE6, "data-testid": "cs-insert-cells-range", children: [
|
|
3051
|
+
"Insert at ",
|
|
3052
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: rangeLabel ?? "the current selection" })
|
|
3053
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: RANGE_NOTE_STYLE6, "data-testid": "cs-insert-cells-no-selection", children: "Select one or more cells first, then reopen this dialog." }),
|
|
3054
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { role: "radiogroup", "aria-label": "Shift direction", children: SHIFT_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3055
|
+
"label",
|
|
3056
|
+
{
|
|
3057
|
+
style: RADIO_STYLE,
|
|
3058
|
+
"data-testid": `cs-insert-cells-shift-${opt.value}-label`,
|
|
3059
|
+
children: [
|
|
3060
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3061
|
+
"input",
|
|
3062
|
+
{
|
|
3063
|
+
type: "radio",
|
|
3064
|
+
name: "cs-insert-cells-shift",
|
|
3065
|
+
"data-testid": `cs-insert-cells-shift-${opt.value}`,
|
|
3066
|
+
checked: shift === opt.value,
|
|
3067
|
+
onChange: () => setShift(opt.value)
|
|
3068
|
+
}
|
|
3069
|
+
),
|
|
3070
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: opt.label })
|
|
3071
|
+
]
|
|
3072
|
+
},
|
|
3073
|
+
opt.value
|
|
3074
|
+
)) })
|
|
3075
|
+
]
|
|
3076
|
+
}
|
|
3077
|
+
);
|
|
3078
|
+
}
|
|
3079
|
+
|
|
3080
|
+
// src/chrome/DeleteCellsDialog.tsx
|
|
3081
|
+
var import_react13 = require("react");
|
|
3082
|
+
var import_core3 = require("@univerjs/core");
|
|
3083
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3084
|
+
var SHIFT_OPTIONS2 = [
|
|
3085
|
+
{ value: "left", label: "Shift cells left" },
|
|
3086
|
+
{ value: "up", label: "Shift cells up" },
|
|
3087
|
+
{ value: "row", label: "Entire row" },
|
|
3088
|
+
{ value: "column", label: "Entire column" }
|
|
3089
|
+
];
|
|
3090
|
+
function activeRange8(api) {
|
|
3091
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
3092
|
+
}
|
|
3093
|
+
function applyDelete(api, choice) {
|
|
3094
|
+
const range = activeRange8(api);
|
|
3095
|
+
if (!range) return false;
|
|
3096
|
+
if (choice === "left") {
|
|
3097
|
+
range.deleteCells(import_core3.Dimension.COLUMNS);
|
|
3098
|
+
return true;
|
|
3099
|
+
}
|
|
3100
|
+
if (choice === "up") {
|
|
3101
|
+
range.deleteCells(import_core3.Dimension.ROWS);
|
|
3102
|
+
return true;
|
|
3103
|
+
}
|
|
3104
|
+
const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
|
|
3105
|
+
if (!sheet) return false;
|
|
3106
|
+
if (choice === "row") {
|
|
3107
|
+
const start2 = range.getRow();
|
|
3108
|
+
const count2 = range.getLastRow() - start2 + 1;
|
|
3109
|
+
if (count2 <= 0) return false;
|
|
3110
|
+
sheet.deleteRows(start2, count2);
|
|
3111
|
+
return true;
|
|
3112
|
+
}
|
|
3113
|
+
const start = range.getColumn();
|
|
3114
|
+
const count = range.getLastColumn() - start + 1;
|
|
3115
|
+
if (count <= 0) return false;
|
|
3116
|
+
sheet.deleteColumns(start, count);
|
|
3117
|
+
return true;
|
|
3118
|
+
}
|
|
3119
|
+
var RANGE_NOTE_STYLE7 = {
|
|
3120
|
+
fontSize: 12,
|
|
3121
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
3122
|
+
marginBottom: 12
|
|
3123
|
+
};
|
|
3124
|
+
var OPTION_STYLE = {
|
|
3125
|
+
display: "flex",
|
|
3126
|
+
alignItems: "center",
|
|
3127
|
+
gap: 8,
|
|
3128
|
+
padding: "6px 4px",
|
|
3129
|
+
cursor: "pointer"
|
|
3130
|
+
};
|
|
3131
|
+
function DeleteCellsDialog({ api, onClose }) {
|
|
3132
|
+
const [choice, setChoice] = (0, import_react13.useState)("left");
|
|
3133
|
+
const rangeLabel = (0, import_react13.useMemo)(() => {
|
|
3134
|
+
const fRange = activeRange8(api);
|
|
3135
|
+
return fRange?.getA1Notation?.() ?? null;
|
|
3136
|
+
}, [api]);
|
|
3137
|
+
const hasSelection = activeRange8(api) !== null;
|
|
3138
|
+
const apply = () => {
|
|
3139
|
+
if (applyDelete(api, choice)) onClose();
|
|
3140
|
+
};
|
|
3141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
3142
|
+
Dialog,
|
|
3143
|
+
{
|
|
3144
|
+
title: "Delete cells",
|
|
3145
|
+
onClose,
|
|
3146
|
+
width: 360,
|
|
3147
|
+
"data-testid": "cs-delete-cells-dialog",
|
|
3148
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
3149
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
3150
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3151
|
+
"button",
|
|
3152
|
+
{
|
|
3153
|
+
type: "button",
|
|
3154
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
3155
|
+
"data-testid": "cs-delete-cells-apply",
|
|
3156
|
+
disabled: !hasSelection,
|
|
3157
|
+
onClick: apply,
|
|
3158
|
+
children: "Delete"
|
|
3159
|
+
}
|
|
3160
|
+
)
|
|
3161
|
+
] }),
|
|
3162
|
+
children: [
|
|
3163
|
+
hasSelection ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: RANGE_NOTE_STYLE7, "data-testid": "cs-delete-cells-range", children: [
|
|
3164
|
+
"Delete ",
|
|
3165
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: rangeLabel ?? "the current selection" }),
|
|
3166
|
+
" and\u2026"
|
|
3167
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: RANGE_NOTE_STYLE7, "data-testid": "cs-delete-cells-no-selection", children: "Select one or more cells first, then reopen this dialog." }),
|
|
3168
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "radiogroup", "aria-label": "Delete option", children: SHIFT_OPTIONS2.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { style: OPTION_STYLE, children: [
|
|
3169
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3170
|
+
"input",
|
|
3171
|
+
{
|
|
3172
|
+
type: "radio",
|
|
3173
|
+
name: "cs-delete-cells-shift",
|
|
3174
|
+
"data-testid": `cs-delete-cells-${opt.value}`,
|
|
3175
|
+
value: opt.value,
|
|
3176
|
+
checked: choice === opt.value,
|
|
3177
|
+
onChange: () => setChoice(opt.value)
|
|
3178
|
+
}
|
|
3179
|
+
),
|
|
3180
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: opt.label })
|
|
3181
|
+
] }, opt.value)) })
|
|
3182
|
+
]
|
|
3183
|
+
}
|
|
3184
|
+
);
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
// src/chrome/GoalSeekDialog.tsx
|
|
3188
|
+
var import_react14 = require("react");
|
|
3189
|
+
var import_facade5 = require("@univerjs/sheets-formula/facade");
|
|
3190
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
3191
|
+
function getSolver(api) {
|
|
3192
|
+
const worksheet = api.univer.getActiveWorkbook()?.getActiveSheet() ?? null;
|
|
3193
|
+
if (!worksheet) return null;
|
|
3194
|
+
const formula = api.univer.getFormula?.();
|
|
3195
|
+
return {
|
|
3196
|
+
worksheet,
|
|
3197
|
+
settle: async () => {
|
|
3198
|
+
if (formula?.onCalculationEnd) {
|
|
3199
|
+
await formula.onCalculationEnd();
|
|
3200
|
+
return;
|
|
3201
|
+
}
|
|
3202
|
+
await new Promise((resolve) => {
|
|
3203
|
+
if (typeof requestAnimationFrame === "function") requestAnimationFrame(() => resolve());
|
|
3204
|
+
else setTimeout(resolve, 16);
|
|
3205
|
+
});
|
|
3206
|
+
}
|
|
3207
|
+
};
|
|
3208
|
+
}
|
|
3209
|
+
function toNumber(value) {
|
|
3210
|
+
if (typeof value === "number") return value;
|
|
3211
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
3212
|
+
if (typeof value === "string" && value.trim() !== "") return Number(value);
|
|
3213
|
+
return Number.NaN;
|
|
3214
|
+
}
|
|
3215
|
+
function isSingleCellA1(ref) {
|
|
3216
|
+
return /^[A-Za-z]{1,3}[1-9][0-9]*$/.test(ref.trim());
|
|
3217
|
+
}
|
|
3218
|
+
var INITIAL_STATE3 = { setCell: "", toValue: "", byChangingCell: "" };
|
|
3219
|
+
var TOLERANCE = 1e-6;
|
|
3220
|
+
var MAX_ITERATIONS = 100;
|
|
3221
|
+
async function goalSeek(solver, setCellRef, target, changeCellRef) {
|
|
3222
|
+
const setRange = solver.worksheet.getRange(setCellRef);
|
|
3223
|
+
const changeRange = solver.worksheet.getRange(changeCellRef);
|
|
3224
|
+
if (!setRange || !changeRange) return { ok: false, reason: "Could not resolve the cells." };
|
|
3225
|
+
const original = toNumber(changeRange.getValue());
|
|
3226
|
+
const x0Seed = Number.isFinite(original) ? original : 0;
|
|
3227
|
+
const evalAt = async (x) => {
|
|
3228
|
+
changeRange.setValue(x);
|
|
3229
|
+
await solver.settle();
|
|
3230
|
+
return toNumber(setRange.getValue());
|
|
3231
|
+
};
|
|
3232
|
+
const restore = async () => {
|
|
3233
|
+
changeRange.setValue(x0Seed);
|
|
3234
|
+
await solver.settle();
|
|
3235
|
+
};
|
|
3236
|
+
let x0 = x0Seed;
|
|
3237
|
+
let f0 = await evalAt(x0) - target;
|
|
3238
|
+
if (!Number.isFinite(f0)) {
|
|
3239
|
+
await restore();
|
|
3240
|
+
return { ok: false, reason: "The set cell is not a number (check that it holds a formula)." };
|
|
3241
|
+
}
|
|
3242
|
+
if (Math.abs(f0) <= TOLERANCE) return { ok: true, solution: x0, result: f0 + target };
|
|
3243
|
+
let x1 = x0 !== 0 ? x0 * 1.01 + 0.01 : 1;
|
|
3244
|
+
let f1 = await evalAt(x1) - target;
|
|
3245
|
+
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
|
3246
|
+
if (Number.isFinite(f1) && Math.abs(f1) <= TOLERANCE) {
|
|
3247
|
+
return { ok: true, solution: x1, result: f1 + target };
|
|
3248
|
+
}
|
|
3249
|
+
const denom = f1 - f0;
|
|
3250
|
+
let x2;
|
|
3251
|
+
if (!Number.isFinite(f1) || denom === 0) {
|
|
3252
|
+
x2 = x1 + (x1 !== 0 ? x1 * 0.1 : 0.1);
|
|
3253
|
+
} else {
|
|
3254
|
+
const step = f1 * (x1 - x0) / denom;
|
|
3255
|
+
x2 = x1 - step;
|
|
3256
|
+
if (!Number.isFinite(x2)) x2 = x1 + (x1 !== 0 ? x1 * 0.1 : 0.1);
|
|
3257
|
+
}
|
|
3258
|
+
const f2 = await evalAt(x2) - target;
|
|
3259
|
+
x0 = x1;
|
|
3260
|
+
f0 = f1;
|
|
3261
|
+
x1 = x2;
|
|
3262
|
+
f1 = f2;
|
|
3263
|
+
}
|
|
3264
|
+
await restore();
|
|
3265
|
+
return {
|
|
3266
|
+
ok: false,
|
|
3267
|
+
reason: `Could not converge after ${MAX_ITERATIONS} iterations. Try an input cell whose value the set cell actually depends on.`
|
|
3268
|
+
};
|
|
3269
|
+
}
|
|
3270
|
+
var NOTE_STYLE = {
|
|
3271
|
+
fontSize: 12,
|
|
3272
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
3273
|
+
marginBottom: 12
|
|
3274
|
+
};
|
|
3275
|
+
var STATUS_OK_STYLE = {
|
|
3276
|
+
fontSize: 12,
|
|
3277
|
+
color: "var(--cs-chrome-active-fg, #0e7490)",
|
|
3278
|
+
marginTop: 4
|
|
3279
|
+
};
|
|
3280
|
+
var STATUS_ERR_STYLE = {
|
|
3281
|
+
fontSize: 12,
|
|
3282
|
+
color: "var(--cs-chrome-danger, #b91c1c)",
|
|
3283
|
+
marginTop: 4
|
|
3284
|
+
};
|
|
3285
|
+
function GoalSeekDialog({ api, onClose }) {
|
|
3286
|
+
const initialSetCell = (0, import_react14.useMemo)(() => {
|
|
3287
|
+
const range = api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange();
|
|
3288
|
+
const a1 = range?.getA1Notation?.();
|
|
3289
|
+
return a1 && isSingleCellA1(a1) ? a1 : "";
|
|
3290
|
+
}, [api]);
|
|
3291
|
+
const [state, setState] = (0, import_react14.useState)({ ...INITIAL_STATE3, setCell: initialSetCell });
|
|
3292
|
+
const [status, setStatus] = (0, import_react14.useState)({ kind: "idle" });
|
|
3293
|
+
const update = (key, value) => {
|
|
3294
|
+
setState((prev) => ({ ...prev, [key]: value }));
|
|
3295
|
+
setStatus({ kind: "idle" });
|
|
3296
|
+
};
|
|
3297
|
+
const setCellValid = isSingleCellA1(state.setCell);
|
|
3298
|
+
const changeCellValid = isSingleCellA1(state.byChangingCell);
|
|
3299
|
+
const targetNum = Number(state.toValue);
|
|
3300
|
+
const targetValid = state.toValue.trim() !== "" && Number.isFinite(targetNum);
|
|
3301
|
+
const canRun = setCellValid && changeCellValid && targetValid && state.setCell.trim().toUpperCase() !== state.byChangingCell.trim().toUpperCase() && status.kind !== "running";
|
|
3302
|
+
const run = async () => {
|
|
3303
|
+
const solver = getSolver(api);
|
|
3304
|
+
if (!solver) {
|
|
3305
|
+
setStatus({ kind: "error", message: "No active sheet." });
|
|
3306
|
+
return;
|
|
3307
|
+
}
|
|
3308
|
+
setStatus({ kind: "running" });
|
|
3309
|
+
try {
|
|
3310
|
+
const result = await goalSeek(
|
|
3311
|
+
solver,
|
|
3312
|
+
state.setCell.trim(),
|
|
3313
|
+
targetNum,
|
|
3314
|
+
state.byChangingCell.trim()
|
|
3315
|
+
);
|
|
3316
|
+
if (result.ok) {
|
|
3317
|
+
setStatus({ kind: "done", solution: result.solution, result: result.result });
|
|
3318
|
+
} else {
|
|
3319
|
+
setStatus({ kind: "error", message: result.reason });
|
|
3320
|
+
}
|
|
3321
|
+
} catch (err) {
|
|
3322
|
+
setStatus({
|
|
3323
|
+
kind: "error",
|
|
3324
|
+
message: err instanceof Error ? err.message : "Goal seek failed."
|
|
3325
|
+
});
|
|
3326
|
+
}
|
|
3327
|
+
};
|
|
3328
|
+
const running = status.kind === "running";
|
|
3329
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3330
|
+
Dialog,
|
|
3331
|
+
{
|
|
3332
|
+
title: "Goal seek",
|
|
3333
|
+
onClose,
|
|
3334
|
+
width: 420,
|
|
3335
|
+
"data-testid": "cs-goal-seek-dialog",
|
|
3336
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
3337
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: status.kind === "done" ? "Done" : "Cancel" }),
|
|
3338
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3339
|
+
"button",
|
|
3340
|
+
{
|
|
3341
|
+
type: "button",
|
|
3342
|
+
style: { ...DIALOG_BTN_PRIMARY_STYLE, opacity: canRun ? 1 : 0.5 },
|
|
3343
|
+
"data-testid": "cs-goal-seek-run",
|
|
3344
|
+
disabled: !canRun,
|
|
3345
|
+
onClick: run,
|
|
3346
|
+
children: running ? "Solving\u2026" : "Solve"
|
|
3347
|
+
}
|
|
3348
|
+
)
|
|
3349
|
+
] }),
|
|
3350
|
+
children: [
|
|
3351
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: NOTE_STYLE, "data-testid": "cs-goal-seek-note", children: "Drives the input cell until the formula cell reaches your target value." }),
|
|
3352
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
3353
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Set cell (formula cell)" }),
|
|
3354
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3355
|
+
"input",
|
|
3356
|
+
{
|
|
3357
|
+
style: DIALOG_INPUT_STYLE,
|
|
3358
|
+
"data-testid": "cs-goal-seek-set-cell",
|
|
3359
|
+
placeholder: "e.g. B5",
|
|
3360
|
+
value: state.setCell,
|
|
3361
|
+
onChange: (e) => update("setCell", e.target.value)
|
|
3362
|
+
}
|
|
3363
|
+
)
|
|
3364
|
+
] }),
|
|
3365
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
3366
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "To value" }),
|
|
3367
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3368
|
+
"input",
|
|
3369
|
+
{
|
|
3370
|
+
style: DIALOG_INPUT_STYLE,
|
|
3371
|
+
"data-testid": "cs-goal-seek-to-value",
|
|
3372
|
+
type: "number",
|
|
3373
|
+
placeholder: "e.g. 1000",
|
|
3374
|
+
value: state.toValue,
|
|
3375
|
+
onChange: (e) => update("toValue", e.target.value)
|
|
3376
|
+
}
|
|
3377
|
+
)
|
|
3378
|
+
] }),
|
|
3379
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
3380
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "By changing cell (input cell)" }),
|
|
3381
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3382
|
+
"input",
|
|
3383
|
+
{
|
|
3384
|
+
style: DIALOG_INPUT_STYLE,
|
|
3385
|
+
"data-testid": "cs-goal-seek-change-cell",
|
|
3386
|
+
placeholder: "e.g. B2",
|
|
3387
|
+
value: state.byChangingCell,
|
|
3388
|
+
onChange: (e) => update("byChangingCell", e.target.value)
|
|
3389
|
+
}
|
|
3390
|
+
)
|
|
3391
|
+
] }),
|
|
3392
|
+
status.kind === "done" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: STATUS_OK_STYLE, "data-testid": "cs-goal-seek-success", children: [
|
|
3393
|
+
"Solved: ",
|
|
3394
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: state.byChangingCell.trim().toUpperCase() }),
|
|
3395
|
+
" =",
|
|
3396
|
+
" ",
|
|
3397
|
+
formatNumber(status.solution),
|
|
3398
|
+
" makes",
|
|
3399
|
+
" ",
|
|
3400
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: state.setCell.trim().toUpperCase() }),
|
|
3401
|
+
" = ",
|
|
3402
|
+
formatNumber(status.result),
|
|
3403
|
+
"."
|
|
3404
|
+
] }),
|
|
3405
|
+
status.kind === "error" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: STATUS_ERR_STYLE, "data-testid": "cs-goal-seek-error", children: status.message })
|
|
3406
|
+
]
|
|
3407
|
+
}
|
|
3408
|
+
);
|
|
3409
|
+
}
|
|
3410
|
+
function formatNumber(n) {
|
|
3411
|
+
if (!Number.isFinite(n)) return String(n);
|
|
3412
|
+
const rounded = Math.round(n * 1e6) / 1e6;
|
|
3413
|
+
return String(rounded);
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
// src/chrome/InsertChartDialog.tsx
|
|
3417
|
+
var import_react15 = require("react");
|
|
3418
|
+
var import_facade6 = require("@univerjs/sheets-drawing-ui/facade");
|
|
3419
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
3420
|
+
var CHART_TYPE_OPTIONS = [
|
|
3421
|
+
{ value: "column", label: "Column" },
|
|
3422
|
+
{ value: "bar", label: "Bar" },
|
|
3423
|
+
{ value: "line", label: "Line" },
|
|
3424
|
+
{ value: "pie", label: "Pie" }
|
|
3425
|
+
];
|
|
3426
|
+
var CHART_COMPONENT_KEY = "cs-builtin-chart-preview";
|
|
3427
|
+
var PALETTE = ["#0e7490", "#f59e0b", "#10b981", "#ef4444", "#6366f1", "#ec4899"];
|
|
3428
|
+
function activeRange9(api) {
|
|
3429
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
3430
|
+
}
|
|
3431
|
+
function activeSheet2(api) {
|
|
3432
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet() ?? null;
|
|
3433
|
+
}
|
|
3434
|
+
function readRangeNumbers(api) {
|
|
3435
|
+
const snap = api.getSnapshot();
|
|
3436
|
+
const sel = api.getSelection();
|
|
3437
|
+
if (!snap || !sel) return [];
|
|
3438
|
+
const sheet = snap.sheets?.[sel.sheetId];
|
|
3439
|
+
if (!sheet) return [];
|
|
3440
|
+
const { startRow, endRow, startColumn, endColumn } = sel.range;
|
|
3441
|
+
const out = [];
|
|
3442
|
+
for (let r = startRow; r <= endRow; r++) {
|
|
3443
|
+
for (let c = startColumn; c <= endColumn; c++) {
|
|
3444
|
+
const raw = sheet.cellData?.[r]?.[c]?.v;
|
|
3445
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
3446
|
+
if (Number.isFinite(n)) out.push(n);
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
return out;
|
|
3450
|
+
}
|
|
3451
|
+
function ensureChartComponent(api) {
|
|
3452
|
+
const uni = api.univer;
|
|
3453
|
+
if (uni.__csChartRegistered || typeof uni.registerComponent !== "function") return;
|
|
3454
|
+
uni.registerComponent(CHART_COMPONENT_KEY, ChartPreview);
|
|
3455
|
+
uni.__csChartRegistered = true;
|
|
3456
|
+
}
|
|
3457
|
+
function insertChart(api, s) {
|
|
3458
|
+
const range = activeRange9(api);
|
|
3459
|
+
const sheet = activeSheet2(api);
|
|
3460
|
+
if (!range || !sheet) return false;
|
|
3461
|
+
ensureChartComponent(api);
|
|
3462
|
+
const values = readRangeNumbers(api);
|
|
3463
|
+
const domSheet = sheet;
|
|
3464
|
+
if (typeof domSheet.addFloatDomToRange !== "function") return false;
|
|
3465
|
+
const result = domSheet.addFloatDomToRange(
|
|
3466
|
+
range,
|
|
3467
|
+
{
|
|
3468
|
+
componentKey: CHART_COMPONENT_KEY,
|
|
3469
|
+
allowTransform: true,
|
|
3470
|
+
data: { type: s.chartType, values, rangeA1: s.rangeA1 }
|
|
3471
|
+
},
|
|
3472
|
+
{ width: 360, height: 240, marginX: 0, marginY: 0 },
|
|
3473
|
+
`cs-chart-${Date.now()}`
|
|
3474
|
+
);
|
|
3475
|
+
return result != null;
|
|
3476
|
+
}
|
|
3477
|
+
function ChartPreview({
|
|
3478
|
+
data
|
|
3479
|
+
}) {
|
|
3480
|
+
const type = data?.type ?? "column";
|
|
3481
|
+
const values = (data?.values ?? []).slice(0, 24);
|
|
3482
|
+
const label = data?.rangeA1 ?? "";
|
|
3483
|
+
const wrapStyle = {
|
|
3484
|
+
width: "100%",
|
|
3485
|
+
height: "100%",
|
|
3486
|
+
boxSizing: "border-box",
|
|
3487
|
+
background: "#ffffff",
|
|
3488
|
+
border: "1px solid #cdd3db",
|
|
3489
|
+
borderRadius: 6,
|
|
3490
|
+
padding: 8,
|
|
3491
|
+
display: "flex",
|
|
3492
|
+
flexDirection: "column",
|
|
3493
|
+
font: "12px system-ui, sans-serif",
|
|
3494
|
+
color: "#201f1e",
|
|
3495
|
+
overflow: "hidden"
|
|
3496
|
+
};
|
|
3497
|
+
const titleStyle = {
|
|
3498
|
+
fontWeight: 600,
|
|
3499
|
+
marginBottom: 4,
|
|
3500
|
+
whiteSpace: "nowrap",
|
|
3501
|
+
overflow: "hidden",
|
|
3502
|
+
textOverflow: "ellipsis"
|
|
3503
|
+
};
|
|
3504
|
+
const W = 340;
|
|
3505
|
+
const H = 176;
|
|
3506
|
+
const max = values.length ? Math.max(...values, 0) : 0;
|
|
3507
|
+
const min = values.length ? Math.min(...values, 0) : 0;
|
|
3508
|
+
const span = max - min || 1;
|
|
3509
|
+
let body;
|
|
3510
|
+
if (values.length === 0) {
|
|
3511
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("text", { x: W / 2, y: H / 2, textAnchor: "middle", fill: "#605e5c", children: "No numeric data in range" });
|
|
3512
|
+
} else if (type === "pie") {
|
|
3513
|
+
const total = values.reduce((a, v) => a + Math.abs(v), 0) || 1;
|
|
3514
|
+
const cx = W / 2;
|
|
3515
|
+
const cy = H / 2;
|
|
3516
|
+
const rad = Math.min(W, H) / 2 - 6;
|
|
3517
|
+
let angle = -Math.PI / 2;
|
|
3518
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: values.map((v, i) => {
|
|
3519
|
+
const frac = Math.abs(v) / total;
|
|
3520
|
+
const next = angle + frac * Math.PI * 2;
|
|
3521
|
+
const x1 = cx + rad * Math.cos(angle);
|
|
3522
|
+
const y1 = cy + rad * Math.sin(angle);
|
|
3523
|
+
const x2 = cx + rad * Math.cos(next);
|
|
3524
|
+
const y2 = cy + rad * Math.sin(next);
|
|
3525
|
+
const large = frac > 0.5 ? 1 : 0;
|
|
3526
|
+
const d = `M ${cx} ${cy} L ${x1} ${y1} A ${rad} ${rad} 0 ${large} 1 ${x2} ${y2} Z`;
|
|
3527
|
+
angle = next;
|
|
3528
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d, fill: PALETTE[i % PALETTE.length] }, i);
|
|
3529
|
+
}) });
|
|
3530
|
+
} else if (type === "line") {
|
|
3531
|
+
const step = values.length > 1 ? W / (values.length - 1) : W;
|
|
3532
|
+
const pts = values.map((v, i) => `${i * step},${H - (v - min) / span * H}`).join(" ");
|
|
3533
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("polyline", { points: pts, fill: "none", stroke: PALETTE[0], strokeWidth: 2 });
|
|
3534
|
+
} else {
|
|
3535
|
+
const horizontal = type === "bar";
|
|
3536
|
+
const n = values.length;
|
|
3537
|
+
const gap = 4;
|
|
3538
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: values.map((v, i) => {
|
|
3539
|
+
const fill = PALETTE[i % PALETTE.length];
|
|
3540
|
+
if (horizontal) {
|
|
3541
|
+
const bh2 = H / n - gap;
|
|
3542
|
+
const bw2 = (v - min) / span * W;
|
|
3543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3544
|
+
"rect",
|
|
3545
|
+
{
|
|
3546
|
+
x: 0,
|
|
3547
|
+
y: i * (bh2 + gap),
|
|
3548
|
+
width: Math.max(bw2, 1),
|
|
3549
|
+
height: bh2,
|
|
3550
|
+
fill
|
|
3551
|
+
},
|
|
3552
|
+
i
|
|
3553
|
+
);
|
|
3554
|
+
}
|
|
3555
|
+
const bw = W / n - gap;
|
|
3556
|
+
const bh = (v - min) / span * H;
|
|
3557
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3558
|
+
"rect",
|
|
3559
|
+
{
|
|
3560
|
+
x: i * (bw + gap),
|
|
3561
|
+
y: H - bh,
|
|
3562
|
+
width: bw,
|
|
3563
|
+
height: Math.max(bh, 1),
|
|
3564
|
+
fill
|
|
3565
|
+
},
|
|
3566
|
+
i
|
|
3567
|
+
);
|
|
3568
|
+
}) });
|
|
3569
|
+
}
|
|
3570
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: wrapStyle, children: [
|
|
3571
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: titleStyle, children: `${type[0].toUpperCase()}${type.slice(1)} chart \xB7 ${label}` }),
|
|
3572
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { viewBox: `0 0 ${W} ${H}`, width: "100%", height: "100%", preserveAspectRatio: "xMidYMid meet", children: body })
|
|
3573
|
+
] });
|
|
3574
|
+
}
|
|
3575
|
+
var RANGE_NOTE_STYLE8 = {
|
|
3576
|
+
fontSize: 12,
|
|
3577
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
3578
|
+
marginBottom: 12
|
|
3579
|
+
};
|
|
3580
|
+
var TYPE_ROW_STYLE = {
|
|
3581
|
+
display: "grid",
|
|
3582
|
+
gridTemplateColumns: "repeat(4, 1fr)",
|
|
3583
|
+
gap: 8,
|
|
3584
|
+
marginBottom: 12
|
|
3585
|
+
};
|
|
3586
|
+
function typeCardStyle(selected) {
|
|
3587
|
+
return {
|
|
3588
|
+
display: "flex",
|
|
3589
|
+
flexDirection: "column",
|
|
3590
|
+
alignItems: "center",
|
|
3591
|
+
gap: 6,
|
|
3592
|
+
padding: "10px 4px",
|
|
3593
|
+
border: `1px solid ${selected ? "var(--cs-chrome-active-fg, #0e7490)" : "var(--cs-chrome-border, #cdd3db)"}`,
|
|
3594
|
+
borderRadius: 8,
|
|
3595
|
+
background: selected ? "var(--cs-chrome-active-bg, #ecfeff)" : "var(--cs-chrome-input-bg, #fff)",
|
|
3596
|
+
color: selected ? "var(--cs-chrome-active-fg, #0e7490)" : "var(--cs-chrome-fg, #201f1e)",
|
|
3597
|
+
font: "inherit",
|
|
3598
|
+
fontSize: 12,
|
|
3599
|
+
cursor: "pointer"
|
|
3600
|
+
};
|
|
3601
|
+
}
|
|
3602
|
+
function TypeGlyph({ type }) {
|
|
3603
|
+
const c = "currentColor";
|
|
3604
|
+
switch (type) {
|
|
3605
|
+
case "column":
|
|
3606
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { width: 22, height: 22, viewBox: "0 0 22 22", fill: c, "aria-hidden": "true", children: [
|
|
3607
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: 2, y: 10, width: 4, height: 10 }),
|
|
3608
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: 9, y: 5, width: 4, height: 15 }),
|
|
3609
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: 16, y: 2, width: 4, height: 18 })
|
|
3610
|
+
] });
|
|
3611
|
+
case "bar":
|
|
3612
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { width: 22, height: 22, viewBox: "0 0 22 22", fill: c, "aria-hidden": "true", children: [
|
|
3613
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: 2, y: 2, width: 10, height: 4 }),
|
|
3614
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: 2, y: 9, width: 16, height: 4 }),
|
|
3615
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: 2, y: 16, width: 7, height: 4 })
|
|
3616
|
+
] });
|
|
3617
|
+
case "line":
|
|
3618
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3619
|
+
"svg",
|
|
3620
|
+
{
|
|
3621
|
+
width: 22,
|
|
3622
|
+
height: 22,
|
|
3623
|
+
viewBox: "0 0 22 22",
|
|
3624
|
+
fill: "none",
|
|
3625
|
+
stroke: c,
|
|
3626
|
+
strokeWidth: 2,
|
|
3627
|
+
"aria-hidden": "true",
|
|
3628
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("polyline", { points: "2,16 8,9 13,13 20,3" })
|
|
3629
|
+
}
|
|
3630
|
+
);
|
|
3631
|
+
case "pie":
|
|
3632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { width: 22, height: 22, viewBox: "0 0 22 22", fill: c, "aria-hidden": "true", children: [
|
|
3633
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M11 11 L11 2 A9 9 0 0 1 20 11 Z" }),
|
|
3634
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: 11, cy: 11, r: 9, fill: "none", stroke: c, strokeWidth: 1.5 })
|
|
3635
|
+
] });
|
|
3636
|
+
}
|
|
3637
|
+
}
|
|
3638
|
+
function InsertChartDialog({ api, onClose }) {
|
|
3639
|
+
const rangeLabel = (0, import_react15.useMemo)(() => {
|
|
3640
|
+
const fRange = activeRange9(api);
|
|
3641
|
+
return fRange?.getA1Notation?.() ?? null;
|
|
3642
|
+
}, [api]);
|
|
3643
|
+
const [state, setState] = (0, import_react15.useState)(() => ({
|
|
3644
|
+
chartType: "column",
|
|
3645
|
+
rangeA1: rangeLabel ?? ""
|
|
3646
|
+
}));
|
|
3647
|
+
const hasSelection = activeRange9(api) !== null;
|
|
3648
|
+
const update = (key, value) => setState((prev) => ({ ...prev, [key]: value }));
|
|
3649
|
+
const apply = () => {
|
|
3650
|
+
if (insertChart(api, state)) onClose();
|
|
3651
|
+
};
|
|
3652
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
3653
|
+
Dialog,
|
|
3654
|
+
{
|
|
3655
|
+
title: "Insert chart",
|
|
3656
|
+
onClose,
|
|
3657
|
+
width: 440,
|
|
3658
|
+
"data-testid": "cs-insert-chart-dialog",
|
|
3659
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
3660
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
3661
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3662
|
+
"button",
|
|
3663
|
+
{
|
|
3664
|
+
type: "button",
|
|
3665
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
3666
|
+
"data-testid": "cs-insert-chart-apply",
|
|
3667
|
+
disabled: !hasSelection,
|
|
3668
|
+
onClick: apply,
|
|
3669
|
+
children: "Insert"
|
|
3670
|
+
}
|
|
3671
|
+
)
|
|
3672
|
+
] }),
|
|
3673
|
+
children: [
|
|
3674
|
+
hasSelection ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: RANGE_NOTE_STYLE8, "data-testid": "cs-insert-chart-range", children: [
|
|
3675
|
+
"Chart from ",
|
|
3676
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: rangeLabel ?? "the current selection" })
|
|
3677
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: RANGE_NOTE_STYLE8, "data-testid": "cs-insert-chart-no-selection", children: "Select the data range first, then reopen this dialog." }),
|
|
3678
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: DIALOG_LABEL_STYLE, children: "Chart type" }),
|
|
3679
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: TYPE_ROW_STYLE, role: "radiogroup", "aria-label": "Chart type", children: CHART_TYPE_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
3680
|
+
"button",
|
|
3681
|
+
{
|
|
3682
|
+
type: "button",
|
|
3683
|
+
role: "radio",
|
|
3684
|
+
"aria-checked": state.chartType === opt.value,
|
|
3685
|
+
"data-testid": `cs-insert-chart-type-${opt.value}`,
|
|
3686
|
+
style: typeCardStyle(state.chartType === opt.value),
|
|
3687
|
+
onClick: () => update("chartType", opt.value),
|
|
3688
|
+
children: [
|
|
3689
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TypeGlyph, { type: opt.value }),
|
|
3690
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: opt.label })
|
|
3691
|
+
]
|
|
3692
|
+
},
|
|
3693
|
+
opt.value
|
|
3694
|
+
)) }),
|
|
3695
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
3696
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Data range" }),
|
|
3697
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3698
|
+
"input",
|
|
3699
|
+
{
|
|
3700
|
+
style: DIALOG_INPUT_STYLE,
|
|
3701
|
+
"data-testid": "cs-insert-chart-range-input",
|
|
3702
|
+
value: state.rangeA1,
|
|
3703
|
+
placeholder: "A1:B5",
|
|
3704
|
+
onChange: (e) => update("rangeA1", e.target.value)
|
|
3705
|
+
}
|
|
3706
|
+
)
|
|
3707
|
+
] }),
|
|
3708
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: RANGE_NOTE_STYLE8, children: "The chart is placed over the current selection. Numeric cells in the range become the series." })
|
|
3709
|
+
]
|
|
3710
|
+
}
|
|
3711
|
+
);
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3714
|
+
// src/chrome/InsertSparklineDialog.tsx
|
|
3715
|
+
var import_react16 = require("react");
|
|
3716
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
3717
|
+
var SPARKLINES_RESOURCE_NAME = "__casual_sheets_sparklines__";
|
|
3718
|
+
var TYPE_OPTIONS = [
|
|
3719
|
+
{ value: "line", label: "Line" },
|
|
3720
|
+
{ value: "column", label: "Column" },
|
|
3721
|
+
{ value: "win-loss", label: "Win / Loss" }
|
|
3722
|
+
];
|
|
3723
|
+
function activeRange10(api) {
|
|
3724
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
3725
|
+
}
|
|
3726
|
+
function colLettersToIndex(letters) {
|
|
3727
|
+
let n = 0;
|
|
3728
|
+
for (let i = 0; i < letters.length; i += 1) {
|
|
3729
|
+
n = n * 26 + (letters.charCodeAt(i) - 64);
|
|
3730
|
+
}
|
|
3731
|
+
return n - 1;
|
|
3732
|
+
}
|
|
3733
|
+
function parseRange(s) {
|
|
3734
|
+
const m = /^\$?([A-Z]+)\$?(\d+)(?::\$?([A-Z]+)\$?(\d+))?$/.exec(s.trim().toUpperCase());
|
|
3735
|
+
if (!m) return null;
|
|
3736
|
+
const c1 = colLettersToIndex(m[1]);
|
|
3737
|
+
const r1 = parseInt(m[2], 10) - 1;
|
|
3738
|
+
const c2 = m[3] ? colLettersToIndex(m[3]) : c1;
|
|
3739
|
+
const r2 = m[4] ? parseInt(m[4], 10) - 1 : r1;
|
|
3740
|
+
return {
|
|
3741
|
+
startRow: Math.min(r1, r2),
|
|
3742
|
+
endRow: Math.max(r1, r2),
|
|
3743
|
+
startColumn: Math.min(c1, c2),
|
|
3744
|
+
endColumn: Math.max(c1, c2)
|
|
3745
|
+
};
|
|
3746
|
+
}
|
|
3747
|
+
function parseSingleCell(s) {
|
|
3748
|
+
const m = /^\$?([A-Z]+)\$?(\d+)$/.exec(s.trim().toUpperCase());
|
|
3749
|
+
if (!m) return null;
|
|
3750
|
+
return { col: colLettersToIndex(m[1]), row: parseInt(m[2], 10) - 1 };
|
|
3751
|
+
}
|
|
3752
|
+
function insertSparkline(api, model) {
|
|
3753
|
+
const data = api.getContent();
|
|
3754
|
+
if (!data) return false;
|
|
3755
|
+
const resources = data.resources ? [...data.resources] : [];
|
|
3756
|
+
const idx = resources.findIndex((r) => r.name === SPARKLINES_RESOURCE_NAME);
|
|
3757
|
+
let existing = [];
|
|
3758
|
+
if (idx >= 0 && resources[idx]?.data) {
|
|
3759
|
+
try {
|
|
3760
|
+
const parsed = JSON.parse(resources[idx].data);
|
|
3761
|
+
if (parsed?.v === 1 && Array.isArray(parsed.sparklines)) existing = parsed.sparklines;
|
|
3762
|
+
} catch {
|
|
3763
|
+
existing = [];
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
const payload = { v: 1, sparklines: [...existing, model] };
|
|
3767
|
+
const entry = { name: SPARKLINES_RESOURCE_NAME, data: JSON.stringify(payload) };
|
|
3768
|
+
if (idx >= 0) resources[idx] = entry;
|
|
3769
|
+
else resources.push(entry);
|
|
3770
|
+
const next = { ...data, resources };
|
|
3771
|
+
api.setContent(next);
|
|
3772
|
+
return true;
|
|
3773
|
+
}
|
|
3774
|
+
function activeIds(api) {
|
|
3775
|
+
const wb = api.univer.getActiveWorkbook();
|
|
3776
|
+
const sheet = wb?.getActiveSheet();
|
|
3777
|
+
if (!wb || !sheet) return null;
|
|
3778
|
+
return { unitId: wb.getId(), sheetId: sheet.getSheetId() };
|
|
3779
|
+
}
|
|
3780
|
+
var RANGE_NOTE_STYLE9 = {
|
|
3781
|
+
fontSize: 12,
|
|
3782
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
3783
|
+
marginBottom: 12
|
|
3784
|
+
};
|
|
3785
|
+
var RADIO_ROW_STYLE = {
|
|
3786
|
+
display: "flex",
|
|
3787
|
+
gap: 16,
|
|
3788
|
+
marginTop: 2
|
|
3789
|
+
};
|
|
3790
|
+
var RADIO_OPT_STYLE = {
|
|
3791
|
+
display: "flex",
|
|
3792
|
+
alignItems: "center",
|
|
3793
|
+
gap: 6,
|
|
3794
|
+
cursor: "pointer"
|
|
3795
|
+
};
|
|
3796
|
+
var ERROR_STYLE2 = {
|
|
3797
|
+
fontSize: 12,
|
|
3798
|
+
color: "var(--cs-chrome-danger-fg, #b91c1c)",
|
|
3799
|
+
marginTop: 4
|
|
3800
|
+
};
|
|
3801
|
+
function InsertSparklineDialog({ api, onClose }) {
|
|
3802
|
+
const selectedA1 = (0, import_react16.useMemo)(() => {
|
|
3803
|
+
const fRange = activeRange10(api);
|
|
3804
|
+
return fRange?.getA1Notation?.() ?? "";
|
|
3805
|
+
}, [api]);
|
|
3806
|
+
const [state, setState] = (0, import_react16.useState)({
|
|
3807
|
+
type: "line",
|
|
3808
|
+
sourceA1: selectedA1,
|
|
3809
|
+
anchorA1: ""
|
|
3810
|
+
});
|
|
3811
|
+
const [error, setError] = (0, import_react16.useState)(null);
|
|
3812
|
+
const hasWorkbook = api.univer.getActiveWorkbook() != null;
|
|
3813
|
+
const update = (key, value) => {
|
|
3814
|
+
setState((prev) => ({ ...prev, [key]: value }));
|
|
3815
|
+
setError(null);
|
|
3816
|
+
};
|
|
3817
|
+
const apply = () => {
|
|
3818
|
+
const source = parseRange(state.sourceA1);
|
|
3819
|
+
if (!source) {
|
|
3820
|
+
setError("Data range must be a range like A1:F1.");
|
|
3821
|
+
return;
|
|
3822
|
+
}
|
|
3823
|
+
const anchor = parseSingleCell(state.anchorA1);
|
|
3824
|
+
if (!anchor) {
|
|
3825
|
+
setError("Location must be a single cell like G1.");
|
|
3826
|
+
return;
|
|
3827
|
+
}
|
|
3828
|
+
const ids = activeIds(api);
|
|
3829
|
+
if (!ids) {
|
|
3830
|
+
setError("No active sheet.");
|
|
3831
|
+
return;
|
|
3832
|
+
}
|
|
3833
|
+
const model = {
|
|
3834
|
+
id: `spark-${Math.random().toString(36).slice(2, 10)}`,
|
|
3835
|
+
type: state.type,
|
|
3836
|
+
unitId: ids.unitId,
|
|
3837
|
+
sheetId: ids.sheetId,
|
|
3838
|
+
source,
|
|
3839
|
+
anchor
|
|
3840
|
+
};
|
|
3841
|
+
if (insertSparkline(api, model)) onClose();
|
|
3842
|
+
else setError("Could not read the active workbook.");
|
|
3843
|
+
};
|
|
3844
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3845
|
+
Dialog,
|
|
3846
|
+
{
|
|
3847
|
+
title: "Insert sparkline",
|
|
3848
|
+
onClose,
|
|
3849
|
+
width: 420,
|
|
3850
|
+
"data-testid": "cs-insert-sparkline-dialog",
|
|
3851
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3852
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
3853
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3854
|
+
"button",
|
|
3855
|
+
{
|
|
3856
|
+
type: "button",
|
|
3857
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
3858
|
+
"data-testid": "cs-insert-sparkline-apply",
|
|
3859
|
+
disabled: !hasWorkbook,
|
|
3860
|
+
onClick: apply,
|
|
3861
|
+
children: "Insert"
|
|
3862
|
+
}
|
|
3863
|
+
)
|
|
3864
|
+
] }),
|
|
3865
|
+
children: [
|
|
3866
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: RANGE_NOTE_STYLE9, children: "Draws an in-cell mini-chart in the location cell from the values in the data range." }),
|
|
3867
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
3868
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Type" }),
|
|
3869
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3870
|
+
"div",
|
|
3871
|
+
{
|
|
3872
|
+
style: RADIO_ROW_STYLE,
|
|
3873
|
+
role: "radiogroup",
|
|
3874
|
+
"aria-label": "Sparkline type",
|
|
3875
|
+
"data-testid": "cs-insert-sparkline-type",
|
|
3876
|
+
children: TYPE_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { style: RADIO_OPT_STYLE, children: [
|
|
3877
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3878
|
+
"input",
|
|
3879
|
+
{
|
|
3880
|
+
type: "radio",
|
|
3881
|
+
name: "cs-sparkline-type",
|
|
3882
|
+
value: opt.value,
|
|
3883
|
+
"data-testid": `cs-insert-sparkline-type-${opt.value}`,
|
|
3884
|
+
checked: state.type === opt.value,
|
|
3885
|
+
onChange: () => update("type", opt.value)
|
|
3886
|
+
}
|
|
3887
|
+
),
|
|
3888
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: opt.label })
|
|
3889
|
+
] }, opt.value))
|
|
3890
|
+
}
|
|
3891
|
+
)
|
|
3892
|
+
] }),
|
|
3893
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
3894
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Data range" }),
|
|
3895
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3896
|
+
"input",
|
|
3897
|
+
{
|
|
3898
|
+
style: DIALOG_INPUT_STYLE,
|
|
3899
|
+
"data-testid": "cs-insert-sparkline-source",
|
|
3900
|
+
value: state.sourceA1,
|
|
3901
|
+
placeholder: "A1:F1",
|
|
3902
|
+
spellCheck: false,
|
|
3903
|
+
onChange: (e) => update("sourceA1", e.target.value.toUpperCase())
|
|
3904
|
+
}
|
|
3905
|
+
)
|
|
3906
|
+
] }),
|
|
3907
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
3908
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Location" }),
|
|
3909
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3910
|
+
"input",
|
|
3911
|
+
{
|
|
3912
|
+
style: DIALOG_INPUT_STYLE,
|
|
3913
|
+
"data-testid": "cs-insert-sparkline-anchor",
|
|
3914
|
+
value: state.anchorA1,
|
|
3915
|
+
placeholder: "G1",
|
|
3916
|
+
spellCheck: false,
|
|
3917
|
+
onChange: (e) => update("anchorA1", e.target.value.toUpperCase())
|
|
3918
|
+
}
|
|
3919
|
+
)
|
|
3920
|
+
] }),
|
|
3921
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: ERROR_STYLE2, "data-testid": "cs-insert-sparkline-error", children: error })
|
|
3922
|
+
]
|
|
3923
|
+
}
|
|
3924
|
+
);
|
|
3925
|
+
}
|
|
3926
|
+
|
|
3927
|
+
// src/chrome/InsertPivotDialog.tsx
|
|
3928
|
+
var import_react17 = require("react");
|
|
3929
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
3930
|
+
var AGG_OPTIONS = [
|
|
3931
|
+
{ value: "sum", label: "Sum" },
|
|
3932
|
+
{ value: "count", label: "Count" },
|
|
3933
|
+
{ value: "average", label: "Average" },
|
|
3934
|
+
{ value: "min", label: "Min" },
|
|
3935
|
+
{ value: "max", label: "Max" }
|
|
3936
|
+
];
|
|
3937
|
+
function activeRange11(api) {
|
|
3938
|
+
return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
3939
|
+
}
|
|
3940
|
+
function readSource(api) {
|
|
3941
|
+
const range = activeRange11(api);
|
|
3942
|
+
const grid = range?.getValues?.() ?? [];
|
|
3943
|
+
return Array.isArray(grid) ? grid : [];
|
|
3944
|
+
}
|
|
3945
|
+
function columnLabel(index, headerRow, useHeader) {
|
|
3946
|
+
if (useHeader) {
|
|
3947
|
+
const raw = headerRow?.[index];
|
|
3948
|
+
if (raw != null && String(raw).trim().length > 0) return String(raw);
|
|
3949
|
+
}
|
|
3950
|
+
let n = index;
|
|
3951
|
+
let label = "";
|
|
3952
|
+
do {
|
|
3953
|
+
label = String.fromCharCode(65 + n % 26) + label;
|
|
3954
|
+
n = Math.floor(n / 26) - 1;
|
|
3955
|
+
} while (n >= 0);
|
|
3956
|
+
return `Column ${label}`;
|
|
3957
|
+
}
|
|
3958
|
+
function toNumber2(v) {
|
|
3959
|
+
if (typeof v === "number") return Number.isFinite(v) ? v : null;
|
|
3960
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
3961
|
+
if (typeof v === "string" && v.trim() !== "") {
|
|
3962
|
+
const n = Number(v);
|
|
3963
|
+
return Number.isFinite(n) ? n : null;
|
|
3964
|
+
}
|
|
3965
|
+
return null;
|
|
3966
|
+
}
|
|
3967
|
+
function aggregate(fn, values, rowCount) {
|
|
3968
|
+
if (fn === "count") return rowCount;
|
|
3969
|
+
if (values.length === 0) return 0;
|
|
3970
|
+
switch (fn) {
|
|
3971
|
+
case "sum":
|
|
3972
|
+
return values.reduce((a, b) => a + b, 0);
|
|
3973
|
+
case "average":
|
|
3974
|
+
return values.reduce((a, b) => a + b, 0) / values.length;
|
|
3975
|
+
case "min":
|
|
3976
|
+
return Math.min(...values);
|
|
3977
|
+
case "max":
|
|
3978
|
+
return Math.max(...values);
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
function buildPivot(source, useHeader, groupCol, valueCol, fn) {
|
|
3982
|
+
if (source.length === 0) return null;
|
|
3983
|
+
const headerRow = useHeader ? source[0] : void 0;
|
|
3984
|
+
const dataRows = useHeader ? source.slice(1) : source;
|
|
3985
|
+
if (dataRows.length === 0) return null;
|
|
3986
|
+
const order = [];
|
|
3987
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
3988
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3989
|
+
for (const row of dataRows) {
|
|
3990
|
+
const rawKey = row[groupCol];
|
|
3991
|
+
const key = rawKey == null ? "" : String(rawKey);
|
|
3992
|
+
if (!buckets.has(key)) {
|
|
3993
|
+
buckets.set(key, []);
|
|
3994
|
+
counts.set(key, 0);
|
|
3995
|
+
order.push(key);
|
|
3996
|
+
}
|
|
3997
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
3998
|
+
const num = toNumber2(row[valueCol]);
|
|
3999
|
+
if (num != null) buckets.get(key).push(num);
|
|
4000
|
+
}
|
|
4001
|
+
const groupHeader = columnLabel(groupCol, headerRow, useHeader);
|
|
4002
|
+
const valueHeader = columnLabel(valueCol, headerRow, useHeader);
|
|
4003
|
+
const aggLabel = AGG_OPTIONS.find((o) => o.value === fn)?.label ?? "Sum";
|
|
4004
|
+
const grid = [[groupHeader, `${aggLabel} of ${valueHeader}`]];
|
|
4005
|
+
for (const key of order) {
|
|
4006
|
+
grid.push([key === "" ? "(blank)" : key, aggregate(fn, buckets.get(key), counts.get(key))]);
|
|
4007
|
+
}
|
|
4008
|
+
return { grid };
|
|
4009
|
+
}
|
|
4010
|
+
function toA1(row, col) {
|
|
4011
|
+
let n = col;
|
|
4012
|
+
let letters = "";
|
|
4013
|
+
do {
|
|
4014
|
+
letters = String.fromCharCode(65 + n % 26) + letters;
|
|
4015
|
+
n = Math.floor(n / 26) - 1;
|
|
4016
|
+
} while (n >= 0);
|
|
4017
|
+
return `${letters}${row + 1}`;
|
|
4018
|
+
}
|
|
4019
|
+
var RANGE_NOTE_STYLE10 = {
|
|
4020
|
+
fontSize: 12,
|
|
4021
|
+
color: "var(--cs-chrome-muted, #605e5c)",
|
|
4022
|
+
marginBottom: 12
|
|
4023
|
+
};
|
|
4024
|
+
var CHECK_STYLE5 = {
|
|
4025
|
+
display: "flex",
|
|
4026
|
+
alignItems: "center",
|
|
4027
|
+
gap: 6,
|
|
4028
|
+
marginBottom: 12,
|
|
4029
|
+
cursor: "pointer"
|
|
4030
|
+
};
|
|
4031
|
+
var RADIO_ROW_STYLE2 = {
|
|
4032
|
+
display: "flex",
|
|
4033
|
+
alignItems: "center",
|
|
4034
|
+
gap: 6,
|
|
4035
|
+
marginBottom: 6,
|
|
4036
|
+
cursor: "pointer"
|
|
4037
|
+
};
|
|
4038
|
+
function InsertPivotDialog({ api, onClose }) {
|
|
4039
|
+
const source = (0, import_react17.useMemo)(() => readSource(api), [api]);
|
|
4040
|
+
const rangeLabel = (0, import_react17.useMemo)(() => {
|
|
4041
|
+
const r = activeRange11(api);
|
|
4042
|
+
return r?.getA1Notation?.() ?? null;
|
|
4043
|
+
}, [api]);
|
|
4044
|
+
const hasSource = source.length > 0 && (source[0]?.length ?? 0) > 0;
|
|
4045
|
+
const colCount = hasSource ? source[0].length : 0;
|
|
4046
|
+
const [state, setState] = (0, import_react17.useState)({
|
|
4047
|
+
useHeader: true,
|
|
4048
|
+
groupCol: 0,
|
|
4049
|
+
valueCol: colCount > 1 ? 1 : 0,
|
|
4050
|
+
aggFn: "sum",
|
|
4051
|
+
destination: "newSheet",
|
|
4052
|
+
sheetName: "Pivot",
|
|
4053
|
+
anchor: ""
|
|
4054
|
+
});
|
|
4055
|
+
const [error, setError] = (0, import_react17.useState)(null);
|
|
4056
|
+
const update = (key, value) => {
|
|
4057
|
+
setState((prev) => ({ ...prev, [key]: value }));
|
|
4058
|
+
setError(null);
|
|
4059
|
+
};
|
|
4060
|
+
const columnOptions = (0, import_react17.useMemo)(() => {
|
|
4061
|
+
const header = state.useHeader ? source[0] : void 0;
|
|
4062
|
+
return Array.from({ length: colCount }, (_, i) => ({
|
|
4063
|
+
value: i,
|
|
4064
|
+
label: columnLabel(i, header, state.useHeader)
|
|
4065
|
+
}));
|
|
4066
|
+
}, [source, colCount, state.useHeader]);
|
|
4067
|
+
const apply = () => {
|
|
4068
|
+
const pivot = buildPivot(source, state.useHeader, state.groupCol, state.valueCol, state.aggFn);
|
|
4069
|
+
if (!pivot) {
|
|
4070
|
+
setError("The selection has no data rows to summarize.");
|
|
4071
|
+
return;
|
|
4072
|
+
}
|
|
4073
|
+
const wb = api.univer.getActiveWorkbook();
|
|
4074
|
+
if (!wb) {
|
|
4075
|
+
setError("No active workbook.");
|
|
4076
|
+
return;
|
|
4077
|
+
}
|
|
4078
|
+
try {
|
|
4079
|
+
if (state.destination === "newSheet") {
|
|
4080
|
+
const name = state.sheetName.trim() || "Pivot";
|
|
4081
|
+
const rows = Math.max(pivot.grid.length + 2, 10);
|
|
4082
|
+
const sheet = wb.create(name, rows, 4);
|
|
4083
|
+
const target = sheet.getRange(`A1:${toA1(pivot.grid.length - 1, 1)}`);
|
|
4084
|
+
target.setValues(pivot.grid);
|
|
4085
|
+
} else {
|
|
4086
|
+
const anchor = state.anchor.trim().toUpperCase();
|
|
4087
|
+
if (!/^[A-Z]+[0-9]+$/.test(anchor)) {
|
|
4088
|
+
setError("Enter a valid top-left cell, e.g. E1.");
|
|
4089
|
+
return;
|
|
4090
|
+
}
|
|
4091
|
+
const sheet = wb.getActiveSheet();
|
|
4092
|
+
if (!sheet) {
|
|
4093
|
+
setError("No active sheet to write into.");
|
|
4094
|
+
return;
|
|
4095
|
+
}
|
|
4096
|
+
const m = /^([A-Z]+)([0-9]+)$/.exec(anchor);
|
|
4097
|
+
let col = 0;
|
|
4098
|
+
for (const ch of m[1]) col = col * 26 + (ch.charCodeAt(0) - 64);
|
|
4099
|
+
col -= 1;
|
|
4100
|
+
const startRow = Number(m[2]) - 1;
|
|
4101
|
+
const end = toA1(startRow + pivot.grid.length - 1, col + 1);
|
|
4102
|
+
sheet.getRange(`${anchor}:${end}`).setValues(pivot.grid);
|
|
4103
|
+
}
|
|
4104
|
+
} catch (e) {
|
|
4105
|
+
setError(e instanceof Error ? e.message : "Failed to create the pivot table.");
|
|
4106
|
+
return;
|
|
4107
|
+
}
|
|
4108
|
+
onClose();
|
|
4109
|
+
};
|
|
4110
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
4111
|
+
Dialog,
|
|
4112
|
+
{
|
|
4113
|
+
title: "Insert pivot table",
|
|
4114
|
+
onClose,
|
|
4115
|
+
width: 460,
|
|
4116
|
+
"data-testid": "cs-insert-pivot-dialog",
|
|
4117
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
4118
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
|
|
4119
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4120
|
+
"button",
|
|
4121
|
+
{
|
|
4122
|
+
type: "button",
|
|
4123
|
+
style: DIALOG_BTN_PRIMARY_STYLE,
|
|
4124
|
+
"data-testid": "cs-insert-pivot-create",
|
|
4125
|
+
disabled: !hasSource,
|
|
4126
|
+
onClick: apply,
|
|
4127
|
+
children: "Create"
|
|
4128
|
+
}
|
|
4129
|
+
)
|
|
4130
|
+
] }),
|
|
4131
|
+
children: [
|
|
4132
|
+
hasSource ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: RANGE_NOTE_STYLE10, "data-testid": "cs-insert-pivot-source", children: [
|
|
4133
|
+
"Source data ",
|
|
4134
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: rangeLabel ?? "the current selection" }),
|
|
4135
|
+
" (",
|
|
4136
|
+
source.length,
|
|
4137
|
+
" rows \xD7 ",
|
|
4138
|
+
colCount,
|
|
4139
|
+
" columns)"
|
|
4140
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: RANGE_NOTE_STYLE10, "data-testid": "cs-insert-pivot-no-selection", children: "Select the source data range first (including its header row), then reopen this dialog." }),
|
|
4141
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { style: CHECK_STYLE5, "data-testid": "cs-insert-pivot-header-label", children: [
|
|
4142
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4143
|
+
"input",
|
|
4144
|
+
{
|
|
4145
|
+
type: "checkbox",
|
|
4146
|
+
"data-testid": "cs-insert-pivot-header",
|
|
4147
|
+
checked: state.useHeader,
|
|
4148
|
+
onChange: (e) => update("useHeader", e.target.checked),
|
|
4149
|
+
disabled: !hasSource
|
|
4150
|
+
}
|
|
4151
|
+
),
|
|
4152
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "First row is a header" })
|
|
4153
|
+
] }),
|
|
4154
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
4155
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Rows (group by)" }),
|
|
4156
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4157
|
+
"select",
|
|
4158
|
+
{
|
|
4159
|
+
style: DIALOG_INPUT_STYLE,
|
|
4160
|
+
"data-testid": "cs-insert-pivot-group-col",
|
|
4161
|
+
value: state.groupCol,
|
|
4162
|
+
disabled: !hasSource,
|
|
4163
|
+
onChange: (e) => update("groupCol", Number(e.target.value)),
|
|
4164
|
+
children: columnOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
|
|
4165
|
+
}
|
|
4166
|
+
)
|
|
4167
|
+
] }),
|
|
4168
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
4169
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Values" }),
|
|
4170
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4171
|
+
"select",
|
|
4172
|
+
{
|
|
4173
|
+
style: DIALOG_INPUT_STYLE,
|
|
4174
|
+
"data-testid": "cs-insert-pivot-value-col",
|
|
4175
|
+
value: state.valueCol,
|
|
4176
|
+
disabled: !hasSource,
|
|
4177
|
+
onChange: (e) => update("valueCol", Number(e.target.value)),
|
|
4178
|
+
children: columnOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
|
|
4179
|
+
}
|
|
4180
|
+
)
|
|
4181
|
+
] }),
|
|
4182
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
4183
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Summarize by" }),
|
|
4184
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4185
|
+
"select",
|
|
4186
|
+
{
|
|
4187
|
+
style: DIALOG_INPUT_STYLE,
|
|
4188
|
+
"data-testid": "cs-insert-pivot-agg",
|
|
4189
|
+
value: state.aggFn,
|
|
4190
|
+
disabled: !hasSource,
|
|
4191
|
+
onChange: (e) => update("aggFn", e.target.value),
|
|
4192
|
+
children: AGG_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
|
|
4193
|
+
}
|
|
4194
|
+
)
|
|
4195
|
+
] }),
|
|
4196
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: DIALOG_FIELD_STYLE, children: [
|
|
4197
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Destination" }),
|
|
4198
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { style: RADIO_ROW_STYLE2, children: [
|
|
4199
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4200
|
+
"input",
|
|
4201
|
+
{
|
|
4202
|
+
type: "radio",
|
|
4203
|
+
name: "cs-insert-pivot-destination",
|
|
4204
|
+
"data-testid": "cs-insert-pivot-dest-new",
|
|
4205
|
+
checked: state.destination === "newSheet",
|
|
4206
|
+
onChange: () => update("destination", "newSheet")
|
|
4207
|
+
}
|
|
4208
|
+
),
|
|
4209
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "New sheet" })
|
|
4210
|
+
] }),
|
|
4211
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { style: RADIO_ROW_STYLE2, children: [
|
|
4212
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1169
4213
|
"input",
|
|
1170
4214
|
{
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
onChange: (
|
|
4215
|
+
type: "radio",
|
|
4216
|
+
name: "cs-insert-pivot-destination",
|
|
4217
|
+
"data-testid": "cs-insert-pivot-dest-existing",
|
|
4218
|
+
checked: state.destination === "existing",
|
|
4219
|
+
onChange: () => update("destination", "existing")
|
|
1176
4220
|
}
|
|
1177
|
-
)
|
|
4221
|
+
),
|
|
4222
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Existing sheet (choose top-left cell)" })
|
|
1178
4223
|
] })
|
|
1179
|
-
] })
|
|
4224
|
+
] }),
|
|
4225
|
+
state.destination === "newSheet" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
4226
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "New sheet name" }),
|
|
4227
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4228
|
+
"input",
|
|
4229
|
+
{
|
|
4230
|
+
style: DIALOG_INPUT_STYLE,
|
|
4231
|
+
"data-testid": "cs-insert-pivot-sheet-name",
|
|
4232
|
+
value: state.sheetName,
|
|
4233
|
+
placeholder: "Pivot",
|
|
4234
|
+
onChange: (e) => update("sheetName", e.target.value)
|
|
4235
|
+
}
|
|
4236
|
+
)
|
|
4237
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { style: DIALOG_FIELD_STYLE, children: [
|
|
4238
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: DIALOG_LABEL_STYLE, children: "Top-left cell (on the active sheet)" }),
|
|
4239
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4240
|
+
"input",
|
|
4241
|
+
{
|
|
4242
|
+
style: DIALOG_INPUT_STYLE,
|
|
4243
|
+
"data-testid": "cs-insert-pivot-anchor",
|
|
4244
|
+
value: state.anchor,
|
|
4245
|
+
placeholder: "e.g. E1",
|
|
4246
|
+
onChange: (e) => update("anchor", e.target.value)
|
|
4247
|
+
}
|
|
4248
|
+
)
|
|
4249
|
+
] }),
|
|
4250
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4251
|
+
"div",
|
|
4252
|
+
{
|
|
4253
|
+
style: {
|
|
4254
|
+
...RANGE_NOTE_STYLE10,
|
|
4255
|
+
color: "var(--cs-chrome-danger, #b3261e)",
|
|
4256
|
+
marginBottom: 0
|
|
4257
|
+
},
|
|
4258
|
+
"data-testid": "cs-insert-pivot-error",
|
|
4259
|
+
role: "alert",
|
|
4260
|
+
children: error
|
|
4261
|
+
}
|
|
4262
|
+
)
|
|
1180
4263
|
]
|
|
1181
4264
|
}
|
|
1182
4265
|
);
|
|
1183
4266
|
}
|
|
1184
4267
|
|
|
1185
4268
|
// src/chrome/dialog-context.tsx
|
|
1186
|
-
var
|
|
4269
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1187
4270
|
var BUILT_IN_DIALOGS = {
|
|
1188
|
-
"format-cells": FormatCellsDialog
|
|
4271
|
+
"format-cells": FormatCellsDialog,
|
|
4272
|
+
"data-validation": DataValidationDialog,
|
|
4273
|
+
"conditional-formatting": ConditionalFormattingDialog,
|
|
4274
|
+
"custom-sort": CustomSortDialog,
|
|
4275
|
+
"paste-special": PasteSpecialDialog,
|
|
4276
|
+
"insert-function": InsertFunctionDialog,
|
|
4277
|
+
"name-manager": NameManagerDialog,
|
|
4278
|
+
"insert-cells": InsertCellsDialog,
|
|
4279
|
+
"delete-cells": DeleteCellsDialog,
|
|
4280
|
+
"goal-seek": GoalSeekDialog,
|
|
4281
|
+
"insert-chart": InsertChartDialog,
|
|
4282
|
+
"insert-sparkline": InsertSparklineDialog,
|
|
4283
|
+
"insert-pivot": InsertPivotDialog
|
|
1189
4284
|
};
|
|
1190
4285
|
function hasBuiltInDialog(kind) {
|
|
1191
4286
|
return kind in BUILT_IN_DIALOGS || kind === "find-replace";
|
|
1192
4287
|
}
|
|
1193
|
-
var DialogContext = (0,
|
|
4288
|
+
var DialogContext = (0, import_react18.createContext)(null);
|
|
1194
4289
|
function useDialogs() {
|
|
1195
|
-
const ctx = (0,
|
|
4290
|
+
const ctx = (0, import_react18.useContext)(DialogContext);
|
|
1196
4291
|
if (!ctx) {
|
|
1197
4292
|
return {
|
|
1198
4293
|
openDialog: () => {
|
|
@@ -1212,10 +4307,10 @@ function DialogProvider({
|
|
|
1212
4307
|
onOpenFindReplace,
|
|
1213
4308
|
children
|
|
1214
4309
|
}) {
|
|
1215
|
-
const [active, setActive] = (0,
|
|
4310
|
+
const [active, setActive] = (0, import_react18.useState)(null);
|
|
1216
4311
|
const overrides = extensions?.dialogs;
|
|
1217
|
-
const hostOwned = (0,
|
|
1218
|
-
const openDialog = (0,
|
|
4312
|
+
const hostOwned = (0, import_react18.useMemo)(() => new Set(hostOwnedDialogs ?? []), [hostOwnedDialogs]);
|
|
4313
|
+
const openDialog = (0, import_react18.useCallback)(
|
|
1219
4314
|
(kind, context) => {
|
|
1220
4315
|
if (overrides?.[kind]) {
|
|
1221
4316
|
setActive({ kind, context });
|
|
@@ -1240,22 +4335,22 @@ function DialogProvider({
|
|
|
1240
4335
|
},
|
|
1241
4336
|
[overrides, onDialogRequest, hostOwned, onOpenFindReplace]
|
|
1242
4337
|
);
|
|
1243
|
-
const closeDialog = (0,
|
|
1244
|
-
const canOpen = (0,
|
|
4338
|
+
const closeDialog = (0, import_react18.useCallback)(() => setActive(null), []);
|
|
4339
|
+
const canOpen = (0, import_react18.useCallback)(
|
|
1245
4340
|
(kind) => !!overrides?.[kind] || hasBuiltInDialog(kind) || !!onDialogRequest || hostOwned.has(kind),
|
|
1246
4341
|
[overrides, onDialogRequest, hostOwned]
|
|
1247
4342
|
);
|
|
1248
|
-
const controllerCanOpen = (0,
|
|
4343
|
+
const controllerCanOpen = (0, import_react18.useCallback)(
|
|
1249
4344
|
(kind) => kind === "find-replace" ? !!onOpenFindReplace || canOpen(kind) : canOpen(kind),
|
|
1250
4345
|
[canOpen, onOpenFindReplace]
|
|
1251
4346
|
);
|
|
1252
|
-
const controller = (0,
|
|
4347
|
+
const controller = (0, import_react18.useMemo)(
|
|
1253
4348
|
() => ({ openDialog, closeDialog, canOpen: controllerCanOpen }),
|
|
1254
4349
|
[openDialog, closeDialog, controllerCanOpen]
|
|
1255
4350
|
);
|
|
1256
|
-
return /* @__PURE__ */ (0,
|
|
4351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DialogContext.Provider, { value: controller, children: [
|
|
1257
4352
|
children,
|
|
1258
|
-
/* @__PURE__ */ (0,
|
|
4353
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogHost, { api, active, overrides, onClose: closeDialog })
|
|
1259
4354
|
] });
|
|
1260
4355
|
}
|
|
1261
4356
|
function DialogHost({ api, active, overrides, onClose }) {
|
|
@@ -1263,11 +4358,11 @@ function DialogHost({ api, active, overrides, onClose }) {
|
|
|
1263
4358
|
if (active.kind === "find-replace") return null;
|
|
1264
4359
|
const Component = overrides?.[active.kind] ?? BUILT_IN_DIALOGS[active.kind];
|
|
1265
4360
|
if (!Component) return null;
|
|
1266
|
-
return /* @__PURE__ */ (0,
|
|
4361
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Component, { api, onClose, context: active.context });
|
|
1267
4362
|
}
|
|
1268
4363
|
|
|
1269
4364
|
// src/chrome/Toolbar.tsx
|
|
1270
|
-
var
|
|
4365
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1271
4366
|
var NO_STYLE = {
|
|
1272
4367
|
bold: false,
|
|
1273
4368
|
italic: false,
|
|
@@ -1601,16 +4696,16 @@ function isActive(id, s) {
|
|
|
1601
4696
|
}
|
|
1602
4697
|
function Toolbar({ api, features, extensions }) {
|
|
1603
4698
|
const dialogs = useDialogs();
|
|
1604
|
-
const [active, setActive] = (0,
|
|
1605
|
-
(0,
|
|
4699
|
+
const [active, setActive] = (0, import_react19.useState)(NO_STYLE);
|
|
4700
|
+
(0, import_react19.useEffect)(() => {
|
|
1606
4701
|
ensureChromeFonts();
|
|
1607
4702
|
}, []);
|
|
1608
|
-
(0,
|
|
4703
|
+
(0, import_react19.useEffect)(() => {
|
|
1609
4704
|
if (!api) return;
|
|
1610
4705
|
const refresh = () => setActive(readActiveStyle2(api));
|
|
1611
4706
|
refresh();
|
|
1612
4707
|
const injector = api.univer._injector;
|
|
1613
|
-
const cmd = injector?.get(
|
|
4708
|
+
const cmd = injector?.get(import_core4.ICommandService);
|
|
1614
4709
|
const sub = cmd?.onCommandExecuted(() => refresh());
|
|
1615
4710
|
return () => sub?.dispose();
|
|
1616
4711
|
}, [api]);
|
|
@@ -1638,7 +4733,7 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1638
4733
|
const renderActionButton = (a) => {
|
|
1639
4734
|
const on = isActive(a.id, active);
|
|
1640
4735
|
const baseBg = on ? "var(--cs-chrome-active, #e6f3f7)" : "transparent";
|
|
1641
|
-
return /* @__PURE__ */ (0,
|
|
4736
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1642
4737
|
"button",
|
|
1643
4738
|
{
|
|
1644
4739
|
type: "button",
|
|
@@ -1664,12 +4759,12 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1664
4759
|
onMouseLeave: (e) => {
|
|
1665
4760
|
e.currentTarget.style.background = baseBg;
|
|
1666
4761
|
},
|
|
1667
|
-
children: /* @__PURE__ */ (0,
|
|
4762
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { name: a.icon, size: 20 })
|
|
1668
4763
|
},
|
|
1669
4764
|
a.id
|
|
1670
4765
|
);
|
|
1671
4766
|
};
|
|
1672
|
-
const renderIconButton = (id, label, icon, onPress, testid) => /* @__PURE__ */ (0,
|
|
4767
|
+
const renderIconButton = (id, label, icon, onPress, testid) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1673
4768
|
"button",
|
|
1674
4769
|
{
|
|
1675
4770
|
type: "button",
|
|
@@ -1689,7 +4784,7 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1689
4784
|
onMouseLeave: (e) => {
|
|
1690
4785
|
e.currentTarget.style.background = "transparent";
|
|
1691
4786
|
},
|
|
1692
|
-
children: /* @__PURE__ */ (0,
|
|
4787
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { name: icon, size: 20 })
|
|
1693
4788
|
},
|
|
1694
4789
|
id
|
|
1695
4790
|
);
|
|
@@ -1700,8 +4795,8 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1700
4795
|
if (visible.length === 0) return null;
|
|
1701
4796
|
const showDivider = firstGroupRendered;
|
|
1702
4797
|
firstGroupRendered = true;
|
|
1703
|
-
return /* @__PURE__ */ (0,
|
|
1704
|
-
showDivider && /* @__PURE__ */ (0,
|
|
4798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: { display: "inline-flex", alignItems: "center" }, children: [
|
|
4799
|
+
showDivider && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
|
|
1705
4800
|
visible.map(renderActionButton)
|
|
1706
4801
|
] }, gi);
|
|
1707
4802
|
});
|
|
@@ -1722,9 +4817,9 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1722
4817
|
if (e.command) void api.executeCommand(e.command, e.commandParams);
|
|
1723
4818
|
else e.onClick?.(api);
|
|
1724
4819
|
};
|
|
1725
|
-
return /* @__PURE__ */ (0,
|
|
1726
|
-
showFont && /* @__PURE__ */ (0,
|
|
1727
|
-
/* @__PURE__ */ (0,
|
|
4820
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: BAR_STYLE, "data-testid": "casual-sheets-toolbar", role: "toolbar", "aria-label": "Editor", children: [
|
|
4821
|
+
showFont && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
4822
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1728
4823
|
"select",
|
|
1729
4824
|
{
|
|
1730
4825
|
"aria-label": "Font family",
|
|
@@ -1733,10 +4828,10 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1733
4828
|
value: familyValue,
|
|
1734
4829
|
disabled: !api,
|
|
1735
4830
|
onChange: (e) => dispatch("sheet.command.set-range-font-family", { value: e.target.value }),
|
|
1736
|
-
children: familyOptions.map((f) => /* @__PURE__ */ (0,
|
|
4831
|
+
children: familyOptions.map((f) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: f, children: f }, f))
|
|
1737
4832
|
}
|
|
1738
4833
|
),
|
|
1739
|
-
/* @__PURE__ */ (0,
|
|
4834
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1740
4835
|
"select",
|
|
1741
4836
|
{
|
|
1742
4837
|
"aria-label": "Font size",
|
|
@@ -1745,7 +4840,7 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1745
4840
|
value: sizeValue,
|
|
1746
4841
|
disabled: !api,
|
|
1747
4842
|
onChange: (e) => applyFontSize(Number(e.target.value)),
|
|
1748
|
-
children: sizeOptions.map((s) => /* @__PURE__ */ (0,
|
|
4843
|
+
children: sizeOptions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: s, children: s }, s))
|
|
1749
4844
|
}
|
|
1750
4845
|
),
|
|
1751
4846
|
renderIconButton(
|
|
@@ -1762,15 +4857,15 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1762
4857
|
() => adjustFontSize(-1),
|
|
1763
4858
|
"cs-font-size-down"
|
|
1764
4859
|
),
|
|
1765
|
-
/* @__PURE__ */ (0,
|
|
4860
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: DIVIDER_STYLE, "aria-hidden": true })
|
|
1766
4861
|
] }),
|
|
1767
4862
|
groupNodes,
|
|
1768
|
-
(showColor || showBorders) && /* @__PURE__ */ (0,
|
|
1769
|
-
showColor && /* @__PURE__ */ (0,
|
|
1770
|
-
showBorders && /* @__PURE__ */ (0,
|
|
1771
|
-
showNumberDropdown && /* @__PURE__ */ (0,
|
|
1772
|
-
/* @__PURE__ */ (0,
|
|
1773
|
-
/* @__PURE__ */ (0,
|
|
4863
|
+
(showColor || showBorders) && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
|
|
4864
|
+
showColor && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ColorPicker, { api }),
|
|
4865
|
+
showBorders && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(BordersPicker, { api }),
|
|
4866
|
+
showNumberDropdown && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
4867
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
|
|
4868
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1774
4869
|
"select",
|
|
1775
4870
|
{
|
|
1776
4871
|
"aria-label": "Number format",
|
|
@@ -1779,16 +4874,16 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1779
4874
|
value: numberFormatValue,
|
|
1780
4875
|
disabled: !api,
|
|
1781
4876
|
onChange: (e) => applyNumberFormat(NUMBER_FORMAT_PATTERNS2[e.target.value]),
|
|
1782
|
-
children: NUMBER_FORMAT_OPTIONS2.map((o) => /* @__PURE__ */ (0,
|
|
4877
|
+
children: NUMBER_FORMAT_OPTIONS2.map((o) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { value: o.value, children: o.label }, o.value))
|
|
1783
4878
|
}
|
|
1784
4879
|
)
|
|
1785
4880
|
] }),
|
|
1786
|
-
showAutoSum && /* @__PURE__ */ (0,
|
|
1787
|
-
/* @__PURE__ */ (0,
|
|
1788
|
-
/* @__PURE__ */ (0,
|
|
4881
|
+
showAutoSum && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
4882
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
|
|
4883
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AutoSumPicker, { api })
|
|
1789
4884
|
] }),
|
|
1790
|
-
showDialogGroup && /* @__PURE__ */ (0,
|
|
1791
|
-
/* @__PURE__ */ (0,
|
|
4885
|
+
showDialogGroup && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
4886
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
|
|
1792
4887
|
showFormatCells && renderIconButton(
|
|
1793
4888
|
"format-cells",
|
|
1794
4889
|
"Format Cells\u2026",
|
|
@@ -1811,8 +4906,8 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1811
4906
|
"cs-pivot-table"
|
|
1812
4907
|
)
|
|
1813
4908
|
] }),
|
|
1814
|
-
toolbarExt.length > 0 && /* @__PURE__ */ (0,
|
|
1815
|
-
/* @__PURE__ */ (0,
|
|
4909
|
+
toolbarExt.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
4910
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
|
|
1816
4911
|
toolbarExt.map(
|
|
1817
4912
|
(e) => renderIconButton(e.id, e.label, e.icon, () => runExt(e), `cs-ext-${e.id}`)
|
|
1818
4913
|
)
|
|
@@ -1821,13 +4916,13 @@ function Toolbar({ api, features, extensions }) {
|
|
|
1821
4916
|
}
|
|
1822
4917
|
|
|
1823
4918
|
// src/chrome/FormulaBar.tsx
|
|
1824
|
-
var
|
|
1825
|
-
var
|
|
4919
|
+
var import_react21 = require("react");
|
|
4920
|
+
var import_core6 = require("@univerjs/core");
|
|
1826
4921
|
|
|
1827
4922
|
// src/chrome/NameBox.tsx
|
|
1828
|
-
var
|
|
1829
|
-
var
|
|
1830
|
-
var
|
|
4923
|
+
var import_react20 = require("react");
|
|
4924
|
+
var import_core5 = require("@univerjs/core");
|
|
4925
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1831
4926
|
function readDefinedNames(api) {
|
|
1832
4927
|
if (!api) return [];
|
|
1833
4928
|
try {
|
|
@@ -1937,15 +5032,15 @@ var ITEM_REF_STYLE = {
|
|
|
1937
5032
|
flex: "0 0 auto"
|
|
1938
5033
|
};
|
|
1939
5034
|
function NameBox({ api }) {
|
|
1940
|
-
const [ref, setRef] = (0,
|
|
1941
|
-
const [draft, setDraft] = (0,
|
|
1942
|
-
const draftRef = (0,
|
|
5035
|
+
const [ref, setRef] = (0, import_react20.useState)("");
|
|
5036
|
+
const [draft, setDraft] = (0, import_react20.useState)(null);
|
|
5037
|
+
const draftRef = (0, import_react20.useRef)(null);
|
|
1943
5038
|
draftRef.current = draft;
|
|
1944
|
-
const inputRef = (0,
|
|
1945
|
-
const [open, setOpen] = (0,
|
|
1946
|
-
const [names, setNames] = (0,
|
|
1947
|
-
const rootRef = (0,
|
|
1948
|
-
(0,
|
|
5039
|
+
const inputRef = (0, import_react20.useRef)(null);
|
|
5040
|
+
const [open, setOpen] = (0, import_react20.useState)(false);
|
|
5041
|
+
const [names, setNames] = (0, import_react20.useState)([]);
|
|
5042
|
+
const rootRef = (0, import_react20.useRef)(null);
|
|
5043
|
+
(0, import_react20.useEffect)(() => {
|
|
1949
5044
|
if (!api) return;
|
|
1950
5045
|
const refresh = () => {
|
|
1951
5046
|
if (draftRef.current !== null) return;
|
|
@@ -1953,11 +5048,11 @@ function NameBox({ api }) {
|
|
|
1953
5048
|
};
|
|
1954
5049
|
refresh();
|
|
1955
5050
|
const injector = api.univer._injector;
|
|
1956
|
-
const cmd = injector?.get(
|
|
5051
|
+
const cmd = injector?.get(import_core5.ICommandService);
|
|
1957
5052
|
const sub = cmd?.onCommandExecuted(() => refresh());
|
|
1958
5053
|
return () => sub?.dispose();
|
|
1959
5054
|
}, [api]);
|
|
1960
|
-
(0,
|
|
5055
|
+
(0, import_react20.useEffect)(() => {
|
|
1961
5056
|
if (!open) return;
|
|
1962
5057
|
const onPointerDown = (e) => {
|
|
1963
5058
|
if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
|
|
@@ -2018,8 +5113,8 @@ function NameBox({ api }) {
|
|
|
2018
5113
|
}
|
|
2019
5114
|
};
|
|
2020
5115
|
const shown = draft ?? ref;
|
|
2021
|
-
return /* @__PURE__ */ (0,
|
|
2022
|
-
/* @__PURE__ */ (0,
|
|
5116
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { ref: rootRef, style: ROOT_STYLE, children: [
|
|
5117
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2023
5118
|
"input",
|
|
2024
5119
|
{
|
|
2025
5120
|
ref: inputRef,
|
|
@@ -2041,7 +5136,7 @@ function NameBox({ api }) {
|
|
|
2041
5136
|
}
|
|
2042
5137
|
}
|
|
2043
5138
|
),
|
|
2044
|
-
/* @__PURE__ */ (0,
|
|
5139
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2045
5140
|
"button",
|
|
2046
5141
|
{
|
|
2047
5142
|
type: "button",
|
|
@@ -2060,10 +5155,10 @@ function NameBox({ api }) {
|
|
|
2060
5155
|
e.preventDefault();
|
|
2061
5156
|
toggleDropdown();
|
|
2062
5157
|
},
|
|
2063
|
-
children: /* @__PURE__ */ (0,
|
|
5158
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Icon, { name: "expand_more", size: 18 })
|
|
2064
5159
|
}
|
|
2065
5160
|
),
|
|
2066
|
-
open && /* @__PURE__ */ (0,
|
|
5161
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: MENU_STYLE, role: "menu", "data-testid": "cs-namebox-menu", children: names.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: MENU_EMPTY_STYLE, children: "No names" }) : names.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2067
5162
|
"button",
|
|
2068
5163
|
{
|
|
2069
5164
|
type: "button",
|
|
@@ -2082,8 +5177,8 @@ function NameBox({ api }) {
|
|
|
2082
5177
|
e.currentTarget.style.background = "transparent";
|
|
2083
5178
|
},
|
|
2084
5179
|
children: [
|
|
2085
|
-
/* @__PURE__ */ (0,
|
|
2086
|
-
entry.ref && /* @__PURE__ */ (0,
|
|
5180
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: entry.name }),
|
|
5181
|
+
entry.ref && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: ITEM_REF_STYLE, children: entry.ref })
|
|
2087
5182
|
]
|
|
2088
5183
|
},
|
|
2089
5184
|
entry.name
|
|
@@ -2092,8 +5187,8 @@ function NameBox({ api }) {
|
|
|
2092
5187
|
}
|
|
2093
5188
|
|
|
2094
5189
|
// src/chrome/FormulaBar.tsx
|
|
2095
|
-
var
|
|
2096
|
-
var
|
|
5190
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
5191
|
+
var FUNCTIONS2 = [
|
|
2097
5192
|
"ABS",
|
|
2098
5193
|
"AND",
|
|
2099
5194
|
"AVERAGE",
|
|
@@ -2197,7 +5292,7 @@ function suggestFor(draft) {
|
|
|
2197
5292
|
const m = TOKEN_RE.exec(draft);
|
|
2198
5293
|
if (!m) return [];
|
|
2199
5294
|
const prefix = m[1].toUpperCase();
|
|
2200
|
-
return
|
|
5295
|
+
return FUNCTIONS2.filter((f) => f.startsWith(prefix) && f !== prefix).slice(0, 8);
|
|
2201
5296
|
}
|
|
2202
5297
|
function colToLetters2(col) {
|
|
2203
5298
|
let s = "";
|
|
@@ -2280,13 +5375,13 @@ var AC_ITEM_STYLE = {
|
|
|
2280
5375
|
cursor: "pointer"
|
|
2281
5376
|
};
|
|
2282
5377
|
function FormulaBar({ api }) {
|
|
2283
|
-
const [cell, setCell] = (0,
|
|
2284
|
-
const [draft, setDraft] = (0,
|
|
2285
|
-
const draftRef = (0,
|
|
5378
|
+
const [cell, setCell] = (0, import_react21.useState)(null);
|
|
5379
|
+
const [draft, setDraft] = (0, import_react21.useState)(null);
|
|
5380
|
+
const draftRef = (0, import_react21.useRef)(null);
|
|
2286
5381
|
draftRef.current = draft;
|
|
2287
|
-
const [acIdx, setAcIdx] = (0,
|
|
2288
|
-
const [acDismissed, setAcDismissed] = (0,
|
|
2289
|
-
(0,
|
|
5382
|
+
const [acIdx, setAcIdx] = (0, import_react21.useState)(0);
|
|
5383
|
+
const [acDismissed, setAcDismissed] = (0, import_react21.useState)(false);
|
|
5384
|
+
(0, import_react21.useEffect)(() => {
|
|
2290
5385
|
if (!api) return;
|
|
2291
5386
|
const refresh = () => {
|
|
2292
5387
|
if (draftRef.current !== null) return;
|
|
@@ -2294,11 +5389,11 @@ function FormulaBar({ api }) {
|
|
|
2294
5389
|
};
|
|
2295
5390
|
refresh();
|
|
2296
5391
|
const injector = api.univer._injector;
|
|
2297
|
-
const cmd = injector?.get(
|
|
5392
|
+
const cmd = injector?.get(import_core6.ICommandService);
|
|
2298
5393
|
const sub = cmd?.onCommandExecuted(() => refresh());
|
|
2299
5394
|
return () => sub?.dispose();
|
|
2300
5395
|
}, [api]);
|
|
2301
|
-
const suggestions = (0,
|
|
5396
|
+
const suggestions = (0, import_react21.useMemo)(() => suggestFor(draft), [draft]);
|
|
2302
5397
|
const acOpen = !acDismissed && suggestions.length > 0;
|
|
2303
5398
|
const commit = (text) => {
|
|
2304
5399
|
setDraft(null);
|
|
@@ -2356,11 +5451,11 @@ function FormulaBar({ api }) {
|
|
|
2356
5451
|
}
|
|
2357
5452
|
};
|
|
2358
5453
|
const shown = draft ?? cell?.text ?? "";
|
|
2359
|
-
return /* @__PURE__ */ (0,
|
|
2360
|
-
/* @__PURE__ */ (0,
|
|
2361
|
-
/* @__PURE__ */ (0,
|
|
2362
|
-
/* @__PURE__ */ (0,
|
|
2363
|
-
/* @__PURE__ */ (0,
|
|
5454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: BAR_STYLE2, "data-testid": "casual-sheets-formula-bar", children: [
|
|
5455
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(NameBox, { api }),
|
|
5456
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: FX_STYLE, "aria-hidden": true, children: "fx" }),
|
|
5457
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: INPUT_WRAP_STYLE, children: [
|
|
5458
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2364
5459
|
"input",
|
|
2365
5460
|
{
|
|
2366
5461
|
type: "text",
|
|
@@ -2376,7 +5471,7 @@ function FormulaBar({ api }) {
|
|
|
2376
5471
|
disabled: !api
|
|
2377
5472
|
}
|
|
2378
5473
|
),
|
|
2379
|
-
acOpen && /* @__PURE__ */ (0,
|
|
5474
|
+
acOpen && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: AC_STYLE, "data-testid": "cs-formula-suggestions", role: "listbox", children: suggestions.map((fn, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2380
5475
|
"button",
|
|
2381
5476
|
{
|
|
2382
5477
|
type: "button",
|
|
@@ -2402,9 +5497,9 @@ function FormulaBar({ api }) {
|
|
|
2402
5497
|
}
|
|
2403
5498
|
|
|
2404
5499
|
// src/chrome/StatusBar.tsx
|
|
2405
|
-
var
|
|
2406
|
-
var
|
|
2407
|
-
var
|
|
5500
|
+
var import_react22 = require("react");
|
|
5501
|
+
var import_core7 = require("@univerjs/core");
|
|
5502
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2408
5503
|
function readStats(api) {
|
|
2409
5504
|
const sel = api.getSelection();
|
|
2410
5505
|
const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
|
|
@@ -2487,9 +5582,9 @@ var ZOOM_LEVEL_STYLE = {
|
|
|
2487
5582
|
textAlign: "center"
|
|
2488
5583
|
};
|
|
2489
5584
|
function StatusBar({ api }) {
|
|
2490
|
-
const [stats, setStats] = (0,
|
|
2491
|
-
const [zoom, setZoom] = (0,
|
|
2492
|
-
(0,
|
|
5585
|
+
const [stats, setStats] = (0, import_react22.useState)(null);
|
|
5586
|
+
const [zoom, setZoom] = (0, import_react22.useState)(1);
|
|
5587
|
+
(0, import_react22.useEffect)(() => {
|
|
2493
5588
|
if (!api) return;
|
|
2494
5589
|
const refresh = () => {
|
|
2495
5590
|
setStats(readStats(api));
|
|
@@ -2497,7 +5592,7 @@ function StatusBar({ api }) {
|
|
|
2497
5592
|
};
|
|
2498
5593
|
refresh();
|
|
2499
5594
|
const injector = api.univer._injector;
|
|
2500
|
-
const cmd = injector?.get(
|
|
5595
|
+
const cmd = injector?.get(import_core7.ICommandService);
|
|
2501
5596
|
const sub = cmd?.onCommandExecuted(() => refresh());
|
|
2502
5597
|
return () => sub?.dispose();
|
|
2503
5598
|
}, [api]);
|
|
@@ -2515,37 +5610,37 @@ function StatusBar({ api }) {
|
|
|
2515
5610
|
};
|
|
2516
5611
|
const zoomBy = (delta) => setZoomRatio(Math.round((zoom + delta) * 100) / 100);
|
|
2517
5612
|
const resetZoom = () => setZoomRatio(1);
|
|
2518
|
-
return /* @__PURE__ */ (0,
|
|
2519
|
-
stats && /* @__PURE__ */ (0,
|
|
2520
|
-
stats.numCount > 0 && /* @__PURE__ */ (0,
|
|
5613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: BAR_STYLE3, "data-testid": "casual-sheets-status-bar", children: [
|
|
5614
|
+
stats && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
5615
|
+
stats.numCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { "data-stat": "average", children: [
|
|
2521
5616
|
"Average: ",
|
|
2522
5617
|
fmt(stats.avg)
|
|
2523
5618
|
] }),
|
|
2524
|
-
/* @__PURE__ */ (0,
|
|
5619
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { "data-stat": "count", children: [
|
|
2525
5620
|
"Count: ",
|
|
2526
5621
|
stats.count
|
|
2527
5622
|
] }),
|
|
2528
|
-
stats.numCount > 0 && /* @__PURE__ */ (0,
|
|
2529
|
-
/* @__PURE__ */ (0,
|
|
5623
|
+
stats.numCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
5624
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { "data-stat": "num-count", children: [
|
|
2530
5625
|
"Numerical Count: ",
|
|
2531
5626
|
stats.numCount
|
|
2532
5627
|
] }),
|
|
2533
|
-
/* @__PURE__ */ (0,
|
|
5628
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { "data-stat": "min", children: [
|
|
2534
5629
|
"Min: ",
|
|
2535
5630
|
fmt(stats.min)
|
|
2536
5631
|
] }),
|
|
2537
|
-
/* @__PURE__ */ (0,
|
|
5632
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { "data-stat": "max", children: [
|
|
2538
5633
|
"Max: ",
|
|
2539
5634
|
fmt(stats.max)
|
|
2540
5635
|
] }),
|
|
2541
|
-
/* @__PURE__ */ (0,
|
|
5636
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { "data-stat": "sum", children: [
|
|
2542
5637
|
"Sum: ",
|
|
2543
5638
|
fmt(stats.sum)
|
|
2544
5639
|
] })
|
|
2545
5640
|
] })
|
|
2546
5641
|
] }),
|
|
2547
|
-
/* @__PURE__ */ (0,
|
|
2548
|
-
/* @__PURE__ */ (0,
|
|
5642
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { style: ZOOM_GROUP_STYLE, "data-testid": "cs-zoom", children: [
|
|
5643
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2549
5644
|
"button",
|
|
2550
5645
|
{
|
|
2551
5646
|
type: "button",
|
|
@@ -2561,7 +5656,7 @@ function StatusBar({ api }) {
|
|
|
2561
5656
|
children: "\u2212"
|
|
2562
5657
|
}
|
|
2563
5658
|
),
|
|
2564
|
-
/* @__PURE__ */ (0,
|
|
5659
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
2565
5660
|
"button",
|
|
2566
5661
|
{
|
|
2567
5662
|
type: "button",
|
|
@@ -2580,7 +5675,7 @@ function StatusBar({ api }) {
|
|
|
2580
5675
|
]
|
|
2581
5676
|
}
|
|
2582
5677
|
),
|
|
2583
|
-
/* @__PURE__ */ (0,
|
|
5678
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2584
5679
|
"button",
|
|
2585
5680
|
{
|
|
2586
5681
|
type: "button",
|
|
@@ -2601,8 +5696,8 @@ function StatusBar({ api }) {
|
|
|
2601
5696
|
}
|
|
2602
5697
|
|
|
2603
5698
|
// src/chrome/MenuBar.tsx
|
|
2604
|
-
var
|
|
2605
|
-
var
|
|
5699
|
+
var import_react23 = require("react");
|
|
5700
|
+
var import_core8 = require("@univerjs/core");
|
|
2606
5701
|
|
|
2607
5702
|
// src/chrome/openExternal.ts
|
|
2608
5703
|
function openExternal(url) {
|
|
@@ -2813,7 +5908,7 @@ function computeVisibleMenus(menus, features, canOpen, ext) {
|
|
|
2813
5908
|
}
|
|
2814
5909
|
|
|
2815
5910
|
// src/chrome/MenuBar.tsx
|
|
2816
|
-
var
|
|
5911
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2817
5912
|
function fmtShortcut(shortcut) {
|
|
2818
5913
|
const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/i.test(navigator.platform || "");
|
|
2819
5914
|
if (!isMac) return shortcut;
|
|
@@ -2833,14 +5928,14 @@ function fmtShortcut(shortcut) {
|
|
|
2833
5928
|
function fu(api) {
|
|
2834
5929
|
return api.univer;
|
|
2835
5930
|
}
|
|
2836
|
-
function
|
|
5931
|
+
function activeRange12(api) {
|
|
2837
5932
|
return fu(api).getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
|
|
2838
5933
|
}
|
|
2839
|
-
function
|
|
5934
|
+
function activeSheet3(api) {
|
|
2840
5935
|
return fu(api).getActiveWorkbook()?.getActiveSheet() ?? null;
|
|
2841
5936
|
}
|
|
2842
5937
|
function selectionA1(api) {
|
|
2843
|
-
const range =
|
|
5938
|
+
const range = activeRange12(api);
|
|
2844
5939
|
if (!range) return null;
|
|
2845
5940
|
try {
|
|
2846
5941
|
return range.getA1Notation();
|
|
@@ -2855,38 +5950,38 @@ var copy = (api) => void api.executeCommand("univer.command.copy");
|
|
|
2855
5950
|
var paste = (api) => void api.executeCommand("univer.command.paste");
|
|
2856
5951
|
var pasteFormattingOnly = (api) => void api.executeCommand("sheet.command.paste-format");
|
|
2857
5952
|
var insertRowAbove = (api) => {
|
|
2858
|
-
const range =
|
|
2859
|
-
const sheet =
|
|
5953
|
+
const range = activeRange12(api);
|
|
5954
|
+
const sheet = activeSheet3(api);
|
|
2860
5955
|
if (!range || !sheet) return;
|
|
2861
5956
|
sheet.insertRowBefore(range.getRow());
|
|
2862
5957
|
};
|
|
2863
5958
|
var insertRowBelow = (api) => {
|
|
2864
|
-
const range =
|
|
2865
|
-
const sheet =
|
|
5959
|
+
const range = activeRange12(api);
|
|
5960
|
+
const sheet = activeSheet3(api);
|
|
2866
5961
|
if (!range || !sheet) return;
|
|
2867
5962
|
sheet.insertRowAfter(range.getRow() + range.getHeight() - 1);
|
|
2868
5963
|
};
|
|
2869
5964
|
var insertColumnLeft = (api) => {
|
|
2870
|
-
const range =
|
|
2871
|
-
const sheet =
|
|
5965
|
+
const range = activeRange12(api);
|
|
5966
|
+
const sheet = activeSheet3(api);
|
|
2872
5967
|
if (!range || !sheet) return;
|
|
2873
5968
|
sheet.insertColumnBefore(range.getColumn());
|
|
2874
5969
|
};
|
|
2875
5970
|
var insertColumnRight = (api) => {
|
|
2876
|
-
const range =
|
|
2877
|
-
const sheet =
|
|
5971
|
+
const range = activeRange12(api);
|
|
5972
|
+
const sheet = activeSheet3(api);
|
|
2878
5973
|
if (!range || !sheet) return;
|
|
2879
5974
|
sheet.insertColumnAfter(range.getColumn() + range.getWidth() - 1);
|
|
2880
5975
|
};
|
|
2881
5976
|
var deleteSelectedRow = (api) => {
|
|
2882
|
-
const range =
|
|
2883
|
-
const sheet =
|
|
5977
|
+
const range = activeRange12(api);
|
|
5978
|
+
const sheet = activeSheet3(api);
|
|
2884
5979
|
if (!range || !sheet) return;
|
|
2885
5980
|
sheet.deleteRows(range.getRow(), range.getHeight());
|
|
2886
5981
|
};
|
|
2887
5982
|
var deleteSelectedColumn = (api) => {
|
|
2888
|
-
const range =
|
|
2889
|
-
const sheet =
|
|
5983
|
+
const range = activeRange12(api);
|
|
5984
|
+
const sheet = activeSheet3(api);
|
|
2890
5985
|
if (!range || !sheet) return;
|
|
2891
5986
|
sheet.deleteColumns(range.getColumn(), range.getWidth());
|
|
2892
5987
|
};
|
|
@@ -2897,7 +5992,7 @@ var insertImage = (api) => void api.executeCommand("sheet.command.insert-float-i
|
|
|
2897
5992
|
var insertHyperlink = (api) => void api.executeCommand("sheet.operation.insert-hyper-link");
|
|
2898
5993
|
var insertComment = (api) => void api.executeCommand("sheet.operation.show-comment-modal");
|
|
2899
5994
|
var insertTodayDate = (api) => {
|
|
2900
|
-
const range =
|
|
5995
|
+
const range = activeRange12(api);
|
|
2901
5996
|
if (!range) return;
|
|
2902
5997
|
const today = /* @__PURE__ */ new Date();
|
|
2903
5998
|
const pad = (n) => n.toString().padStart(2, "0");
|
|
@@ -2905,7 +6000,7 @@ var insertTodayDate = (api) => {
|
|
|
2905
6000
|
range.setValue({ v });
|
|
2906
6001
|
};
|
|
2907
6002
|
var insertCurrentTime = (api) => {
|
|
2908
|
-
const range =
|
|
6003
|
+
const range = activeRange12(api);
|
|
2909
6004
|
if (!range) return;
|
|
2910
6005
|
const now = /* @__PURE__ */ new Date();
|
|
2911
6006
|
const pad = (n) => n.toString().padStart(2, "0");
|
|
@@ -2914,8 +6009,8 @@ var insertCurrentTime = (api) => {
|
|
|
2914
6009
|
};
|
|
2915
6010
|
var insertTable = (api) => {
|
|
2916
6011
|
void (async () => {
|
|
2917
|
-
const range =
|
|
2918
|
-
const sheet =
|
|
6012
|
+
const range = activeRange12(api);
|
|
6013
|
+
const sheet = activeSheet3(api);
|
|
2919
6014
|
const wb = fu(api).getActiveWorkbook();
|
|
2920
6015
|
if (!range || !sheet || !wb) return;
|
|
2921
6016
|
await ensurePluginByName("table");
|
|
@@ -2932,16 +6027,16 @@ var insertTable = (api) => {
|
|
|
2932
6027
|
})();
|
|
2933
6028
|
};
|
|
2934
6029
|
var autoFitColumns = (api) => {
|
|
2935
|
-
const range =
|
|
2936
|
-
const sheet =
|
|
6030
|
+
const range = activeRange12(api);
|
|
6031
|
+
const sheet = activeSheet3(api);
|
|
2937
6032
|
if (!range || !sheet) return;
|
|
2938
6033
|
const withAutoWidth = sheet;
|
|
2939
6034
|
withAutoWidth.setColumnAutoWidth?.(range.getColumn(), range.getWidth());
|
|
2940
6035
|
};
|
|
2941
6036
|
var AUTO_FIT_ROW_CAP = 500;
|
|
2942
6037
|
var autoFitRows = (api) => {
|
|
2943
|
-
const range =
|
|
2944
|
-
const sheet =
|
|
6038
|
+
const range = activeRange12(api);
|
|
6039
|
+
const sheet = activeSheet3(api);
|
|
2945
6040
|
if (!range || !sheet) return;
|
|
2946
6041
|
const start = range.getRow();
|
|
2947
6042
|
const count = Math.min(range.getHeight(), AUTO_FIT_ROW_CAP);
|
|
@@ -2980,23 +6075,23 @@ var NUM_FORMAT_SHORTCUT = {
|
|
|
2980
6075
|
scientific: "Ctrl+Shift+6"
|
|
2981
6076
|
};
|
|
2982
6077
|
function setNumberFormatByKey(api, key) {
|
|
2983
|
-
const range =
|
|
6078
|
+
const range = activeRange12(api);
|
|
2984
6079
|
range?.setNumberFormat?.(NUMBER_FORMAT_PATTERNS3[key]);
|
|
2985
6080
|
}
|
|
2986
6081
|
var increaseDecimal = (api) => void api.executeCommand("sheet.command.numfmt.add.decimal.command");
|
|
2987
6082
|
var decreaseDecimal = (api) => void api.executeCommand("sheet.command.numfmt.subtract.decimal.command");
|
|
2988
6083
|
var clearFormat = (api) => void api.executeCommand("sheet.command.clear-selection-format");
|
|
2989
6084
|
function applyBorders(api, choice) {
|
|
2990
|
-
const range =
|
|
6085
|
+
const range = activeRange12(api);
|
|
2991
6086
|
if (!range) return;
|
|
2992
|
-
const type = choice === "all" ?
|
|
2993
|
-
const style = choice === "none" ?
|
|
6087
|
+
const type = choice === "all" ? import_core8.BorderType.ALL : choice === "outside" ? import_core8.BorderType.OUTSIDE : import_core8.BorderType.NONE;
|
|
6088
|
+
const style = choice === "none" ? import_core8.BorderStyleTypes.NONE : import_core8.BorderStyleTypes.THIN;
|
|
2994
6089
|
range.setBorder(type, style, "#000000");
|
|
2995
6090
|
}
|
|
2996
6091
|
function rowSpan(api) {
|
|
2997
6092
|
const wb = fu(api).getActiveWorkbook();
|
|
2998
|
-
const sheet =
|
|
2999
|
-
const range =
|
|
6093
|
+
const sheet = activeSheet3(api);
|
|
6094
|
+
const range = activeRange12(api);
|
|
3000
6095
|
if (!wb || !sheet || !range) return null;
|
|
3001
6096
|
const startRow = range.getRow();
|
|
3002
6097
|
const endRow = startRow + range.getHeight() - 1;
|
|
@@ -3005,8 +6100,8 @@ function rowSpan(api) {
|
|
|
3005
6100
|
}
|
|
3006
6101
|
function colSpan(api) {
|
|
3007
6102
|
const wb = fu(api).getActiveWorkbook();
|
|
3008
|
-
const sheet =
|
|
3009
|
-
const range =
|
|
6103
|
+
const sheet = activeSheet3(api);
|
|
6104
|
+
const range = activeRange12(api);
|
|
3010
6105
|
if (!wb || !sheet || !range) return null;
|
|
3011
6106
|
const startColumn = range.getColumn();
|
|
3012
6107
|
const endColumn = startColumn + range.getWidth() - 1;
|
|
@@ -3082,16 +6177,16 @@ var unhideSelectedColumns = (api) => {
|
|
|
3082
6177
|
});
|
|
3083
6178
|
};
|
|
3084
6179
|
var freezeFirstRow = (api) => {
|
|
3085
|
-
|
|
6180
|
+
activeSheet3(api)?.setFrozenRows(1);
|
|
3086
6181
|
};
|
|
3087
6182
|
var freezeFirstColumn = (api) => {
|
|
3088
|
-
|
|
6183
|
+
activeSheet3(api)?.setFrozenColumns(1);
|
|
3089
6184
|
};
|
|
3090
6185
|
var freezeAtSelection = (api) => void api.executeCommand("sheet.command.set-selection-frozen");
|
|
3091
6186
|
var unfreezePanes = (api) => void api.executeCommand("sheet.command.cancel-frozen");
|
|
3092
6187
|
var toggleGridlines = (api) => {
|
|
3093
6188
|
const wb = fu(api).getActiveWorkbook();
|
|
3094
|
-
const sheet =
|
|
6189
|
+
const sheet = activeSheet3(api);
|
|
3095
6190
|
if (!wb || !sheet) return;
|
|
3096
6191
|
void api.executeCommand("sheet.command.toggle-gridlines", {
|
|
3097
6192
|
unitId: wb.getId(),
|
|
@@ -3101,7 +6196,7 @@ var toggleGridlines = (api) => {
|
|
|
3101
6196
|
};
|
|
3102
6197
|
var toggleCommentPanel = (api) => void api.executeCommand("sheet.operation.toggle-comment-panel");
|
|
3103
6198
|
var jumpToFirstCell = (api) => {
|
|
3104
|
-
|
|
6199
|
+
activeSheet3(api)?.getRange(0, 0).activate();
|
|
3105
6200
|
};
|
|
3106
6201
|
var switchToPreviousSheet = (api) => switchSheetByDelta(api, -1);
|
|
3107
6202
|
var switchToNextSheet = (api) => switchSheetByDelta(api, 1);
|
|
@@ -3121,7 +6216,7 @@ var showFormulas = (api) => void api.executeCommand("sheet.command.set-show-form
|
|
|
3121
6216
|
var sortAsc = (api) => sortRange(api, true);
|
|
3122
6217
|
var sortDesc = (api) => sortRange(api, false);
|
|
3123
6218
|
function sortRange(api, ascending) {
|
|
3124
|
-
const range =
|
|
6219
|
+
const range = activeRange12(api);
|
|
3125
6220
|
if (!range) return;
|
|
3126
6221
|
const withSort = range;
|
|
3127
6222
|
withSort.sort?.({ column: range.getColumn(), ascending });
|
|
@@ -3130,8 +6225,8 @@ var toggleFilter = (api) => {
|
|
|
3130
6225
|
void (async () => {
|
|
3131
6226
|
await ensurePluginByName("filter");
|
|
3132
6227
|
const wb = fu(api).getActiveWorkbook();
|
|
3133
|
-
const sheet =
|
|
3134
|
-
const range =
|
|
6228
|
+
const sheet = activeSheet3(api);
|
|
6229
|
+
const range = activeRange12(api);
|
|
3135
6230
|
if (!wb || !sheet || !range) return;
|
|
3136
6231
|
const sheetWithFilter = sheet;
|
|
3137
6232
|
if (sheetWithFilter.getFilter?.()) {
|
|
@@ -3837,13 +6932,13 @@ var SUBMENU_PANEL_STYLE = {
|
|
|
3837
6932
|
};
|
|
3838
6933
|
function MenuBar({ api, features = {}, extensions }) {
|
|
3839
6934
|
const dialogs = useDialogs();
|
|
3840
|
-
const [open, setOpen] = (0,
|
|
3841
|
-
const [openSubmenu, setOpenSubmenu] = (0,
|
|
3842
|
-
const rootRef = (0,
|
|
3843
|
-
(0,
|
|
6935
|
+
const [open, setOpen] = (0, import_react23.useState)(null);
|
|
6936
|
+
const [openSubmenu, setOpenSubmenu] = (0, import_react23.useState)(null);
|
|
6937
|
+
const rootRef = (0, import_react23.useRef)(null);
|
|
6938
|
+
(0, import_react23.useEffect)(() => {
|
|
3844
6939
|
ensureChromeFonts();
|
|
3845
6940
|
}, []);
|
|
3846
|
-
(0,
|
|
6941
|
+
(0, import_react23.useEffect)(() => {
|
|
3847
6942
|
if (open === null) return;
|
|
3848
6943
|
const onKey = (e) => {
|
|
3849
6944
|
if (e.key === "Escape") {
|
|
@@ -3881,18 +6976,18 @@ function MenuBar({ api, features = {}, extensions }) {
|
|
|
3881
6976
|
const visibleMenus = computeVisibleMenus(MENUS, features, dialogs.canOpen, extensions?.menu);
|
|
3882
6977
|
const renderItems = (items) => items.map((item) => {
|
|
3883
6978
|
if (item.kind === "separator") {
|
|
3884
|
-
return /* @__PURE__ */ (0,
|
|
6979
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: SEPARATOR_STYLE, role: "separator", "aria-hidden": true }, item.id);
|
|
3885
6980
|
}
|
|
3886
6981
|
if (item.kind === "submenu") {
|
|
3887
6982
|
const isSubOpen = openSubmenu === item.id;
|
|
3888
|
-
return /* @__PURE__ */ (0,
|
|
6983
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
3889
6984
|
"div",
|
|
3890
6985
|
{
|
|
3891
6986
|
style: { position: "relative" },
|
|
3892
6987
|
onMouseEnter: () => setOpenSubmenu(item.id),
|
|
3893
6988
|
onMouseLeave: () => setOpenSubmenu((cur) => cur === item.id ? null : cur),
|
|
3894
6989
|
children: [
|
|
3895
|
-
/* @__PURE__ */ (0,
|
|
6990
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
3896
6991
|
"button",
|
|
3897
6992
|
{
|
|
3898
6993
|
type: "button",
|
|
@@ -3904,19 +6999,19 @@ function MenuBar({ api, features = {}, extensions }) {
|
|
|
3904
6999
|
style: { ...ITEM_STYLE3, opacity: api ? 1 : 0.5 },
|
|
3905
7000
|
onMouseDown: (e) => e.preventDefault(),
|
|
3906
7001
|
children: [
|
|
3907
|
-
item.icon ? /* @__PURE__ */ (0,
|
|
3908
|
-
/* @__PURE__ */ (0,
|
|
3909
|
-
/* @__PURE__ */ (0,
|
|
7002
|
+
item.icon ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Icon, { name: item.icon, size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { width: 18 }, "aria-hidden": true }),
|
|
7003
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: item.label }),
|
|
7004
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Icon, { name: "chevron_right", size: 18, style: { marginLeft: "auto" } })
|
|
3910
7005
|
]
|
|
3911
7006
|
}
|
|
3912
7007
|
),
|
|
3913
|
-
isSubOpen && /* @__PURE__ */ (0,
|
|
7008
|
+
isSubOpen && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: SUBMENU_PANEL_STYLE, role: "menu", "aria-label": item.label, children: renderItems(item.items) })
|
|
3914
7009
|
]
|
|
3915
7010
|
},
|
|
3916
7011
|
item.id
|
|
3917
7012
|
);
|
|
3918
7013
|
}
|
|
3919
|
-
return /* @__PURE__ */ (0,
|
|
7014
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
3920
7015
|
"button",
|
|
3921
7016
|
{
|
|
3922
7017
|
type: "button",
|
|
@@ -3936,15 +7031,15 @@ function MenuBar({ api, features = {}, extensions }) {
|
|
|
3936
7031
|
e.currentTarget.style.background = "transparent";
|
|
3937
7032
|
},
|
|
3938
7033
|
children: [
|
|
3939
|
-
item.icon ? /* @__PURE__ */ (0,
|
|
3940
|
-
/* @__PURE__ */ (0,
|
|
3941
|
-
item.shortcut && /* @__PURE__ */ (0,
|
|
7034
|
+
item.icon ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Icon, { name: item.icon, size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { width: 18 }, "aria-hidden": true }),
|
|
7035
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: item.label }),
|
|
7036
|
+
item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: SHORTCUT_STYLE, children: fmtShortcut(item.shortcut) })
|
|
3942
7037
|
]
|
|
3943
7038
|
},
|
|
3944
7039
|
item.id
|
|
3945
7040
|
);
|
|
3946
7041
|
});
|
|
3947
|
-
return /* @__PURE__ */ (0,
|
|
7042
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3948
7043
|
"div",
|
|
3949
7044
|
{
|
|
3950
7045
|
ref: rootRef,
|
|
@@ -3954,8 +7049,8 @@ function MenuBar({ api, features = {}, extensions }) {
|
|
|
3954
7049
|
"aria-label": "Menu bar",
|
|
3955
7050
|
children: visibleMenus.map((menu) => {
|
|
3956
7051
|
const isOpen = open === menu.id;
|
|
3957
|
-
return /* @__PURE__ */ (0,
|
|
3958
|
-
/* @__PURE__ */ (0,
|
|
7052
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { position: "relative" }, children: [
|
|
7053
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3959
7054
|
"button",
|
|
3960
7055
|
{
|
|
3961
7056
|
type: "button",
|
|
@@ -3986,7 +7081,7 @@ function MenuBar({ api, features = {}, extensions }) {
|
|
|
3986
7081
|
children: menu.label
|
|
3987
7082
|
}
|
|
3988
7083
|
),
|
|
3989
|
-
isOpen && /* @__PURE__ */ (0,
|
|
7084
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: DROPDOWN_STYLE, role: "menu", "aria-label": menu.label, children: renderItems(menu.items) })
|
|
3990
7085
|
] }, menu.id);
|
|
3991
7086
|
})
|
|
3992
7087
|
}
|
|
@@ -3994,9 +7089,9 @@ function MenuBar({ api, features = {}, extensions }) {
|
|
|
3994
7089
|
}
|
|
3995
7090
|
|
|
3996
7091
|
// src/chrome/SheetTabs.tsx
|
|
3997
|
-
var
|
|
7092
|
+
var import_react24 = require("react");
|
|
3998
7093
|
var import_react_dom2 = require("react-dom");
|
|
3999
|
-
var
|
|
7094
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
4000
7095
|
var EMPTY = { tabs: [], activeId: null };
|
|
4001
7096
|
var SHEET_LIST_MUTATIONS = /* @__PURE__ */ new Set([
|
|
4002
7097
|
"sheet.mutation.insert-sheet",
|
|
@@ -4029,7 +7124,7 @@ var BAR_STYLE5 = {
|
|
|
4029
7124
|
overflowX: "auto",
|
|
4030
7125
|
overflowY: "hidden"
|
|
4031
7126
|
};
|
|
4032
|
-
var
|
|
7127
|
+
var ADD_BTN_STYLE2 = {
|
|
4033
7128
|
flex: "0 0 auto",
|
|
4034
7129
|
width: 28,
|
|
4035
7130
|
border: "none",
|
|
@@ -4077,11 +7172,11 @@ var MENU_ITEM_STYLE2 = {
|
|
|
4077
7172
|
cursor: "pointer"
|
|
4078
7173
|
};
|
|
4079
7174
|
function SheetTabs({ api }) {
|
|
4080
|
-
const [{ tabs, activeId }, setSnapshot] = (0,
|
|
4081
|
-
const [renaming, setRenaming] = (0,
|
|
4082
|
-
const [draft, setDraft] = (0,
|
|
4083
|
-
const [menu, setMenu] = (0,
|
|
4084
|
-
(0,
|
|
7175
|
+
const [{ tabs, activeId }, setSnapshot] = (0, import_react24.useState)(EMPTY);
|
|
7176
|
+
const [renaming, setRenaming] = (0, import_react24.useState)(null);
|
|
7177
|
+
const [draft, setDraft] = (0, import_react24.useState)("");
|
|
7178
|
+
const [menu, setMenu] = (0, import_react24.useState)(null);
|
|
7179
|
+
(0, import_react24.useEffect)(() => {
|
|
4085
7180
|
if (!api) return;
|
|
4086
7181
|
const refresh = () => setSnapshot(readSheets(api));
|
|
4087
7182
|
refresh();
|
|
@@ -4109,7 +7204,7 @@ function SheetTabs({ api }) {
|
|
|
4109
7204
|
for (const s of subs) s?.dispose?.();
|
|
4110
7205
|
};
|
|
4111
7206
|
}, [api]);
|
|
4112
|
-
(0,
|
|
7207
|
+
(0, import_react24.useEffect)(() => {
|
|
4113
7208
|
if (!menu) return;
|
|
4114
7209
|
const close = () => setMenu(null);
|
|
4115
7210
|
window.addEventListener("pointerdown", close);
|
|
@@ -4120,7 +7215,7 @@ function SheetTabs({ api }) {
|
|
|
4120
7215
|
};
|
|
4121
7216
|
}, [menu]);
|
|
4122
7217
|
if (!api) {
|
|
4123
|
-
return /* @__PURE__ */ (0,
|
|
7218
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: BAR_STYLE5, "data-testid": "casual-sheets-tabs" });
|
|
4124
7219
|
}
|
|
4125
7220
|
const visible = tabs.filter((t) => !t.hidden);
|
|
4126
7221
|
const wb = () => api.univer.getActiveWorkbook();
|
|
@@ -4160,11 +7255,11 @@ function SheetTabs({ api }) {
|
|
|
4160
7255
|
setRenaming(null);
|
|
4161
7256
|
}
|
|
4162
7257
|
};
|
|
4163
|
-
return /* @__PURE__ */ (0,
|
|
7258
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: BAR_STYLE5, "data-testid": "casual-sheets-tabs", role: "tablist", children: [
|
|
4164
7259
|
visible.map((tab) => {
|
|
4165
7260
|
const active = tab.id === activeId;
|
|
4166
7261
|
if (renaming === tab.id) {
|
|
4167
|
-
return /* @__PURE__ */ (0,
|
|
7262
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
4168
7263
|
"input",
|
|
4169
7264
|
{
|
|
4170
7265
|
autoFocus: true,
|
|
@@ -4178,7 +7273,7 @@ function SheetTabs({ api }) {
|
|
|
4178
7273
|
tab.id
|
|
4179
7274
|
);
|
|
4180
7275
|
}
|
|
4181
|
-
return /* @__PURE__ */ (0,
|
|
7276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
4182
7277
|
"button",
|
|
4183
7278
|
{
|
|
4184
7279
|
type: "button",
|
|
@@ -4217,11 +7312,11 @@ function SheetTabs({ api }) {
|
|
|
4217
7312
|
tab.id
|
|
4218
7313
|
);
|
|
4219
7314
|
}),
|
|
4220
|
-
/* @__PURE__ */ (0,
|
|
7315
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
4221
7316
|
"button",
|
|
4222
7317
|
{
|
|
4223
7318
|
type: "button",
|
|
4224
|
-
style:
|
|
7319
|
+
style: ADD_BTN_STYLE2,
|
|
4225
7320
|
"aria-label": "Add sheet",
|
|
4226
7321
|
title: "Add sheet",
|
|
4227
7322
|
"data-testid": "cs-tab-add",
|
|
@@ -4233,7 +7328,7 @@ function SheetTabs({ api }) {
|
|
|
4233
7328
|
}
|
|
4234
7329
|
),
|
|
4235
7330
|
menu && (0, import_react_dom2.createPortal)(
|
|
4236
|
-
/* @__PURE__ */ (0,
|
|
7331
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
4237
7332
|
"div",
|
|
4238
7333
|
{
|
|
4239
7334
|
style: { ...MENU_STYLE2, left: menu.x, top: menu.y, transform: "translateY(-100%)" },
|
|
@@ -4241,7 +7336,7 @@ function SheetTabs({ api }) {
|
|
|
4241
7336
|
role: "menu",
|
|
4242
7337
|
onPointerDown: (e) => e.stopPropagation(),
|
|
4243
7338
|
children: [
|
|
4244
|
-
/* @__PURE__ */ (0,
|
|
7339
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
4245
7340
|
"button",
|
|
4246
7341
|
{
|
|
4247
7342
|
type: "button",
|
|
@@ -4256,7 +7351,7 @@ function SheetTabs({ api }) {
|
|
|
4256
7351
|
children: "Rename"
|
|
4257
7352
|
}
|
|
4258
7353
|
),
|
|
4259
|
-
/* @__PURE__ */ (0,
|
|
7354
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
4260
7355
|
"button",
|
|
4261
7356
|
{
|
|
4262
7357
|
type: "button",
|
|
@@ -4283,8 +7378,8 @@ function SheetTabs({ api }) {
|
|
|
4283
7378
|
}
|
|
4284
7379
|
|
|
4285
7380
|
// src/chrome/FindReplace.tsx
|
|
4286
|
-
var
|
|
4287
|
-
var
|
|
7381
|
+
var import_react25 = require("react");
|
|
7382
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
4288
7383
|
function findMatches(api, query, matchCase) {
|
|
4289
7384
|
if (!query) return [];
|
|
4290
7385
|
const snap = api.getSnapshot();
|
|
@@ -4322,7 +7417,7 @@ var WRAP_STYLE = {
|
|
|
4322
7417
|
fontSize: 13,
|
|
4323
7418
|
color: "var(--cs-chrome-fg, #201f1e)"
|
|
4324
7419
|
};
|
|
4325
|
-
var
|
|
7420
|
+
var ROW_STYLE5 = { display: "flex", alignItems: "center", gap: 6, marginBottom: 6 };
|
|
4326
7421
|
var INPUT_STYLE2 = {
|
|
4327
7422
|
flex: "1 1 auto",
|
|
4328
7423
|
height: 26,
|
|
@@ -4360,14 +7455,14 @@ var ICON_BTN_STYLE = {
|
|
|
4360
7455
|
padding: 0
|
|
4361
7456
|
};
|
|
4362
7457
|
function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
4363
|
-
const [open, setOpen] = (0,
|
|
4364
|
-
const [showReplace, setShowReplace] = (0,
|
|
4365
|
-
const [query, setQuery] = (0,
|
|
4366
|
-
const [replaceText, setReplaceText] = (0,
|
|
4367
|
-
const [matchCase, setMatchCase] = (0,
|
|
4368
|
-
const [idx, setIdx] = (0,
|
|
4369
|
-
const inputRef = (0,
|
|
4370
|
-
(0,
|
|
7458
|
+
const [open, setOpen] = (0, import_react25.useState)(false);
|
|
7459
|
+
const [showReplace, setShowReplace] = (0, import_react25.useState)(false);
|
|
7460
|
+
const [query, setQuery] = (0, import_react25.useState)("");
|
|
7461
|
+
const [replaceText, setReplaceText] = (0, import_react25.useState)("");
|
|
7462
|
+
const [matchCase, setMatchCase] = (0, import_react25.useState)(false);
|
|
7463
|
+
const [idx, setIdx] = (0, import_react25.useState)(0);
|
|
7464
|
+
const inputRef = (0, import_react25.useRef)(null);
|
|
7465
|
+
(0, import_react25.useEffect)(() => {
|
|
4371
7466
|
const onKey = (e) => {
|
|
4372
7467
|
const mod = e.metaKey || e.ctrlKey;
|
|
4373
7468
|
if (mod && (e.key === "f" || e.key === "F")) {
|
|
@@ -4385,8 +7480,8 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4385
7480
|
document.addEventListener("keydown", onKey);
|
|
4386
7481
|
return () => document.removeEventListener("keydown", onKey);
|
|
4387
7482
|
}, []);
|
|
4388
|
-
const lastSignal = (0,
|
|
4389
|
-
(0,
|
|
7483
|
+
const lastSignal = (0, import_react25.useRef)(void 0);
|
|
7484
|
+
(0, import_react25.useEffect)(() => {
|
|
4390
7485
|
if (openSignal === void 0) return;
|
|
4391
7486
|
if (lastSignal.current === openSignal) return;
|
|
4392
7487
|
lastSignal.current = openSignal;
|
|
@@ -4394,11 +7489,11 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4394
7489
|
setOpen(true);
|
|
4395
7490
|
requestAnimationFrame(() => inputRef.current?.focus());
|
|
4396
7491
|
}, [openSignal, openInReplaceMode]);
|
|
4397
|
-
const matches = (0,
|
|
7492
|
+
const matches = (0, import_react25.useMemo)(
|
|
4398
7493
|
() => api && open && query ? findMatches(api, query, matchCase) : [],
|
|
4399
7494
|
[api, open, query, matchCase]
|
|
4400
7495
|
);
|
|
4401
|
-
(0,
|
|
7496
|
+
(0, import_react25.useEffect)(() => {
|
|
4402
7497
|
setIdx((i) => matches.length === 0 ? 0 : Math.min(i, matches.length - 1));
|
|
4403
7498
|
}, [matches.length]);
|
|
4404
7499
|
if (!open || !api) return null;
|
|
@@ -4444,7 +7539,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4444
7539
|
};
|
|
4445
7540
|
const count = matches.length;
|
|
4446
7541
|
const position = count === 0 ? 0 : Math.min(idx, count - 1) + 1;
|
|
4447
|
-
return /* @__PURE__ */ (0,
|
|
7542
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
4448
7543
|
"div",
|
|
4449
7544
|
{
|
|
4450
7545
|
style: WRAP_STYLE,
|
|
@@ -4452,8 +7547,8 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4452
7547
|
role: "dialog",
|
|
4453
7548
|
"aria-label": "Find and replace",
|
|
4454
7549
|
children: [
|
|
4455
|
-
/* @__PURE__ */ (0,
|
|
4456
|
-
/* @__PURE__ */ (0,
|
|
7550
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: ROW_STYLE5, children: [
|
|
7551
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4457
7552
|
"input",
|
|
4458
7553
|
{
|
|
4459
7554
|
ref: inputRef,
|
|
@@ -4467,7 +7562,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4467
7562
|
onKeyDown: onInputKey
|
|
4468
7563
|
}
|
|
4469
7564
|
),
|
|
4470
|
-
/* @__PURE__ */ (0,
|
|
7565
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
4471
7566
|
"span",
|
|
4472
7567
|
{
|
|
4473
7568
|
style: { minWidth: 54, textAlign: "center", color: "var(--cs-chrome-muted, #6b7280)" },
|
|
@@ -4479,7 +7574,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4479
7574
|
]
|
|
4480
7575
|
}
|
|
4481
7576
|
),
|
|
4482
|
-
/* @__PURE__ */ (0,
|
|
7577
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4483
7578
|
"button",
|
|
4484
7579
|
{
|
|
4485
7580
|
type: "button",
|
|
@@ -4490,10 +7585,10 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4490
7585
|
e.preventDefault();
|
|
4491
7586
|
go(-1);
|
|
4492
7587
|
},
|
|
4493
|
-
children: /* @__PURE__ */ (0,
|
|
7588
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { name: "keyboard_arrow_up", size: 18 })
|
|
4494
7589
|
}
|
|
4495
7590
|
),
|
|
4496
|
-
/* @__PURE__ */ (0,
|
|
7591
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4497
7592
|
"button",
|
|
4498
7593
|
{
|
|
4499
7594
|
type: "button",
|
|
@@ -4504,10 +7599,10 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4504
7599
|
e.preventDefault();
|
|
4505
7600
|
go(1);
|
|
4506
7601
|
},
|
|
4507
|
-
children: /* @__PURE__ */ (0,
|
|
7602
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { name: "keyboard_arrow_down", size: 18 })
|
|
4508
7603
|
}
|
|
4509
7604
|
),
|
|
4510
|
-
/* @__PURE__ */ (0,
|
|
7605
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4511
7606
|
"button",
|
|
4512
7607
|
{
|
|
4513
7608
|
type: "button",
|
|
@@ -4518,12 +7613,12 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4518
7613
|
e.preventDefault();
|
|
4519
7614
|
setOpen(false);
|
|
4520
7615
|
},
|
|
4521
|
-
children: /* @__PURE__ */ (0,
|
|
7616
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Icon, { name: "close", size: 18 })
|
|
4522
7617
|
}
|
|
4523
7618
|
)
|
|
4524
7619
|
] }),
|
|
4525
|
-
showReplace && /* @__PURE__ */ (0,
|
|
4526
|
-
/* @__PURE__ */ (0,
|
|
7620
|
+
showReplace && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: ROW_STYLE5, children: [
|
|
7621
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4527
7622
|
"input",
|
|
4528
7623
|
{
|
|
4529
7624
|
type: "text",
|
|
@@ -4535,7 +7630,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4535
7630
|
onChange: (e) => setReplaceText(e.target.value)
|
|
4536
7631
|
}
|
|
4537
7632
|
),
|
|
4538
|
-
/* @__PURE__ */ (0,
|
|
7633
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4539
7634
|
"button",
|
|
4540
7635
|
{
|
|
4541
7636
|
type: "button",
|
|
@@ -4548,7 +7643,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4548
7643
|
children: "Replace"
|
|
4549
7644
|
}
|
|
4550
7645
|
),
|
|
4551
|
-
/* @__PURE__ */ (0,
|
|
7646
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4552
7647
|
"button",
|
|
4553
7648
|
{
|
|
4554
7649
|
type: "button",
|
|
@@ -4562,9 +7657,9 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4562
7657
|
}
|
|
4563
7658
|
)
|
|
4564
7659
|
] }),
|
|
4565
|
-
/* @__PURE__ */ (0,
|
|
4566
|
-
/* @__PURE__ */ (0,
|
|
4567
|
-
/* @__PURE__ */ (0,
|
|
7660
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
|
|
7661
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: 4, cursor: "pointer" }, children: [
|
|
7662
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4568
7663
|
"input",
|
|
4569
7664
|
{
|
|
4570
7665
|
type: "checkbox",
|
|
@@ -4575,7 +7670,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
|
|
|
4575
7670
|
),
|
|
4576
7671
|
"Match case"
|
|
4577
7672
|
] }),
|
|
4578
|
-
!showReplace && /* @__PURE__ */ (0,
|
|
7673
|
+
!showReplace && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4579
7674
|
"button",
|
|
4580
7675
|
{
|
|
4581
7676
|
type: "button",
|
|
@@ -4619,8 +7714,8 @@ function replaceInString(text, query, replacement, matchCase) {
|
|
|
4619
7714
|
}
|
|
4620
7715
|
|
|
4621
7716
|
// src/chrome/ChromeTop.tsx
|
|
4622
|
-
var
|
|
4623
|
-
var
|
|
7717
|
+
var import_react26 = require("react");
|
|
7718
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
4624
7719
|
function ChromeTop({
|
|
4625
7720
|
api,
|
|
4626
7721
|
features,
|
|
@@ -4628,13 +7723,13 @@ function ChromeTop({
|
|
|
4628
7723
|
hostOwnedDialogs,
|
|
4629
7724
|
extensions
|
|
4630
7725
|
}) {
|
|
4631
|
-
const [findSignal, setFindSignal] = (0,
|
|
4632
|
-
const [findReplaceMode, setFindReplaceMode] = (0,
|
|
4633
|
-
const openFindReplace = (0,
|
|
7726
|
+
const [findSignal, setFindSignal] = (0, import_react26.useState)(0);
|
|
7727
|
+
const [findReplaceMode, setFindReplaceMode] = (0, import_react26.useState)(false);
|
|
7728
|
+
const openFindReplace = (0, import_react26.useCallback)((replaceMode) => {
|
|
4634
7729
|
setFindReplaceMode(replaceMode);
|
|
4635
7730
|
setFindSignal((n) => n + 1);
|
|
4636
7731
|
}, []);
|
|
4637
|
-
return /* @__PURE__ */ (0,
|
|
7732
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
4638
7733
|
DialogProvider,
|
|
4639
7734
|
{
|
|
4640
7735
|
api,
|
|
@@ -4643,10 +7738,10 @@ function ChromeTop({
|
|
|
4643
7738
|
hostOwnedDialogs,
|
|
4644
7739
|
onOpenFindReplace: openFindReplace,
|
|
4645
7740
|
children: [
|
|
4646
|
-
/* @__PURE__ */ (0,
|
|
4647
|
-
/* @__PURE__ */ (0,
|
|
4648
|
-
/* @__PURE__ */ (0,
|
|
4649
|
-
/* @__PURE__ */ (0,
|
|
7741
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MenuBar, { api, features, extensions }),
|
|
7742
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Toolbar, { api, features, extensions }),
|
|
7743
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(FormulaBar, { api }),
|
|
7744
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
4650
7745
|
FindReplace,
|
|
4651
7746
|
{
|
|
4652
7747
|
api,
|
|
@@ -4660,11 +7755,11 @@ function ChromeTop({
|
|
|
4660
7755
|
}
|
|
4661
7756
|
|
|
4662
7757
|
// src/chrome/ChromeBottom.tsx
|
|
4663
|
-
var
|
|
7758
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
4664
7759
|
function ChromeBottom({ api }) {
|
|
4665
|
-
return /* @__PURE__ */ (0,
|
|
4666
|
-
/* @__PURE__ */ (0,
|
|
4667
|
-
/* @__PURE__ */ (0,
|
|
7760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
7761
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SheetTabs, { api }),
|
|
7762
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(StatusBar, { api })
|
|
4668
7763
|
] });
|
|
4669
7764
|
}
|
|
4670
7765
|
//# sourceMappingURL=chrome.cjs.map
|