@casualoffice/sheets 0.17.0 → 0.18.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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/chrome/Toolbar.tsx
2
- import { useEffect as useEffect6, useState as useState6 } from "react";
2
+ import { useEffect as useEffect6, useState as useState18 } from "react";
3
3
  import { ICommandService } from "@univerjs/core";
4
4
 
5
5
  // src/chrome/Icon.tsx
@@ -526,7 +526,7 @@ function AutoSumPicker({ api }) {
526
526
  }
527
527
 
528
528
  // src/chrome/dialog-context.tsx
529
- import { createContext, useCallback, useContext, useMemo as useMemo2, useState as useState5 } from "react";
529
+ import { createContext, useCallback as useCallback2, useContext, useMemo as useMemo14, useState as useState17 } from "react";
530
530
 
531
531
  // src/chrome/FormatCellsDialog.tsx
532
532
  import { useEffect as useEffect5, useMemo, useState as useState4 } from "react";
@@ -1128,10 +1128,3105 @@ function FormatCellsDialog({ api, onClose }) {
1128
1128
  );
1129
1129
  }
1130
1130
 
1131
+ // src/chrome/DataValidationDialog.tsx
1132
+ import { useMemo as useMemo2, useState as useState5 } from "react";
1133
+ import "@univerjs/sheets-data-validation/facade";
1134
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1135
+ var RULE_TYPE_OPTIONS = [
1136
+ { value: "list", label: "List of items" },
1137
+ { value: "number", label: "Whole number" },
1138
+ { value: "decimal", label: "Decimal" },
1139
+ { value: "date", label: "Date" },
1140
+ { value: "textLength", label: "Text length" },
1141
+ { value: "checkbox", label: "Checkbox" }
1142
+ ];
1143
+ var OPERATOR_OPTIONS = [
1144
+ { value: "between", label: "Between" },
1145
+ { value: "notBetween", label: "Not between" },
1146
+ { value: "equal", label: "Equal to" },
1147
+ { value: "notEqual", label: "Not equal to" },
1148
+ { value: "greater", label: "Greater than" },
1149
+ { value: "greaterEqual", label: "Greater than or equal to" },
1150
+ { value: "less", label: "Less than" },
1151
+ { value: "lessEqual", label: "Less than or equal to" }
1152
+ ];
1153
+ function isRangeOperator(op) {
1154
+ return op === "between" || op === "notBetween";
1155
+ }
1156
+ function usesOperator(type) {
1157
+ return type === "number" || type === "decimal" || type === "date" || type === "textLength";
1158
+ }
1159
+ var INITIAL_STATE = {
1160
+ ruleType: "list",
1161
+ operator: "between",
1162
+ operand1: "",
1163
+ operand2: "",
1164
+ listItems: "",
1165
+ ignoreBlank: true,
1166
+ showErrorMessage: false,
1167
+ errorMessage: "",
1168
+ showInputMessage: false,
1169
+ inputMessage: ""
1170
+ };
1171
+ function activeRange2(api) {
1172
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
1173
+ }
1174
+ function applyValidation(api, s, remove) {
1175
+ const range = activeRange2(api);
1176
+ if (!range) return false;
1177
+ const dvRange = range;
1178
+ if (remove) {
1179
+ dvRange.setDataValidation(null);
1180
+ return true;
1181
+ }
1182
+ const builder = api.univer.newDataValidation();
1183
+ const n1 = Number(s.operand1);
1184
+ const n2 = Number(s.operand2);
1185
+ const wholeNumber = s.ruleType === "number";
1186
+ switch (s.ruleType) {
1187
+ case "list": {
1188
+ const values = s.listItems.split(/[\n,]/).map((v) => v.trim()).filter((v) => v.length > 0);
1189
+ if (values.length === 0) return false;
1190
+ builder.requireValueInList(values, false, true);
1191
+ break;
1192
+ }
1193
+ case "number":
1194
+ case "decimal": {
1195
+ if (!Number.isFinite(n1)) return false;
1196
+ switch (s.operator) {
1197
+ case "between":
1198
+ if (!Number.isFinite(n2)) return false;
1199
+ builder.requireNumberBetween(n1, n2, wholeNumber);
1200
+ break;
1201
+ case "notBetween":
1202
+ if (!Number.isFinite(n2)) return false;
1203
+ builder.requireNumberNotBetween(n1, n2, wholeNumber);
1204
+ break;
1205
+ case "equal":
1206
+ builder.requireNumberEqualTo(n1, wholeNumber);
1207
+ break;
1208
+ case "notEqual":
1209
+ builder.requireNumberNotEqualTo(n1, wholeNumber);
1210
+ break;
1211
+ case "greater":
1212
+ builder.requireNumberGreaterThan(n1, wholeNumber);
1213
+ break;
1214
+ case "greaterEqual":
1215
+ builder.requireNumberGreaterThanOrEqualTo(n1, wholeNumber);
1216
+ break;
1217
+ case "less":
1218
+ builder.requireNumberLessThan(n1, wholeNumber);
1219
+ break;
1220
+ case "lessEqual":
1221
+ builder.requireNumberLessThanOrEqualTo(n1, wholeNumber);
1222
+ break;
1223
+ }
1224
+ break;
1225
+ }
1226
+ case "date": {
1227
+ const d1 = new Date(s.operand1);
1228
+ const d2 = new Date(s.operand2);
1229
+ if (Number.isNaN(d1.getTime())) return false;
1230
+ switch (s.operator) {
1231
+ case "between":
1232
+ if (Number.isNaN(d2.getTime())) return false;
1233
+ builder.requireDateBetween(d1, d2);
1234
+ break;
1235
+ case "notBetween":
1236
+ if (Number.isNaN(d2.getTime())) return false;
1237
+ builder.requireDateNotBetween(d1, d2);
1238
+ break;
1239
+ case "equal":
1240
+ builder.requireDateEqualTo(d1);
1241
+ break;
1242
+ // The builder has no requireDateNotEqualTo; map the remaining operators
1243
+ // to the closest available on/after / on/before methods.
1244
+ case "notEqual":
1245
+ case "greater":
1246
+ builder.requireDateAfter(d1);
1247
+ break;
1248
+ case "greaterEqual":
1249
+ builder.requireDateOnOrAfter(d1);
1250
+ break;
1251
+ case "less":
1252
+ builder.requireDateBefore(d1);
1253
+ break;
1254
+ case "lessEqual":
1255
+ builder.requireDateOnOrBefore(d1);
1256
+ break;
1257
+ }
1258
+ break;
1259
+ }
1260
+ case "textLength": {
1261
+ if (!Number.isFinite(n1)) return false;
1262
+ const anchor = dvRange.getA1Notation?.() ?? "A1";
1263
+ const cell = anchor.split(":")[0];
1264
+ const len = `LEN(${cell})`;
1265
+ let formula;
1266
+ switch (s.operator) {
1267
+ case "between":
1268
+ if (!Number.isFinite(n2)) return false;
1269
+ formula = `=AND(${len}>=${n1}, ${len}<=${n2})`;
1270
+ break;
1271
+ case "notBetween":
1272
+ if (!Number.isFinite(n2)) return false;
1273
+ formula = `=OR(${len}<${n1}, ${len}>${n2})`;
1274
+ break;
1275
+ case "equal":
1276
+ formula = `=${len}=${n1}`;
1277
+ break;
1278
+ case "notEqual":
1279
+ formula = `=${len}<>${n1}`;
1280
+ break;
1281
+ case "greater":
1282
+ formula = `=${len}>${n1}`;
1283
+ break;
1284
+ case "greaterEqual":
1285
+ formula = `=${len}>=${n1}`;
1286
+ break;
1287
+ case "less":
1288
+ formula = `=${len}<${n1}`;
1289
+ break;
1290
+ case "lessEqual":
1291
+ formula = `=${len}<=${n1}`;
1292
+ break;
1293
+ }
1294
+ builder.requireFormulaSatisfied(formula);
1295
+ break;
1296
+ }
1297
+ case "checkbox":
1298
+ builder.requireCheckbox();
1299
+ break;
1300
+ }
1301
+ builder.setAllowBlank(s.ignoreBlank);
1302
+ builder.setOptions({
1303
+ showErrorMessage: s.showErrorMessage,
1304
+ error: s.showErrorMessage ? s.errorMessage : void 0,
1305
+ showInputMessage: s.showInputMessage,
1306
+ prompt: s.showInputMessage ? s.inputMessage : void 0
1307
+ });
1308
+ dvRange.setDataValidation(builder.build());
1309
+ return true;
1310
+ }
1311
+ var CHECK_STYLE2 = {
1312
+ display: "flex",
1313
+ alignItems: "center",
1314
+ gap: 6,
1315
+ marginBottom: 8,
1316
+ cursor: "pointer"
1317
+ };
1318
+ var TEXTAREA_STYLE = {
1319
+ ...DIALOG_INPUT_STYLE,
1320
+ height: "auto",
1321
+ minHeight: 64,
1322
+ padding: "6px 8px",
1323
+ resize: "vertical",
1324
+ lineHeight: 1.4
1325
+ };
1326
+ var RANGE_NOTE_STYLE = {
1327
+ fontSize: 12,
1328
+ color: "var(--cs-chrome-muted, #605e5c)",
1329
+ marginBottom: 12
1330
+ };
1331
+ var TWO_COL_STYLE = {
1332
+ display: "grid",
1333
+ gridTemplateColumns: "1fr 1fr",
1334
+ gap: 8
1335
+ };
1336
+ function DataValidationDialog({ api, onClose }) {
1337
+ const [state, setState] = useState5(INITIAL_STATE);
1338
+ const rangeLabel = useMemo2(() => {
1339
+ const fRange = activeRange2(api);
1340
+ return fRange?.getA1Notation?.() ?? null;
1341
+ }, [api]);
1342
+ const hasSelection = activeRange2(api) !== null;
1343
+ const update = (key, value) => setState((prev) => ({ ...prev, [key]: value }));
1344
+ const apply = () => {
1345
+ if (applyValidation(api, state, false)) onClose();
1346
+ };
1347
+ const removeRule = () => {
1348
+ applyValidation(api, state, true);
1349
+ onClose();
1350
+ };
1351
+ const showOperator = usesOperator(state.ruleType);
1352
+ const showSecondOperand = showOperator && isRangeOperator(state.operator);
1353
+ const operandType = state.ruleType === "date" ? "date" : "number";
1354
+ return /* @__PURE__ */ jsxs6(
1355
+ Dialog,
1356
+ {
1357
+ title: "Data validation",
1358
+ onClose,
1359
+ width: 440,
1360
+ "data-testid": "cs-data-validation-dialog",
1361
+ footer: /* @__PURE__ */ jsxs6(Fragment2, { children: [
1362
+ /* @__PURE__ */ jsx7(
1363
+ "button",
1364
+ {
1365
+ type: "button",
1366
+ style: DIALOG_BTN_SECONDARY_STYLE,
1367
+ "data-testid": "cs-data-validation-remove",
1368
+ onClick: removeRule,
1369
+ children: "Remove rule"
1370
+ }
1371
+ ),
1372
+ /* @__PURE__ */ jsx7("span", { style: { flex: 1 } }),
1373
+ /* @__PURE__ */ jsx7("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
1374
+ /* @__PURE__ */ jsx7(
1375
+ "button",
1376
+ {
1377
+ type: "button",
1378
+ style: DIALOG_BTN_PRIMARY_STYLE,
1379
+ "data-testid": "cs-data-validation-apply",
1380
+ disabled: !hasSelection,
1381
+ onClick: apply,
1382
+ children: "Apply"
1383
+ }
1384
+ )
1385
+ ] }),
1386
+ children: [
1387
+ hasSelection ? /* @__PURE__ */ jsxs6("div", { style: RANGE_NOTE_STYLE, "data-testid": "cs-data-validation-range", children: [
1388
+ "Applies to ",
1389
+ /* @__PURE__ */ jsx7("strong", { children: rangeLabel ?? "the current selection" })
1390
+ ] }) : /* @__PURE__ */ jsx7("div", { style: RANGE_NOTE_STYLE, "data-testid": "cs-data-validation-no-selection", children: "Select one or more cells first, then reopen this dialog." }),
1391
+ /* @__PURE__ */ jsxs6("label", { style: DIALOG_FIELD_STYLE, children: [
1392
+ /* @__PURE__ */ jsx7("span", { style: DIALOG_LABEL_STYLE, children: "Criteria" }),
1393
+ /* @__PURE__ */ jsx7(
1394
+ "select",
1395
+ {
1396
+ style: DIALOG_INPUT_STYLE,
1397
+ "data-testid": "cs-data-validation-type",
1398
+ value: state.ruleType,
1399
+ onChange: (e) => update("ruleType", e.target.value),
1400
+ children: RULE_TYPE_OPTIONS.map((opt) => /* @__PURE__ */ jsx7("option", { value: opt.value, children: opt.label }, opt.value))
1401
+ }
1402
+ )
1403
+ ] }),
1404
+ state.ruleType === "list" && /* @__PURE__ */ jsxs6("label", { style: DIALOG_FIELD_STYLE, children: [
1405
+ /* @__PURE__ */ jsx7("span", { style: DIALOG_LABEL_STYLE, children: "Items (one per line, or comma-separated)" }),
1406
+ /* @__PURE__ */ jsx7(
1407
+ "textarea",
1408
+ {
1409
+ style: TEXTAREA_STYLE,
1410
+ "data-testid": "cs-data-validation-list-items",
1411
+ value: state.listItems,
1412
+ placeholder: "Yes\nNo\nMaybe",
1413
+ onChange: (e) => update("listItems", e.target.value)
1414
+ }
1415
+ )
1416
+ ] }),
1417
+ showOperator && /* @__PURE__ */ jsxs6(Fragment2, { children: [
1418
+ /* @__PURE__ */ jsxs6("label", { style: DIALOG_FIELD_STYLE, children: [
1419
+ /* @__PURE__ */ jsx7("span", { style: DIALOG_LABEL_STYLE, children: "Condition" }),
1420
+ /* @__PURE__ */ jsx7(
1421
+ "select",
1422
+ {
1423
+ style: DIALOG_INPUT_STYLE,
1424
+ "data-testid": "cs-data-validation-operator",
1425
+ value: state.operator,
1426
+ onChange: (e) => update("operator", e.target.value),
1427
+ children: OPERATOR_OPTIONS.map((opt) => /* @__PURE__ */ jsx7("option", { value: opt.value, children: opt.label }, opt.value))
1428
+ }
1429
+ )
1430
+ ] }),
1431
+ /* @__PURE__ */ jsxs6("div", { style: showSecondOperand ? TWO_COL_STYLE : void 0, children: [
1432
+ /* @__PURE__ */ jsxs6("label", { style: DIALOG_FIELD_STYLE, children: [
1433
+ /* @__PURE__ */ jsx7("span", { style: DIALOG_LABEL_STYLE, children: showSecondOperand ? "Minimum" : "Value" }),
1434
+ /* @__PURE__ */ jsx7(
1435
+ "input",
1436
+ {
1437
+ style: DIALOG_INPUT_STYLE,
1438
+ "data-testid": "cs-data-validation-operand1",
1439
+ type: operandType,
1440
+ value: state.operand1,
1441
+ onChange: (e) => update("operand1", e.target.value)
1442
+ }
1443
+ )
1444
+ ] }),
1445
+ showSecondOperand && /* @__PURE__ */ jsxs6("label", { style: DIALOG_FIELD_STYLE, children: [
1446
+ /* @__PURE__ */ jsx7("span", { style: DIALOG_LABEL_STYLE, children: "Maximum" }),
1447
+ /* @__PURE__ */ jsx7(
1448
+ "input",
1449
+ {
1450
+ style: DIALOG_INPUT_STYLE,
1451
+ "data-testid": "cs-data-validation-operand2",
1452
+ type: operandType,
1453
+ value: state.operand2,
1454
+ onChange: (e) => update("operand2", e.target.value)
1455
+ }
1456
+ )
1457
+ ] })
1458
+ ] })
1459
+ ] }),
1460
+ state.ruleType === "checkbox" && /* @__PURE__ */ jsx7("div", { style: RANGE_NOTE_STYLE, children: "Each cell in the selection becomes a checkbox (checked = TRUE)." }),
1461
+ /* @__PURE__ */ jsxs6("label", { style: CHECK_STYLE2, "data-testid": "cs-data-validation-ignore-blank-label", children: [
1462
+ /* @__PURE__ */ jsx7(
1463
+ "input",
1464
+ {
1465
+ type: "checkbox",
1466
+ "data-testid": "cs-data-validation-ignore-blank",
1467
+ checked: state.ignoreBlank,
1468
+ onChange: (e) => update("ignoreBlank", e.target.checked)
1469
+ }
1470
+ ),
1471
+ /* @__PURE__ */ jsx7("span", { children: "Ignore blank cells" })
1472
+ ] }),
1473
+ /* @__PURE__ */ jsxs6("label", { style: CHECK_STYLE2, children: [
1474
+ /* @__PURE__ */ jsx7(
1475
+ "input",
1476
+ {
1477
+ type: "checkbox",
1478
+ "data-testid": "cs-data-validation-show-input",
1479
+ checked: state.showInputMessage,
1480
+ onChange: (e) => update("showInputMessage", e.target.checked)
1481
+ }
1482
+ ),
1483
+ /* @__PURE__ */ jsx7("span", { children: "Show input message" })
1484
+ ] }),
1485
+ state.showInputMessage && /* @__PURE__ */ jsxs6("label", { style: DIALOG_FIELD_STYLE, children: [
1486
+ /* @__PURE__ */ jsx7("span", { style: DIALOG_LABEL_STYLE, children: "Input message" }),
1487
+ /* @__PURE__ */ jsx7(
1488
+ "input",
1489
+ {
1490
+ style: DIALOG_INPUT_STYLE,
1491
+ "data-testid": "cs-data-validation-input-message",
1492
+ value: state.inputMessage,
1493
+ onChange: (e) => update("inputMessage", e.target.value)
1494
+ }
1495
+ )
1496
+ ] }),
1497
+ /* @__PURE__ */ jsxs6("label", { style: CHECK_STYLE2, children: [
1498
+ /* @__PURE__ */ jsx7(
1499
+ "input",
1500
+ {
1501
+ type: "checkbox",
1502
+ "data-testid": "cs-data-validation-show-error",
1503
+ checked: state.showErrorMessage,
1504
+ onChange: (e) => update("showErrorMessage", e.target.checked)
1505
+ }
1506
+ ),
1507
+ /* @__PURE__ */ jsx7("span", { children: "Show error message on invalid input" })
1508
+ ] }),
1509
+ state.showErrorMessage && /* @__PURE__ */ jsxs6("label", { style: DIALOG_FIELD_STYLE, children: [
1510
+ /* @__PURE__ */ jsx7("span", { style: DIALOG_LABEL_STYLE, children: "Error message" }),
1511
+ /* @__PURE__ */ jsx7(
1512
+ "input",
1513
+ {
1514
+ style: DIALOG_INPUT_STYLE,
1515
+ "data-testid": "cs-data-validation-error-message",
1516
+ value: state.errorMessage,
1517
+ onChange: (e) => update("errorMessage", e.target.value)
1518
+ }
1519
+ )
1520
+ ] })
1521
+ ]
1522
+ }
1523
+ );
1524
+ }
1525
+
1526
+ // src/chrome/ConditionalFormattingDialog.tsx
1527
+ import { useMemo as useMemo3, useState as useState6 } from "react";
1528
+ import "@univerjs/sheets-conditional-formatting/facade";
1529
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1530
+ var RULE_TYPE_OPTIONS2 = [
1531
+ { value: "cellValue", label: "Cell value" },
1532
+ { value: "textContains", label: "Text contains" },
1533
+ { value: "topN", label: "Top N" },
1534
+ { value: "bottomN", label: "Bottom N" },
1535
+ { value: "colorScale", label: "Color scale" }
1536
+ ];
1537
+ var OPERATOR_OPTIONS2 = [
1538
+ { value: "greater", label: "Greater than" },
1539
+ { value: "greaterEqual", label: "Greater than or equal to" },
1540
+ { value: "less", label: "Less than" },
1541
+ { value: "lessEqual", label: "Less than or equal to" },
1542
+ { value: "equal", label: "Equal to" },
1543
+ { value: "notEqual", label: "Not equal to" },
1544
+ { value: "between", label: "Between" },
1545
+ { value: "notBetween", label: "Not between" }
1546
+ ];
1547
+ function isRangeOperator2(op) {
1548
+ return op === "between" || op === "notBetween";
1549
+ }
1550
+ var INITIAL_STATE2 = {
1551
+ ruleType: "cellValue",
1552
+ operator: "greater",
1553
+ operand1: "",
1554
+ operand2: "",
1555
+ text: "",
1556
+ rankN: "10",
1557
+ rankPercent: false,
1558
+ fillColor: "#fce8b2",
1559
+ textColor: "#7f6000",
1560
+ scaleMinColor: "#ffffff",
1561
+ scaleMaxColor: "#57bb8a"
1562
+ };
1563
+ function activeRange3(api) {
1564
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
1565
+ }
1566
+ function activeSheet(api) {
1567
+ return api.univer.getActiveWorkbook()?.getActiveSheet() ?? null;
1568
+ }
1569
+ function usesHighlight(type) {
1570
+ return type !== "colorScale";
1571
+ }
1572
+ function applyRule(api, s) {
1573
+ const range = activeRange3(api);
1574
+ const sheet = activeSheet(api);
1575
+ if (!range || !sheet) return false;
1576
+ const cfSheet = sheet;
1577
+ const iRange = range.getRange();
1578
+ const n1 = Number(s.operand1);
1579
+ const n2 = Number(s.operand2);
1580
+ const rankN = Number(s.rankN);
1581
+ let builder = cfSheet.newConditionalFormattingRule();
1582
+ switch (s.ruleType) {
1583
+ case "cellValue": {
1584
+ if (!Number.isFinite(n1)) return false;
1585
+ switch (s.operator) {
1586
+ case "greater":
1587
+ builder = builder.whenNumberGreaterThan(n1);
1588
+ break;
1589
+ case "greaterEqual":
1590
+ builder = builder.whenNumberGreaterThanOrEqualTo(n1);
1591
+ break;
1592
+ case "less":
1593
+ builder = builder.whenNumberLessThan(n1);
1594
+ break;
1595
+ case "lessEqual":
1596
+ builder = builder.whenNumberLessThanOrEqualTo(n1);
1597
+ break;
1598
+ case "equal":
1599
+ builder = builder.whenNumberEqualTo(n1);
1600
+ break;
1601
+ case "notEqual":
1602
+ builder = builder.whenNumberNotEqualTo(n1);
1603
+ break;
1604
+ case "between":
1605
+ if (!Number.isFinite(n2)) return false;
1606
+ builder = builder.whenNumberBetween(n1, n2);
1607
+ break;
1608
+ case "notBetween":
1609
+ if (!Number.isFinite(n2)) return false;
1610
+ builder = builder.whenNumberNotBetween(n1, n2);
1611
+ break;
1612
+ }
1613
+ break;
1614
+ }
1615
+ case "textContains": {
1616
+ const text = s.text.trim();
1617
+ if (text.length === 0) return false;
1618
+ builder = builder.whenTextContains(text);
1619
+ break;
1620
+ }
1621
+ case "topN":
1622
+ case "bottomN": {
1623
+ if (!Number.isFinite(rankN) || rankN <= 0) return false;
1624
+ builder = builder.setRank({
1625
+ isBottom: s.ruleType === "bottomN",
1626
+ isPercent: s.rankPercent,
1627
+ value: rankN
1628
+ });
1629
+ break;
1630
+ }
1631
+ case "colorScale": {
1632
+ builder = builder.setColorScale([
1633
+ { index: 0, color: s.scaleMinColor, value: { type: "min" } },
1634
+ { index: 1, color: s.scaleMaxColor, value: { type: "max" } }
1635
+ ]);
1636
+ break;
1637
+ }
1638
+ }
1639
+ if (usesHighlight(s.ruleType)) {
1640
+ builder = builder.setBackground(s.fillColor);
1641
+ builder = builder.setFontColor(s.textColor);
1642
+ }
1643
+ const rule = builder.setRanges([iRange]).build();
1644
+ cfSheet.addConditionalFormattingRule(rule);
1645
+ return true;
1646
+ }
1647
+ var RANGE_NOTE_STYLE2 = {
1648
+ fontSize: 12,
1649
+ color: "var(--cs-chrome-muted, #605e5c)",
1650
+ marginBottom: 12
1651
+ };
1652
+ var CHECK_STYLE3 = {
1653
+ display: "flex",
1654
+ alignItems: "center",
1655
+ gap: 6,
1656
+ marginBottom: 8,
1657
+ cursor: "pointer"
1658
+ };
1659
+ var COLOR_INPUT_STYLE2 = {
1660
+ width: 48,
1661
+ height: 30,
1662
+ padding: 2,
1663
+ border: "1px solid var(--cs-chrome-border, #cdd3db)",
1664
+ borderRadius: 6,
1665
+ background: "var(--cs-chrome-input-bg, #fff)",
1666
+ cursor: "pointer"
1667
+ };
1668
+ var TWO_COL_STYLE2 = {
1669
+ display: "grid",
1670
+ gridTemplateColumns: "1fr 1fr",
1671
+ gap: 8
1672
+ };
1673
+ function ConditionalFormattingDialog({ api, onClose }) {
1674
+ const [state, setState] = useState6(INITIAL_STATE2);
1675
+ const rangeLabel = useMemo3(() => {
1676
+ const fRange = activeRange3(api);
1677
+ return fRange?.getA1Notation?.() ?? null;
1678
+ }, [api]);
1679
+ const hasSelection = activeRange3(api) !== null;
1680
+ const update = (key, value) => setState((prev) => ({ ...prev, [key]: value }));
1681
+ const apply = () => {
1682
+ if (applyRule(api, state)) onClose();
1683
+ };
1684
+ const clearRules = () => {
1685
+ const sheet = activeSheet(api);
1686
+ sheet?.clearConditionalFormatRules?.();
1687
+ onClose();
1688
+ };
1689
+ const showOperator = state.ruleType === "cellValue";
1690
+ const showSecondOperand = showOperator && isRangeOperator2(state.operator);
1691
+ const isRank = state.ruleType === "topN" || state.ruleType === "bottomN";
1692
+ return /* @__PURE__ */ jsxs7(
1693
+ Dialog,
1694
+ {
1695
+ title: "Conditional formatting",
1696
+ onClose,
1697
+ width: 440,
1698
+ "data-testid": "cs-conditional-formatting-dialog",
1699
+ footer: /* @__PURE__ */ jsxs7(Fragment3, { children: [
1700
+ /* @__PURE__ */ jsx8(
1701
+ "button",
1702
+ {
1703
+ type: "button",
1704
+ style: DIALOG_BTN_SECONDARY_STYLE,
1705
+ "data-testid": "cs-conditional-formatting-clear",
1706
+ onClick: clearRules,
1707
+ children: "Clear rules"
1708
+ }
1709
+ ),
1710
+ /* @__PURE__ */ jsx8("span", { style: { flex: 1 } }),
1711
+ /* @__PURE__ */ jsx8("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
1712
+ /* @__PURE__ */ jsx8(
1713
+ "button",
1714
+ {
1715
+ type: "button",
1716
+ style: DIALOG_BTN_PRIMARY_STYLE,
1717
+ "data-testid": "cs-conditional-formatting-apply",
1718
+ disabled: !hasSelection,
1719
+ onClick: apply,
1720
+ children: "Apply"
1721
+ }
1722
+ )
1723
+ ] }),
1724
+ children: [
1725
+ hasSelection ? /* @__PURE__ */ jsxs7("div", { style: RANGE_NOTE_STYLE2, "data-testid": "cs-conditional-formatting-range", children: [
1726
+ "Applies to ",
1727
+ /* @__PURE__ */ jsx8("strong", { children: rangeLabel ?? "the current selection" })
1728
+ ] }) : /* @__PURE__ */ jsx8("div", { style: RANGE_NOTE_STYLE2, "data-testid": "cs-conditional-formatting-no-selection", children: "Select one or more cells first, then reopen this dialog." }),
1729
+ /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1730
+ /* @__PURE__ */ jsx8("span", { style: DIALOG_LABEL_STYLE, children: "Condition type" }),
1731
+ /* @__PURE__ */ jsx8(
1732
+ "select",
1733
+ {
1734
+ style: DIALOG_INPUT_STYLE,
1735
+ "data-testid": "cs-conditional-formatting-type",
1736
+ value: state.ruleType,
1737
+ onChange: (e) => update("ruleType", e.target.value),
1738
+ children: RULE_TYPE_OPTIONS2.map((opt) => /* @__PURE__ */ jsx8("option", { value: opt.value, children: opt.label }, opt.value))
1739
+ }
1740
+ )
1741
+ ] }),
1742
+ showOperator && /* @__PURE__ */ jsxs7(Fragment3, { children: [
1743
+ /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1744
+ /* @__PURE__ */ jsx8("span", { style: DIALOG_LABEL_STYLE, children: "Condition" }),
1745
+ /* @__PURE__ */ jsx8(
1746
+ "select",
1747
+ {
1748
+ style: DIALOG_INPUT_STYLE,
1749
+ "data-testid": "cs-conditional-formatting-operator",
1750
+ value: state.operator,
1751
+ onChange: (e) => update("operator", e.target.value),
1752
+ children: OPERATOR_OPTIONS2.map((opt) => /* @__PURE__ */ jsx8("option", { value: opt.value, children: opt.label }, opt.value))
1753
+ }
1754
+ )
1755
+ ] }),
1756
+ /* @__PURE__ */ jsxs7("div", { style: showSecondOperand ? TWO_COL_STYLE2 : void 0, children: [
1757
+ /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1758
+ /* @__PURE__ */ jsx8("span", { style: DIALOG_LABEL_STYLE, children: showSecondOperand ? "Minimum" : "Value" }),
1759
+ /* @__PURE__ */ jsx8(
1760
+ "input",
1761
+ {
1762
+ style: DIALOG_INPUT_STYLE,
1763
+ "data-testid": "cs-conditional-formatting-operand1",
1764
+ type: "number",
1765
+ value: state.operand1,
1766
+ onChange: (e) => update("operand1", e.target.value)
1767
+ }
1768
+ )
1769
+ ] }),
1770
+ showSecondOperand && /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1771
+ /* @__PURE__ */ jsx8("span", { style: DIALOG_LABEL_STYLE, children: "Maximum" }),
1772
+ /* @__PURE__ */ jsx8(
1773
+ "input",
1774
+ {
1775
+ style: DIALOG_INPUT_STYLE,
1776
+ "data-testid": "cs-conditional-formatting-operand2",
1777
+ type: "number",
1778
+ value: state.operand2,
1779
+ onChange: (e) => update("operand2", e.target.value)
1780
+ }
1781
+ )
1782
+ ] })
1783
+ ] })
1784
+ ] }),
1785
+ state.ruleType === "textContains" && /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1786
+ /* @__PURE__ */ jsx8("span", { style: DIALOG_LABEL_STYLE, children: "Text contains" }),
1787
+ /* @__PURE__ */ jsx8(
1788
+ "input",
1789
+ {
1790
+ style: DIALOG_INPUT_STYLE,
1791
+ "data-testid": "cs-conditional-formatting-text",
1792
+ value: state.text,
1793
+ placeholder: "e.g. urgent",
1794
+ onChange: (e) => update("text", e.target.value)
1795
+ }
1796
+ )
1797
+ ] }),
1798
+ isRank && /* @__PURE__ */ jsxs7(Fragment3, { children: [
1799
+ /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1800
+ /* @__PURE__ */ jsxs7("span", { style: DIALOG_LABEL_STYLE, children: [
1801
+ state.ruleType === "topN" ? "Top" : "Bottom",
1802
+ " ",
1803
+ state.rankPercent ? "percent" : "count"
1804
+ ] }),
1805
+ /* @__PURE__ */ jsx8(
1806
+ "input",
1807
+ {
1808
+ style: DIALOG_INPUT_STYLE,
1809
+ "data-testid": "cs-conditional-formatting-rank-n",
1810
+ type: "number",
1811
+ min: 1,
1812
+ value: state.rankN,
1813
+ onChange: (e) => update("rankN", e.target.value)
1814
+ }
1815
+ )
1816
+ ] }),
1817
+ /* @__PURE__ */ jsxs7("label", { style: CHECK_STYLE3, children: [
1818
+ /* @__PURE__ */ jsx8(
1819
+ "input",
1820
+ {
1821
+ type: "checkbox",
1822
+ "data-testid": "cs-conditional-formatting-rank-percent",
1823
+ checked: state.rankPercent,
1824
+ onChange: (e) => update("rankPercent", e.target.checked)
1825
+ }
1826
+ ),
1827
+ /* @__PURE__ */ jsx8("span", { children: "Interpret as percent" })
1828
+ ] })
1829
+ ] }),
1830
+ state.ruleType === "colorScale" ? /* @__PURE__ */ jsxs7("div", { style: TWO_COL_STYLE2, children: [
1831
+ /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1832
+ /* @__PURE__ */ jsx8("span", { style: DIALOG_LABEL_STYLE, children: "Min color" }),
1833
+ /* @__PURE__ */ jsx8(
1834
+ "input",
1835
+ {
1836
+ style: COLOR_INPUT_STYLE2,
1837
+ "data-testid": "cs-conditional-formatting-scale-min",
1838
+ type: "color",
1839
+ value: state.scaleMinColor,
1840
+ onChange: (e) => update("scaleMinColor", e.target.value)
1841
+ }
1842
+ )
1843
+ ] }),
1844
+ /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1845
+ /* @__PURE__ */ jsx8("span", { style: DIALOG_LABEL_STYLE, children: "Max color" }),
1846
+ /* @__PURE__ */ jsx8(
1847
+ "input",
1848
+ {
1849
+ style: COLOR_INPUT_STYLE2,
1850
+ "data-testid": "cs-conditional-formatting-scale-max",
1851
+ type: "color",
1852
+ value: state.scaleMaxColor,
1853
+ onChange: (e) => update("scaleMaxColor", e.target.value)
1854
+ }
1855
+ )
1856
+ ] })
1857
+ ] }) : /* @__PURE__ */ jsxs7("div", { style: TWO_COL_STYLE2, children: [
1858
+ /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1859
+ /* @__PURE__ */ jsx8("span", { style: DIALOG_LABEL_STYLE, children: "Fill color" }),
1860
+ /* @__PURE__ */ jsx8(
1861
+ "input",
1862
+ {
1863
+ style: COLOR_INPUT_STYLE2,
1864
+ "data-testid": "cs-conditional-formatting-fill-color",
1865
+ type: "color",
1866
+ value: state.fillColor,
1867
+ onChange: (e) => update("fillColor", e.target.value)
1868
+ }
1869
+ )
1870
+ ] }),
1871
+ /* @__PURE__ */ jsxs7("label", { style: DIALOG_FIELD_STYLE, children: [
1872
+ /* @__PURE__ */ jsx8("span", { style: DIALOG_LABEL_STYLE, children: "Text color" }),
1873
+ /* @__PURE__ */ jsx8(
1874
+ "input",
1875
+ {
1876
+ style: COLOR_INPUT_STYLE2,
1877
+ "data-testid": "cs-conditional-formatting-text-color",
1878
+ type: "color",
1879
+ value: state.textColor,
1880
+ onChange: (e) => update("textColor", e.target.value)
1881
+ }
1882
+ )
1883
+ ] })
1884
+ ] })
1885
+ ]
1886
+ }
1887
+ );
1888
+ }
1889
+
1890
+ // src/chrome/CustomSortDialog.tsx
1891
+ import { useMemo as useMemo4, useState as useState7 } from "react";
1892
+ import "@univerjs/sheets-sort/facade";
1893
+ import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1894
+ function activeRange4(api) {
1895
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
1896
+ }
1897
+ function columnLetter(index) {
1898
+ let n = index;
1899
+ let label = "";
1900
+ do {
1901
+ label = String.fromCharCode(65 + n % 26) + label;
1902
+ n = Math.floor(n / 26) - 1;
1903
+ } while (n >= 0);
1904
+ return label;
1905
+ }
1906
+ function readRangeInfo(api) {
1907
+ const range = activeRange4(api);
1908
+ if (!range) return null;
1909
+ const values = range.getValues?.();
1910
+ return {
1911
+ startRow: range.getRow(),
1912
+ startColumn: range.getColumn(),
1913
+ width: range.getWidth(),
1914
+ height: range.getHeight(),
1915
+ a1: range.getA1Notation?.() ?? null,
1916
+ firstRow: values && values.length > 0 ? values[0] : null
1917
+ };
1918
+ }
1919
+ function applySort(api, info, levels, hasHeader) {
1920
+ const worksheet = api.univer.getActiveWorkbook()?.getActiveSheet();
1921
+ if (!worksheet) return false;
1922
+ const bandStartRow = hasHeader ? info.startRow + 1 : info.startRow;
1923
+ const bandHeight = hasHeader ? info.height - 1 : info.height;
1924
+ if (bandHeight <= 0) return false;
1925
+ const band = worksheet.getRange(bandStartRow, info.startColumn, bandHeight, info.width);
1926
+ const specs = levels.filter((l) => l.column >= 0 && l.column < info.width).map((l) => ({ column: l.column, ascending: l.ascending }));
1927
+ if (specs.length === 0) return false;
1928
+ band.sort(specs);
1929
+ return true;
1930
+ }
1931
+ var RANGE_NOTE_STYLE3 = {
1932
+ fontSize: 12,
1933
+ color: "var(--cs-chrome-muted, #605e5c)",
1934
+ marginBottom: 12
1935
+ };
1936
+ var CHECK_STYLE4 = {
1937
+ display: "flex",
1938
+ alignItems: "center",
1939
+ gap: 6,
1940
+ marginBottom: 12,
1941
+ cursor: "pointer"
1942
+ };
1943
+ var LEVEL_ROW_STYLE = {
1944
+ display: "grid",
1945
+ gridTemplateColumns: "auto 1fr 130px 28px",
1946
+ alignItems: "center",
1947
+ gap: 8,
1948
+ marginBottom: 8
1949
+ };
1950
+ var LEVEL_PREFIX_STYLE = {
1951
+ fontSize: 12,
1952
+ color: "var(--cs-chrome-muted, #605e5c)",
1953
+ whiteSpace: "nowrap"
1954
+ };
1955
+ var REMOVE_BTN_STYLE = {
1956
+ width: 28,
1957
+ height: 30,
1958
+ display: "inline-flex",
1959
+ alignItems: "center",
1960
+ justifyContent: "center",
1961
+ border: "1px solid var(--cs-chrome-border, #cdd3db)",
1962
+ borderRadius: 6,
1963
+ background: "var(--cs-chrome-input-bg, #fff)",
1964
+ color: "var(--cs-chrome-muted, #605e5c)",
1965
+ cursor: "pointer",
1966
+ padding: 0,
1967
+ fontSize: 16,
1968
+ lineHeight: 1
1969
+ };
1970
+ var ADD_BTN_STYLE = {
1971
+ ...DIALOG_BTN_SECONDARY_STYLE,
1972
+ marginTop: 4
1973
+ };
1974
+ function CustomSortDialog({ api, onClose }) {
1975
+ const info = useMemo4(() => readRangeInfo(api), [api]);
1976
+ const hasSelection = info !== null;
1977
+ const width = info?.width ?? 1;
1978
+ const [hasHeader, setHasHeader] = useState7(false);
1979
+ const [levels, setLevels] = useState7([{ column: 0, ascending: true }]);
1980
+ const columnOptions = useMemo4(() => {
1981
+ const startCol = info?.startColumn ?? 0;
1982
+ return Array.from({ length: width }, (_, offset) => {
1983
+ const headerCell = hasHeader ? info?.firstRow?.[offset] : void 0;
1984
+ const headerText = headerCell !== void 0 && headerCell !== null && String(headerCell).trim() !== "" ? String(headerCell) : null;
1985
+ const letter = columnLetter(startCol + offset);
1986
+ return {
1987
+ value: offset,
1988
+ label: headerText ? `${headerText} (${letter})` : `Column ${letter}`
1989
+ };
1990
+ });
1991
+ }, [width, hasHeader, info]);
1992
+ const updateLevel = (index, patch) => setLevels((prev) => prev.map((l, i) => i === index ? { ...l, ...patch } : l));
1993
+ const addLevel = () => {
1994
+ const used = new Set(levels.map((l) => l.column));
1995
+ let next = 0;
1996
+ for (let c = 0; c < width; c += 1) {
1997
+ if (!used.has(c)) {
1998
+ next = c;
1999
+ break;
2000
+ }
2001
+ }
2002
+ setLevels((prev) => [...prev, { column: next, ascending: true }]);
2003
+ };
2004
+ const removeLevel = (index) => setLevels((prev) => prev.length <= 1 ? prev : prev.filter((_, i) => i !== index));
2005
+ const apply = () => {
2006
+ if (info && applySort(api, info, levels, hasHeader)) onClose();
2007
+ };
2008
+ const canApply = hasSelection && levels.length > 0;
2009
+ return /* @__PURE__ */ jsxs8(
2010
+ Dialog,
2011
+ {
2012
+ title: "Sort range",
2013
+ onClose,
2014
+ width: 480,
2015
+ "data-testid": "cs-custom-sort-dialog",
2016
+ footer: /* @__PURE__ */ jsxs8(Fragment4, { children: [
2017
+ /* @__PURE__ */ jsx9("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
2018
+ /* @__PURE__ */ jsx9(
2019
+ "button",
2020
+ {
2021
+ type: "button",
2022
+ style: DIALOG_BTN_PRIMARY_STYLE,
2023
+ "data-testid": "cs-custom-sort-apply",
2024
+ disabled: !canApply,
2025
+ onClick: apply,
2026
+ children: "Sort"
2027
+ }
2028
+ )
2029
+ ] }),
2030
+ children: [
2031
+ hasSelection ? /* @__PURE__ */ jsxs8("div", { style: RANGE_NOTE_STYLE3, "data-testid": "cs-custom-sort-range", children: [
2032
+ "Sort ",
2033
+ /* @__PURE__ */ jsx9("strong", { children: info?.a1 ?? "the current selection" })
2034
+ ] }) : /* @__PURE__ */ jsx9("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." }),
2035
+ /* @__PURE__ */ jsxs8("label", { style: CHECK_STYLE4, "data-testid": "cs-custom-sort-has-header-label", children: [
2036
+ /* @__PURE__ */ jsx9(
2037
+ "input",
2038
+ {
2039
+ type: "checkbox",
2040
+ "data-testid": "cs-custom-sort-has-header",
2041
+ checked: hasHeader,
2042
+ onChange: (e) => setHasHeader(e.target.checked)
2043
+ }
2044
+ ),
2045
+ /* @__PURE__ */ jsx9("span", { children: "Data has header row" })
2046
+ ] }),
2047
+ /* @__PURE__ */ jsxs8("div", { style: DIALOG_FIELD_STYLE, children: [
2048
+ /* @__PURE__ */ jsx9("span", { style: DIALOG_LABEL_STYLE, children: "Sort by" }),
2049
+ levels.map((level, index) => /* @__PURE__ */ jsxs8("div", { style: LEVEL_ROW_STYLE, "data-testid": `cs-custom-sort-level-${index}`, children: [
2050
+ /* @__PURE__ */ jsx9("span", { style: LEVEL_PREFIX_STYLE, children: index === 0 ? "Sort by" : "then by" }),
2051
+ /* @__PURE__ */ jsx9(
2052
+ "select",
2053
+ {
2054
+ style: DIALOG_INPUT_STYLE,
2055
+ "data-testid": `cs-custom-sort-column-${index}`,
2056
+ value: level.column,
2057
+ onChange: (e) => updateLevel(index, { column: Number(e.target.value) }),
2058
+ children: columnOptions.map((opt) => /* @__PURE__ */ jsx9("option", { value: opt.value, children: opt.label }, opt.value))
2059
+ }
2060
+ ),
2061
+ /* @__PURE__ */ jsxs8(
2062
+ "select",
2063
+ {
2064
+ style: DIALOG_INPUT_STYLE,
2065
+ "data-testid": `cs-custom-sort-order-${index}`,
2066
+ value: level.ascending ? "asc" : "desc",
2067
+ onChange: (e) => updateLevel(index, { ascending: e.target.value === "asc" }),
2068
+ children: [
2069
+ /* @__PURE__ */ jsx9("option", { value: "asc", children: "A \u2192 Z (ascending)" }),
2070
+ /* @__PURE__ */ jsx9("option", { value: "desc", children: "Z \u2192 A (descending)" })
2071
+ ]
2072
+ }
2073
+ ),
2074
+ /* @__PURE__ */ jsx9(
2075
+ "button",
2076
+ {
2077
+ type: "button",
2078
+ style: REMOVE_BTN_STYLE,
2079
+ "data-testid": `cs-custom-sort-remove-${index}`,
2080
+ "aria-label": "Remove sort level",
2081
+ disabled: levels.length <= 1,
2082
+ onClick: () => removeLevel(index),
2083
+ children: "\u2212"
2084
+ }
2085
+ )
2086
+ ] }, index)),
2087
+ /* @__PURE__ */ jsx9(
2088
+ "button",
2089
+ {
2090
+ type: "button",
2091
+ style: ADD_BTN_STYLE,
2092
+ "data-testid": "cs-custom-sort-add-level",
2093
+ disabled: levels.length >= width,
2094
+ onClick: addLevel,
2095
+ children: "Add another sort level"
2096
+ }
2097
+ )
2098
+ ] })
2099
+ ]
2100
+ }
2101
+ );
2102
+ }
2103
+
2104
+ // src/chrome/PasteSpecialDialog.tsx
2105
+ import { useMemo as useMemo5, useState as useState8 } from "react";
2106
+ import "@univerjs/sheets-ui/facade";
2107
+ import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2108
+ var MODE_OPTIONS = [
2109
+ {
2110
+ value: "values",
2111
+ label: "Values only",
2112
+ hint: "Paste cell values, dropping formatting and formulas."
2113
+ },
2114
+ {
2115
+ value: "formats",
2116
+ label: "Formats only",
2117
+ hint: "Paste number formats, fonts, borders and fills \u2014 no values."
2118
+ },
2119
+ {
2120
+ value: "formulas",
2121
+ label: "Formulas only",
2122
+ hint: "Paste formulas, adjusting relative references."
2123
+ },
2124
+ {
2125
+ value: "transpose",
2126
+ label: "Transpose",
2127
+ hint: "Flip the current selection \u2014 rows become columns and columns become rows, in place."
2128
+ }
2129
+ ];
2130
+ var PASTE_HOOK = {
2131
+ values: "special-paste-value",
2132
+ formats: "special-paste-format",
2133
+ formulas: "special-paste-formula"
2134
+ };
2135
+ var SHEET_PASTE_COMMAND = "sheet.command.paste";
2136
+ function activeRange5(api) {
2137
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
2138
+ }
2139
+ function transposeSelection(api) {
2140
+ const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
2141
+ const range = sheet?.getActiveRange();
2142
+ if (!sheet || !range) return false;
2143
+ const rows = range.getHeight();
2144
+ const cols = range.getWidth();
2145
+ if (rows <= 0 || cols <= 0) return false;
2146
+ const values = range.getValues();
2147
+ const transposed = [];
2148
+ for (let c = 0; c < cols; c++) {
2149
+ const newRow = [];
2150
+ for (let r = 0; r < rows; r++) {
2151
+ newRow.push(values[r]?.[c] ?? null);
2152
+ }
2153
+ transposed.push(newRow);
2154
+ }
2155
+ const target = sheet.getRange(range.getRow(), range.getColumn(), cols, rows);
2156
+ target.setValues(transposed);
2157
+ return true;
2158
+ }
2159
+ async function applyPasteSpecial(api, mode) {
2160
+ if (activeRange5(api) === null) return false;
2161
+ if (mode === "transpose") {
2162
+ return transposeSelection(api);
2163
+ }
2164
+ return api.executeCommand(SHEET_PASTE_COMMAND, { value: PASTE_HOOK[mode] });
2165
+ }
2166
+ var MODE_RADIO_ROW_STYLE = {
2167
+ display: "flex",
2168
+ alignItems: "flex-start",
2169
+ gap: 8,
2170
+ padding: "8px 10px",
2171
+ border: "1px solid var(--cs-chrome-border, #cdd3db)",
2172
+ borderRadius: 6,
2173
+ marginBottom: 8,
2174
+ cursor: "pointer"
2175
+ };
2176
+ var MODE_RADIO_ROW_ACTIVE_STYLE = {
2177
+ ...MODE_RADIO_ROW_STYLE,
2178
+ borderColor: "var(--cs-chrome-active-fg, #0e7490)",
2179
+ background: "var(--cs-chrome-active-bg, rgba(14, 116, 144, 0.06))"
2180
+ };
2181
+ var MODE_LABEL_STYLE = {
2182
+ fontSize: 13,
2183
+ fontWeight: 500,
2184
+ color: "var(--cs-chrome-fg, #201f1e)"
2185
+ };
2186
+ var MODE_HINT_STYLE = {
2187
+ fontSize: 12,
2188
+ color: "var(--cs-chrome-muted, #605e5c)",
2189
+ marginTop: 2,
2190
+ lineHeight: 1.35
2191
+ };
2192
+ var RANGE_NOTE_STYLE4 = {
2193
+ fontSize: 12,
2194
+ color: "var(--cs-chrome-muted, #605e5c)",
2195
+ marginBottom: 12
2196
+ };
2197
+ function PasteSpecialDialog({ api, onClose }) {
2198
+ const [mode, setMode] = useState8("values");
2199
+ const rangeLabel = useMemo5(() => {
2200
+ const fRange = activeRange5(api);
2201
+ return fRange?.getA1Notation?.() ?? null;
2202
+ }, [api]);
2203
+ const hasSelection = activeRange5(api) !== null;
2204
+ const apply = () => {
2205
+ void applyPasteSpecial(api, mode).then((ok) => {
2206
+ if (ok) onClose();
2207
+ });
2208
+ };
2209
+ return /* @__PURE__ */ jsxs9(
2210
+ Dialog,
2211
+ {
2212
+ title: "Paste special",
2213
+ onClose,
2214
+ width: 440,
2215
+ "data-testid": "cs-paste-special-dialog",
2216
+ footer: /* @__PURE__ */ jsxs9(Fragment5, { children: [
2217
+ /* @__PURE__ */ jsx10("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
2218
+ /* @__PURE__ */ jsx10(
2219
+ "button",
2220
+ {
2221
+ type: "button",
2222
+ style: DIALOG_BTN_PRIMARY_STYLE,
2223
+ "data-testid": "cs-paste-special-apply",
2224
+ disabled: !hasSelection,
2225
+ onClick: apply,
2226
+ children: "Paste"
2227
+ }
2228
+ )
2229
+ ] }),
2230
+ children: [
2231
+ hasSelection ? /* @__PURE__ */ jsxs9("div", { style: RANGE_NOTE_STYLE4, "data-testid": "cs-paste-special-range", children: [
2232
+ mode === "transpose" ? "Transposes" : "Pastes into",
2233
+ " ",
2234
+ /* @__PURE__ */ jsx10("strong", { children: rangeLabel ?? "the current selection" })
2235
+ ] }) : /* @__PURE__ */ jsx10("div", { style: RANGE_NOTE_STYLE4, "data-testid": "cs-paste-special-no-selection", children: "Select the destination cell(s) first, then reopen this dialog." }),
2236
+ /* @__PURE__ */ jsxs9("div", { style: DIALOG_FIELD_STYLE, children: [
2237
+ /* @__PURE__ */ jsx10("span", { style: DIALOG_LABEL_STYLE, children: "Paste" }),
2238
+ /* @__PURE__ */ jsx10("div", { role: "radiogroup", "aria-label": "Paste special mode", children: MODE_OPTIONS.map((opt) => {
2239
+ const active = mode === opt.value;
2240
+ return /* @__PURE__ */ jsxs9(
2241
+ "label",
2242
+ {
2243
+ style: active ? MODE_RADIO_ROW_ACTIVE_STYLE : MODE_RADIO_ROW_STYLE,
2244
+ "data-testid": `cs-paste-special-mode-${opt.value}`,
2245
+ children: [
2246
+ /* @__PURE__ */ jsx10(
2247
+ "input",
2248
+ {
2249
+ type: "radio",
2250
+ name: "cs-paste-special-mode",
2251
+ value: opt.value,
2252
+ checked: active,
2253
+ onChange: () => setMode(opt.value),
2254
+ style: { marginTop: 2 }
2255
+ }
2256
+ ),
2257
+ /* @__PURE__ */ jsxs9("span", { children: [
2258
+ /* @__PURE__ */ jsx10("span", { style: MODE_LABEL_STYLE, children: opt.label }),
2259
+ /* @__PURE__ */ jsx10("span", { style: MODE_HINT_STYLE, children: opt.hint })
2260
+ ] })
2261
+ ]
2262
+ },
2263
+ opt.value
2264
+ );
2265
+ }) })
2266
+ ] })
2267
+ ]
2268
+ }
2269
+ );
2270
+ }
2271
+
2272
+ // src/chrome/InsertFunctionDialog.tsx
2273
+ import { useMemo as useMemo6, useState as useState9 } from "react";
2274
+ import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2275
+ var FUNCTIONS = [
2276
+ // Math
2277
+ {
2278
+ name: "SUM",
2279
+ category: "Math",
2280
+ description: "Sum of a set of numbers.",
2281
+ syntax: "SUM(value1, [value2, \u2026])"
2282
+ },
2283
+ {
2284
+ name: "PRODUCT",
2285
+ category: "Math",
2286
+ description: "Product of a set of numbers.",
2287
+ syntax: "PRODUCT(factor1, [factor2, \u2026])"
2288
+ },
2289
+ {
2290
+ name: "ROUND",
2291
+ category: "Math",
2292
+ description: "Round a number to a given number of places.",
2293
+ syntax: "ROUND(value, [places])"
2294
+ },
2295
+ {
2296
+ name: "ABS",
2297
+ category: "Math",
2298
+ description: "Absolute value of a number.",
2299
+ syntax: "ABS(value)"
2300
+ },
2301
+ {
2302
+ name: "MOD",
2303
+ category: "Math",
2304
+ description: "Remainder after division.",
2305
+ syntax: "MOD(dividend, divisor)"
2306
+ },
2307
+ {
2308
+ name: "POWER",
2309
+ category: "Math",
2310
+ description: "A number raised to a power.",
2311
+ syntax: "POWER(base, exponent)"
2312
+ },
2313
+ // Statistical
2314
+ {
2315
+ name: "AVERAGE",
2316
+ category: "Statistical",
2317
+ description: "Arithmetic mean of a set of numbers.",
2318
+ syntax: "AVERAGE(value1, [value2, \u2026])"
2319
+ },
2320
+ {
2321
+ name: "COUNT",
2322
+ category: "Statistical",
2323
+ description: "Count of numeric values in a range.",
2324
+ syntax: "COUNT(value1, [value2, \u2026])"
2325
+ },
2326
+ {
2327
+ name: "COUNTA",
2328
+ category: "Statistical",
2329
+ description: "Count of non-empty values in a range.",
2330
+ syntax: "COUNTA(value1, [value2, \u2026])"
2331
+ },
2332
+ {
2333
+ name: "MAX",
2334
+ category: "Statistical",
2335
+ description: "Largest value in a set.",
2336
+ syntax: "MAX(value1, [value2, \u2026])"
2337
+ },
2338
+ {
2339
+ name: "MIN",
2340
+ category: "Statistical",
2341
+ description: "Smallest value in a set.",
2342
+ syntax: "MIN(value1, [value2, \u2026])"
2343
+ },
2344
+ {
2345
+ name: "MEDIAN",
2346
+ category: "Statistical",
2347
+ description: "Median of a set of numbers.",
2348
+ syntax: "MEDIAN(value1, [value2, \u2026])"
2349
+ },
2350
+ // Logical
2351
+ {
2352
+ name: "IF",
2353
+ category: "Logical",
2354
+ description: "Return one value if a condition is true, another if false.",
2355
+ syntax: "IF(condition, value_if_true, value_if_false)"
2356
+ },
2357
+ {
2358
+ name: "IFS",
2359
+ category: "Logical",
2360
+ description: "Test multiple conditions, return the first match.",
2361
+ syntax: "IFS(condition1, value1, [condition2, value2, \u2026])"
2362
+ },
2363
+ {
2364
+ name: "AND",
2365
+ category: "Logical",
2366
+ description: "True when all arguments are true.",
2367
+ syntax: "AND(logical1, [logical2, \u2026])"
2368
+ },
2369
+ {
2370
+ name: "OR",
2371
+ category: "Logical",
2372
+ description: "True when any argument is true.",
2373
+ syntax: "OR(logical1, [logical2, \u2026])"
2374
+ },
2375
+ {
2376
+ name: "IFERROR",
2377
+ category: "Logical",
2378
+ description: "Return a fallback when a formula errors.",
2379
+ syntax: "IFERROR(value, value_if_error)"
2380
+ },
2381
+ // Lookup
2382
+ {
2383
+ name: "VLOOKUP",
2384
+ category: "Lookup",
2385
+ description: "Search a column for a key, return a value from the same row.",
2386
+ syntax: "VLOOKUP(search_key, range, index, [is_sorted])"
2387
+ },
2388
+ {
2389
+ name: "HLOOKUP",
2390
+ category: "Lookup",
2391
+ description: "Search a row for a key, return a value from the same column.",
2392
+ syntax: "HLOOKUP(search_key, range, index, [is_sorted])"
2393
+ },
2394
+ {
2395
+ name: "INDEX",
2396
+ category: "Lookup",
2397
+ description: "Value at a given row/column offset in a range.",
2398
+ syntax: "INDEX(reference, [row], [column])"
2399
+ },
2400
+ {
2401
+ name: "MATCH",
2402
+ category: "Lookup",
2403
+ description: "Position of a value within a range.",
2404
+ syntax: "MATCH(search_key, range, [search_type])"
2405
+ },
2406
+ {
2407
+ name: "XLOOKUP",
2408
+ category: "Lookup",
2409
+ description: "Search a range and return a corresponding value.",
2410
+ syntax: "XLOOKUP(search_key, lookup_range, result_range)"
2411
+ },
2412
+ // Text
2413
+ {
2414
+ name: "CONCATENATE",
2415
+ category: "Text",
2416
+ description: "Join strings end to end.",
2417
+ syntax: "CONCATENATE(string1, [string2, \u2026])"
2418
+ },
2419
+ {
2420
+ name: "LEFT",
2421
+ category: "Text",
2422
+ description: "Leftmost characters of a string.",
2423
+ syntax: "LEFT(string, [num_chars])"
2424
+ },
2425
+ {
2426
+ name: "RIGHT",
2427
+ category: "Text",
2428
+ description: "Rightmost characters of a string.",
2429
+ syntax: "RIGHT(string, [num_chars])"
2430
+ },
2431
+ {
2432
+ name: "MID",
2433
+ category: "Text",
2434
+ description: "Characters from the middle of a string.",
2435
+ syntax: "MID(string, start, length)"
2436
+ },
2437
+ { name: "LEN", category: "Text", description: "Length of a string.", syntax: "LEN(string)" },
2438
+ {
2439
+ name: "TRIM",
2440
+ category: "Text",
2441
+ description: "Remove leading/trailing/duplicate spaces.",
2442
+ syntax: "TRIM(string)"
2443
+ },
2444
+ // Date
2445
+ { name: "TODAY", category: "Date", description: "Today's date.", syntax: "TODAY()" },
2446
+ { name: "NOW", category: "Date", description: "Current date and time.", syntax: "NOW()" },
2447
+ {
2448
+ name: "DATE",
2449
+ category: "Date",
2450
+ description: "Build a date from year, month, day.",
2451
+ syntax: "DATE(year, month, day)"
2452
+ },
2453
+ {
2454
+ name: "DATEDIF",
2455
+ category: "Date",
2456
+ description: "Difference between two dates in a chosen unit.",
2457
+ syntax: "DATEDIF(start_date, end_date, unit)"
2458
+ }
2459
+ ];
2460
+ var CATEGORY_ORDER = ["Math", "Statistical", "Logical", "Lookup", "Text", "Date"];
2461
+ function activeRange6(api) {
2462
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
2463
+ }
2464
+ function insertFunction(api, fn) {
2465
+ const range = activeRange6(api);
2466
+ if (!range) return false;
2467
+ const zeroArg = fn.syntax.endsWith("()");
2468
+ const formula = zeroArg ? `=${fn.name}()` : `=${fn.name}(`;
2469
+ range.setValue(formula);
2470
+ api.focus();
2471
+ return true;
2472
+ }
2473
+ var SEARCH_STYLE = {
2474
+ ...DIALOG_INPUT_STYLE,
2475
+ width: "100%",
2476
+ marginBottom: 12
2477
+ };
2478
+ var RANGE_NOTE_STYLE5 = {
2479
+ fontSize: 12,
2480
+ color: "var(--cs-chrome-muted, #605e5c)",
2481
+ marginBottom: 12
2482
+ };
2483
+ var LIST_STYLE = {
2484
+ maxHeight: 280,
2485
+ overflow: "auto",
2486
+ border: "1px solid var(--cs-chrome-border, #edeff3)",
2487
+ borderRadius: 8
2488
+ };
2489
+ var GROUP_HEADER_STYLE = {
2490
+ position: "sticky",
2491
+ top: 0,
2492
+ padding: "6px 12px",
2493
+ fontSize: 11,
2494
+ fontWeight: 600,
2495
+ letterSpacing: 0.4,
2496
+ textTransform: "uppercase",
2497
+ color: "var(--cs-chrome-muted, #605e5c)",
2498
+ background: "var(--cs-chrome-input-bg, #fff)",
2499
+ borderBottom: "1px solid var(--cs-chrome-border, #edeff3)"
2500
+ };
2501
+ function itemStyle(selected) {
2502
+ return {
2503
+ display: "block",
2504
+ width: "100%",
2505
+ textAlign: "left",
2506
+ padding: "8px 12px",
2507
+ border: "none",
2508
+ borderBottom: "1px solid var(--cs-chrome-border, #f3f4f6)",
2509
+ background: selected ? "var(--cs-chrome-hover-bg, #eef6f8)" : "transparent",
2510
+ color: "var(--cs-chrome-fg, #201f1e)",
2511
+ font: "inherit",
2512
+ fontSize: 13,
2513
+ cursor: "pointer"
2514
+ };
2515
+ }
2516
+ var ITEM_NAME_STYLE = {
2517
+ fontWeight: 600,
2518
+ fontFamily: "var(--cs-chrome-mono, ui-monospace, SFMono-Regular, Menlo, monospace)"
2519
+ };
2520
+ var ITEM_DESC_STYLE = {
2521
+ fontSize: 12,
2522
+ color: "var(--cs-chrome-muted, #605e5c)",
2523
+ marginTop: 2
2524
+ };
2525
+ var PREVIEW_STYLE = {
2526
+ marginTop: 12,
2527
+ padding: "10px 12px",
2528
+ borderRadius: 8,
2529
+ background: "var(--cs-chrome-subtle-bg, #f6f8fa)",
2530
+ fontSize: 12,
2531
+ color: "var(--cs-chrome-fg, #201f1e)"
2532
+ };
2533
+ var PREVIEW_SYNTAX_STYLE = {
2534
+ fontFamily: "var(--cs-chrome-mono, ui-monospace, SFMono-Regular, Menlo, monospace)",
2535
+ fontWeight: 600,
2536
+ marginBottom: 4
2537
+ };
2538
+ function InsertFunctionDialog({ api, onClose }) {
2539
+ const [query, setQuery] = useState9("");
2540
+ const [selectedName, setSelectedName] = useState9(null);
2541
+ const rangeLabel = useMemo6(() => {
2542
+ const fRange = activeRange6(api);
2543
+ return fRange?.getA1Notation?.() ?? null;
2544
+ }, [api]);
2545
+ const hasSelection = activeRange6(api) !== null;
2546
+ const filtered = useMemo6(() => {
2547
+ const q = query.trim().toLowerCase();
2548
+ if (!q) return FUNCTIONS;
2549
+ return FUNCTIONS.filter(
2550
+ (fn) => fn.name.toLowerCase().includes(q) || fn.description.toLowerCase().includes(q) || fn.category.toLowerCase().includes(q)
2551
+ );
2552
+ }, [query]);
2553
+ const grouped = useMemo6(() => {
2554
+ const byCat = /* @__PURE__ */ new Map();
2555
+ for (const fn of filtered) {
2556
+ const list = byCat.get(fn.category);
2557
+ if (list) list.push(fn);
2558
+ else byCat.set(fn.category, [fn]);
2559
+ }
2560
+ return CATEGORY_ORDER.filter((c) => byCat.has(c)).map((c) => ({
2561
+ category: c,
2562
+ items: byCat.get(c)
2563
+ }));
2564
+ }, [filtered]);
2565
+ const selected = useMemo6(
2566
+ () => FUNCTIONS.find((fn) => fn.name === selectedName) ?? null,
2567
+ [selectedName]
2568
+ );
2569
+ const choose = (fn) => {
2570
+ if (insertFunction(api, fn)) onClose();
2571
+ };
2572
+ const insertSelected = () => {
2573
+ if (selected && insertFunction(api, selected)) onClose();
2574
+ };
2575
+ return /* @__PURE__ */ jsxs10(
2576
+ Dialog,
2577
+ {
2578
+ title: "Insert function",
2579
+ onClose,
2580
+ width: 460,
2581
+ "data-testid": "cs-insert-function-dialog",
2582
+ footer: /* @__PURE__ */ jsxs10(Fragment6, { children: [
2583
+ /* @__PURE__ */ jsx11("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
2584
+ /* @__PURE__ */ jsx11(
2585
+ "button",
2586
+ {
2587
+ type: "button",
2588
+ style: DIALOG_BTN_PRIMARY_STYLE,
2589
+ "data-testid": "cs-insert-function-insert",
2590
+ disabled: !hasSelection || !selected,
2591
+ onClick: insertSelected,
2592
+ children: "Insert"
2593
+ }
2594
+ )
2595
+ ] }),
2596
+ children: [
2597
+ hasSelection ? /* @__PURE__ */ jsxs10("div", { style: RANGE_NOTE_STYLE5, "data-testid": "cs-insert-function-range", children: [
2598
+ "Inserts into ",
2599
+ /* @__PURE__ */ jsx11("strong", { children: rangeLabel ?? "the active cell" })
2600
+ ] }) : /* @__PURE__ */ jsx11("div", { style: RANGE_NOTE_STYLE5, "data-testid": "cs-insert-function-no-selection", children: "Select a cell first, then reopen this dialog." }),
2601
+ /* @__PURE__ */ jsx11(
2602
+ "input",
2603
+ {
2604
+ style: SEARCH_STYLE,
2605
+ "data-testid": "cs-insert-function-search",
2606
+ type: "search",
2607
+ placeholder: "Search functions (name, category, or description)",
2608
+ value: query,
2609
+ autoFocus: true,
2610
+ onChange: (e) => setQuery(e.target.value)
2611
+ }
2612
+ ),
2613
+ /* @__PURE__ */ jsxs10(
2614
+ "div",
2615
+ {
2616
+ style: LIST_STYLE,
2617
+ role: "listbox",
2618
+ "aria-label": "Functions",
2619
+ "data-testid": "cs-insert-function-list",
2620
+ children: [
2621
+ grouped.length === 0 && /* @__PURE__ */ jsxs10("div", { style: { padding: "12px", fontSize: 13, color: "var(--cs-chrome-muted, #605e5c)" }, children: [
2622
+ "No functions match \u201C",
2623
+ query,
2624
+ "\u201D."
2625
+ ] }),
2626
+ grouped.map((group) => /* @__PURE__ */ jsxs10("div", { children: [
2627
+ /* @__PURE__ */ jsx11("div", { style: GROUP_HEADER_STYLE, children: group.category }),
2628
+ group.items.map((fn) => /* @__PURE__ */ jsxs10(
2629
+ "button",
2630
+ {
2631
+ type: "button",
2632
+ role: "option",
2633
+ "aria-selected": selectedName === fn.name,
2634
+ "data-testid": `cs-insert-function-item-${fn.name}`,
2635
+ style: itemStyle(selectedName === fn.name),
2636
+ onClick: () => setSelectedName(fn.name),
2637
+ onDoubleClick: () => choose(fn),
2638
+ children: [
2639
+ /* @__PURE__ */ jsx11("div", { style: ITEM_NAME_STYLE, children: fn.name }),
2640
+ /* @__PURE__ */ jsx11("div", { style: ITEM_DESC_STYLE, children: fn.description })
2641
+ ]
2642
+ },
2643
+ fn.name
2644
+ ))
2645
+ ] }, group.category))
2646
+ ]
2647
+ }
2648
+ ),
2649
+ selected && /* @__PURE__ */ jsxs10("div", { style: PREVIEW_STYLE, "data-testid": "cs-insert-function-preview", children: [
2650
+ /* @__PURE__ */ jsx11("div", { style: PREVIEW_SYNTAX_STYLE, children: selected.syntax }),
2651
+ /* @__PURE__ */ jsx11("div", { children: selected.description })
2652
+ ] })
2653
+ ]
2654
+ }
2655
+ );
2656
+ }
2657
+
2658
+ // src/chrome/NameManagerDialog.tsx
2659
+ import { useCallback, useMemo as useMemo7, useState as useState10 } from "react";
2660
+ import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2661
+ var NAME_RE = /^[A-Za-z_][A-Za-z0-9_.]*$/;
2662
+ function workbook(api) {
2663
+ return api.univer.getActiveWorkbook() ?? null;
2664
+ }
2665
+ function readRows(api) {
2666
+ const wb = workbook(api);
2667
+ if (!wb) return [];
2668
+ return wb.getDefinedNames().map((dn) => ({
2669
+ name: dn.getName(),
2670
+ refersTo: dn.getFormulaOrRefString()
2671
+ }));
2672
+ }
2673
+ function selectionRef(api) {
2674
+ const range = workbook(api)?.getActiveSheet()?.getActiveRange();
2675
+ return range?.getA1Notation(true) ?? "";
2676
+ }
2677
+ var ROW_STYLE4 = {
2678
+ display: "grid",
2679
+ gridTemplateColumns: "1fr 1.3fr auto",
2680
+ alignItems: "center",
2681
+ gap: 8,
2682
+ padding: "6px 8px",
2683
+ borderBottom: "1px solid var(--cs-chrome-border, #edeff3)"
2684
+ };
2685
+ var LIST_STYLE2 = {
2686
+ border: "1px solid var(--cs-chrome-border, #cdd3db)",
2687
+ borderRadius: 6,
2688
+ maxHeight: 200,
2689
+ overflow: "auto",
2690
+ marginBottom: 16
2691
+ };
2692
+ var EMPTY_STYLE = {
2693
+ padding: "16px 8px",
2694
+ fontSize: 13,
2695
+ color: "var(--cs-chrome-muted, #605e5c)",
2696
+ textAlign: "center"
2697
+ };
2698
+ var REF_CELL_STYLE = {
2699
+ fontSize: 12,
2700
+ color: "var(--cs-chrome-muted, #605e5c)",
2701
+ overflow: "hidden",
2702
+ textOverflow: "ellipsis",
2703
+ whiteSpace: "nowrap"
2704
+ };
2705
+ var ROW_ACTIONS_STYLE = {
2706
+ display: "flex",
2707
+ gap: 4
2708
+ };
2709
+ var SMALL_BTN_STYLE = {
2710
+ ...DIALOG_BTN_SECONDARY_STYLE,
2711
+ height: 24,
2712
+ padding: "0 8px",
2713
+ fontSize: 12
2714
+ };
2715
+ var SECTION_TITLE_STYLE = {
2716
+ fontSize: 13,
2717
+ fontWeight: 600,
2718
+ color: "var(--cs-chrome-fg, #201f1e)",
2719
+ margin: "0 0 8px"
2720
+ };
2721
+ var ERROR_STYLE = {
2722
+ fontSize: 12,
2723
+ color: "var(--cs-chrome-danger, #b91c1c)",
2724
+ marginBottom: 8
2725
+ };
2726
+ var TWO_COL_STYLE3 = {
2727
+ display: "grid",
2728
+ gridTemplateColumns: "1fr 1.3fr",
2729
+ gap: 8
2730
+ };
2731
+ function NameManagerDialog({ api, onClose }) {
2732
+ const [rows, setRows] = useState10(() => readRows(api));
2733
+ const [editingOriginal, setEditingOriginal] = useState10(null);
2734
+ const [nameInput, setNameInput] = useState10("");
2735
+ const [refInput, setRefInput] = useState10("");
2736
+ const [error, setError] = useState10(null);
2737
+ const initialSelRef = useMemo7(() => selectionRef(api), [api]);
2738
+ const refresh = useCallback(() => setRows(readRows(api)), [api]);
2739
+ const resetForm = useCallback(() => {
2740
+ setEditingOriginal(null);
2741
+ setNameInput("");
2742
+ setRefInput("");
2743
+ setError(null);
2744
+ }, []);
2745
+ const startEdit = (row) => {
2746
+ setEditingOriginal(row.name);
2747
+ setNameInput(row.name);
2748
+ setRefInput(row.refersTo);
2749
+ setError(null);
2750
+ };
2751
+ const useSelection = () => {
2752
+ const ref = selectionRef(api);
2753
+ if (ref) setRefInput(ref);
2754
+ };
2755
+ const remove = (row) => {
2756
+ const wb = workbook(api);
2757
+ if (!wb) return;
2758
+ wb.deleteDefinedName(row.name);
2759
+ if (editingOriginal === row.name) resetForm();
2760
+ refresh();
2761
+ };
2762
+ const submit = () => {
2763
+ const wb = workbook(api);
2764
+ if (!wb) {
2765
+ setError("No active workbook.");
2766
+ return;
2767
+ }
2768
+ const name = nameInput.trim();
2769
+ const ref = refInput.trim();
2770
+ if (!name) {
2771
+ setError("Enter a name.");
2772
+ return;
2773
+ }
2774
+ if (!NAME_RE.test(name)) {
2775
+ setError("Names must start with a letter or underscore and contain no spaces.");
2776
+ return;
2777
+ }
2778
+ if (!ref) {
2779
+ setError("Enter a range or formula (e.g. Sheet1!A1:B2).");
2780
+ return;
2781
+ }
2782
+ const collides = rows.some(
2783
+ (r) => r.name.toLowerCase() === name.toLowerCase() && r.name !== editingOriginal
2784
+ );
2785
+ if (collides) {
2786
+ setError(`A defined name "${name}" already exists.`);
2787
+ return;
2788
+ }
2789
+ if (editingOriginal === null) {
2790
+ wb.insertDefinedName(name, ref);
2791
+ } else {
2792
+ const existing = wb.getDefinedName(editingOriginal);
2793
+ if (existing) {
2794
+ const param = existing.toBuilder().setName(name).setRef(ref).build();
2795
+ wb.updateDefinedNameBuilder(param);
2796
+ } else {
2797
+ wb.insertDefinedName(name, ref);
2798
+ }
2799
+ }
2800
+ refresh();
2801
+ resetForm();
2802
+ };
2803
+ const isEditing = editingOriginal !== null;
2804
+ return /* @__PURE__ */ jsxs11(
2805
+ Dialog,
2806
+ {
2807
+ title: "Name manager",
2808
+ onClose,
2809
+ width: 480,
2810
+ "data-testid": "cs-name-manager-dialog",
2811
+ footer: /* @__PURE__ */ jsxs11(Fragment7, { children: [
2812
+ /* @__PURE__ */ jsx12("span", { style: { flex: 1 } }),
2813
+ /* @__PURE__ */ jsx12("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Close" })
2814
+ ] }),
2815
+ children: [
2816
+ /* @__PURE__ */ jsx12("h3", { style: SECTION_TITLE_STYLE, children: "Defined names" }),
2817
+ /* @__PURE__ */ jsx12("div", { style: LIST_STYLE2, "data-testid": "cs-name-manager-list", children: rows.length === 0 ? /* @__PURE__ */ jsx12("div", { style: EMPTY_STYLE, "data-testid": "cs-name-manager-empty", children: "No defined names yet. Add one below." }) : rows.map((row) => /* @__PURE__ */ jsxs11("div", { style: ROW_STYLE4, "data-testid": "cs-name-manager-row", children: [
2818
+ /* @__PURE__ */ jsx12("span", { style: { fontWeight: 500 }, children: row.name }),
2819
+ /* @__PURE__ */ jsx12("span", { style: REF_CELL_STYLE, title: row.refersTo, children: row.refersTo }),
2820
+ /* @__PURE__ */ jsxs11("span", { style: ROW_ACTIONS_STYLE, children: [
2821
+ /* @__PURE__ */ jsx12(
2822
+ "button",
2823
+ {
2824
+ type: "button",
2825
+ style: SMALL_BTN_STYLE,
2826
+ "data-testid": "cs-name-manager-edit",
2827
+ onClick: () => startEdit(row),
2828
+ children: "Edit"
2829
+ }
2830
+ ),
2831
+ /* @__PURE__ */ jsx12(
2832
+ "button",
2833
+ {
2834
+ type: "button",
2835
+ style: SMALL_BTN_STYLE,
2836
+ "data-testid": "cs-name-manager-delete",
2837
+ onClick: () => remove(row),
2838
+ children: "Delete"
2839
+ }
2840
+ )
2841
+ ] })
2842
+ ] }, row.name)) }),
2843
+ /* @__PURE__ */ jsx12("h3", { style: SECTION_TITLE_STYLE, children: isEditing ? "Edit name" : "Add a name" }),
2844
+ error && /* @__PURE__ */ jsx12("div", { style: ERROR_STYLE, "data-testid": "cs-name-manager-error", children: error }),
2845
+ /* @__PURE__ */ jsxs11("div", { style: TWO_COL_STYLE3, children: [
2846
+ /* @__PURE__ */ jsxs11("label", { style: DIALOG_FIELD_STYLE, children: [
2847
+ /* @__PURE__ */ jsx12("span", { style: DIALOG_LABEL_STYLE, children: "Name" }),
2848
+ /* @__PURE__ */ jsx12(
2849
+ "input",
2850
+ {
2851
+ style: DIALOG_INPUT_STYLE,
2852
+ "data-testid": "cs-name-manager-name",
2853
+ value: nameInput,
2854
+ placeholder: "MyRange",
2855
+ onChange: (e) => setNameInput(e.target.value)
2856
+ }
2857
+ )
2858
+ ] }),
2859
+ /* @__PURE__ */ jsxs11("label", { style: DIALOG_FIELD_STYLE, children: [
2860
+ /* @__PURE__ */ jsx12("span", { style: DIALOG_LABEL_STYLE, children: "Refers to" }),
2861
+ /* @__PURE__ */ jsx12(
2862
+ "input",
2863
+ {
2864
+ style: DIALOG_INPUT_STYLE,
2865
+ "data-testid": "cs-name-manager-ref",
2866
+ value: refInput,
2867
+ placeholder: initialSelRef || "Sheet1!A1:B2",
2868
+ onChange: (e) => setRefInput(e.target.value)
2869
+ }
2870
+ )
2871
+ ] })
2872
+ ] }),
2873
+ /* @__PURE__ */ jsxs11("div", { style: { display: "flex", gap: 8, marginTop: 4 }, children: [
2874
+ /* @__PURE__ */ jsx12(
2875
+ "button",
2876
+ {
2877
+ type: "button",
2878
+ style: DIALOG_BTN_SECONDARY_STYLE,
2879
+ "data-testid": "cs-name-manager-use-selection",
2880
+ onClick: useSelection,
2881
+ children: "Use selection"
2882
+ }
2883
+ ),
2884
+ /* @__PURE__ */ jsx12("span", { style: { flex: 1 } }),
2885
+ isEditing && /* @__PURE__ */ jsx12(
2886
+ "button",
2887
+ {
2888
+ type: "button",
2889
+ style: DIALOG_BTN_SECONDARY_STYLE,
2890
+ "data-testid": "cs-name-manager-cancel-edit",
2891
+ onClick: resetForm,
2892
+ children: "Cancel"
2893
+ }
2894
+ ),
2895
+ /* @__PURE__ */ jsx12(
2896
+ "button",
2897
+ {
2898
+ type: "button",
2899
+ style: DIALOG_BTN_PRIMARY_STYLE,
2900
+ "data-testid": "cs-name-manager-submit",
2901
+ onClick: submit,
2902
+ children: isEditing ? "Update" : "Add"
2903
+ }
2904
+ )
2905
+ ] })
2906
+ ]
2907
+ }
2908
+ );
2909
+ }
2910
+
2911
+ // src/chrome/InsertCellsDialog.tsx
2912
+ import { useMemo as useMemo8, useState as useState11 } from "react";
2913
+ import { Dimension } from "@univerjs/core";
2914
+ import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
2915
+ var SHIFT_OPTIONS = [
2916
+ { value: "right", label: "Shift cells right" },
2917
+ { value: "down", label: "Shift cells down" },
2918
+ { value: "row", label: "Entire row" },
2919
+ { value: "column", label: "Entire column" }
2920
+ ];
2921
+ function activeRange7(api) {
2922
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
2923
+ }
2924
+ function applyInsert(api, shift) {
2925
+ const range = activeRange7(api);
2926
+ if (!range) return false;
2927
+ switch (shift) {
2928
+ case "right":
2929
+ range.insertCells(Dimension.COLUMNS);
2930
+ return true;
2931
+ case "down":
2932
+ range.insertCells(Dimension.ROWS);
2933
+ return true;
2934
+ case "row": {
2935
+ const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
2936
+ if (!sheet) return false;
2937
+ const startRow = range.getRow();
2938
+ const rowCount = range.getLastRow() - startRow + 1;
2939
+ sheet.insertRows(startRow, rowCount);
2940
+ return true;
2941
+ }
2942
+ case "column": {
2943
+ const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
2944
+ if (!sheet) return false;
2945
+ const startColumn = range.getColumn();
2946
+ const colCount = range.getLastColumn() - startColumn + 1;
2947
+ sheet.insertColumns(startColumn, colCount);
2948
+ return true;
2949
+ }
2950
+ }
2951
+ }
2952
+ var RANGE_NOTE_STYLE6 = {
2953
+ fontSize: 12,
2954
+ color: "var(--cs-chrome-muted, #605e5c)",
2955
+ marginBottom: 14
2956
+ };
2957
+ var RADIO_STYLE = {
2958
+ display: "flex",
2959
+ alignItems: "center",
2960
+ gap: 8,
2961
+ marginBottom: 10,
2962
+ cursor: "pointer"
2963
+ };
2964
+ function InsertCellsDialog({ api, onClose }) {
2965
+ const [shift, setShift] = useState11("down");
2966
+ const rangeLabel = useMemo8(() => {
2967
+ const fRange = activeRange7(api);
2968
+ return fRange?.getA1Notation?.() ?? null;
2969
+ }, [api]);
2970
+ const hasSelection = activeRange7(api) !== null;
2971
+ const apply = () => {
2972
+ if (applyInsert(api, shift)) onClose();
2973
+ };
2974
+ return /* @__PURE__ */ jsxs12(
2975
+ Dialog,
2976
+ {
2977
+ title: "Insert cells",
2978
+ onClose,
2979
+ width: 380,
2980
+ "data-testid": "cs-insert-cells-dialog",
2981
+ footer: /* @__PURE__ */ jsxs12(Fragment8, { children: [
2982
+ /* @__PURE__ */ jsx13("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
2983
+ /* @__PURE__ */ jsx13(
2984
+ "button",
2985
+ {
2986
+ type: "button",
2987
+ style: DIALOG_BTN_PRIMARY_STYLE,
2988
+ "data-testid": "cs-insert-cells-apply",
2989
+ disabled: !hasSelection,
2990
+ onClick: apply,
2991
+ children: "Insert"
2992
+ }
2993
+ )
2994
+ ] }),
2995
+ children: [
2996
+ hasSelection ? /* @__PURE__ */ jsxs12("div", { style: RANGE_NOTE_STYLE6, "data-testid": "cs-insert-cells-range", children: [
2997
+ "Insert at ",
2998
+ /* @__PURE__ */ jsx13("strong", { children: rangeLabel ?? "the current selection" })
2999
+ ] }) : /* @__PURE__ */ jsx13("div", { style: RANGE_NOTE_STYLE6, "data-testid": "cs-insert-cells-no-selection", children: "Select one or more cells first, then reopen this dialog." }),
3000
+ /* @__PURE__ */ jsx13("div", { role: "radiogroup", "aria-label": "Shift direction", children: SHIFT_OPTIONS.map((opt) => /* @__PURE__ */ jsxs12(
3001
+ "label",
3002
+ {
3003
+ style: RADIO_STYLE,
3004
+ "data-testid": `cs-insert-cells-shift-${opt.value}-label`,
3005
+ children: [
3006
+ /* @__PURE__ */ jsx13(
3007
+ "input",
3008
+ {
3009
+ type: "radio",
3010
+ name: "cs-insert-cells-shift",
3011
+ "data-testid": `cs-insert-cells-shift-${opt.value}`,
3012
+ checked: shift === opt.value,
3013
+ onChange: () => setShift(opt.value)
3014
+ }
3015
+ ),
3016
+ /* @__PURE__ */ jsx13("span", { children: opt.label })
3017
+ ]
3018
+ },
3019
+ opt.value
3020
+ )) })
3021
+ ]
3022
+ }
3023
+ );
3024
+ }
3025
+
3026
+ // src/chrome/DeleteCellsDialog.tsx
3027
+ import { useMemo as useMemo9, useState as useState12 } from "react";
3028
+ import { Dimension as Dimension2 } from "@univerjs/core";
3029
+ import { Fragment as Fragment9, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
3030
+ var SHIFT_OPTIONS2 = [
3031
+ { value: "left", label: "Shift cells left" },
3032
+ { value: "up", label: "Shift cells up" },
3033
+ { value: "row", label: "Entire row" },
3034
+ { value: "column", label: "Entire column" }
3035
+ ];
3036
+ function activeRange8(api) {
3037
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
3038
+ }
3039
+ function applyDelete(api, choice) {
3040
+ const range = activeRange8(api);
3041
+ if (!range) return false;
3042
+ if (choice === "left") {
3043
+ range.deleteCells(Dimension2.COLUMNS);
3044
+ return true;
3045
+ }
3046
+ if (choice === "up") {
3047
+ range.deleteCells(Dimension2.ROWS);
3048
+ return true;
3049
+ }
3050
+ const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
3051
+ if (!sheet) return false;
3052
+ if (choice === "row") {
3053
+ const start2 = range.getRow();
3054
+ const count2 = range.getLastRow() - start2 + 1;
3055
+ if (count2 <= 0) return false;
3056
+ sheet.deleteRows(start2, count2);
3057
+ return true;
3058
+ }
3059
+ const start = range.getColumn();
3060
+ const count = range.getLastColumn() - start + 1;
3061
+ if (count <= 0) return false;
3062
+ sheet.deleteColumns(start, count);
3063
+ return true;
3064
+ }
3065
+ var RANGE_NOTE_STYLE7 = {
3066
+ fontSize: 12,
3067
+ color: "var(--cs-chrome-muted, #605e5c)",
3068
+ marginBottom: 12
3069
+ };
3070
+ var OPTION_STYLE = {
3071
+ display: "flex",
3072
+ alignItems: "center",
3073
+ gap: 8,
3074
+ padding: "6px 4px",
3075
+ cursor: "pointer"
3076
+ };
3077
+ function DeleteCellsDialog({ api, onClose }) {
3078
+ const [choice, setChoice] = useState12("left");
3079
+ const rangeLabel = useMemo9(() => {
3080
+ const fRange = activeRange8(api);
3081
+ return fRange?.getA1Notation?.() ?? null;
3082
+ }, [api]);
3083
+ const hasSelection = activeRange8(api) !== null;
3084
+ const apply = () => {
3085
+ if (applyDelete(api, choice)) onClose();
3086
+ };
3087
+ return /* @__PURE__ */ jsxs13(
3088
+ Dialog,
3089
+ {
3090
+ title: "Delete cells",
3091
+ onClose,
3092
+ width: 360,
3093
+ "data-testid": "cs-delete-cells-dialog",
3094
+ footer: /* @__PURE__ */ jsxs13(Fragment9, { children: [
3095
+ /* @__PURE__ */ jsx14("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
3096
+ /* @__PURE__ */ jsx14(
3097
+ "button",
3098
+ {
3099
+ type: "button",
3100
+ style: DIALOG_BTN_PRIMARY_STYLE,
3101
+ "data-testid": "cs-delete-cells-apply",
3102
+ disabled: !hasSelection,
3103
+ onClick: apply,
3104
+ children: "Delete"
3105
+ }
3106
+ )
3107
+ ] }),
3108
+ children: [
3109
+ hasSelection ? /* @__PURE__ */ jsxs13("div", { style: RANGE_NOTE_STYLE7, "data-testid": "cs-delete-cells-range", children: [
3110
+ "Delete ",
3111
+ /* @__PURE__ */ jsx14("strong", { children: rangeLabel ?? "the current selection" }),
3112
+ " and\u2026"
3113
+ ] }) : /* @__PURE__ */ jsx14("div", { style: RANGE_NOTE_STYLE7, "data-testid": "cs-delete-cells-no-selection", children: "Select one or more cells first, then reopen this dialog." }),
3114
+ /* @__PURE__ */ jsx14("div", { role: "radiogroup", "aria-label": "Delete option", children: SHIFT_OPTIONS2.map((opt) => /* @__PURE__ */ jsxs13("label", { style: OPTION_STYLE, children: [
3115
+ /* @__PURE__ */ jsx14(
3116
+ "input",
3117
+ {
3118
+ type: "radio",
3119
+ name: "cs-delete-cells-shift",
3120
+ "data-testid": `cs-delete-cells-${opt.value}`,
3121
+ value: opt.value,
3122
+ checked: choice === opt.value,
3123
+ onChange: () => setChoice(opt.value)
3124
+ }
3125
+ ),
3126
+ /* @__PURE__ */ jsx14("span", { children: opt.label })
3127
+ ] }, opt.value)) })
3128
+ ]
3129
+ }
3130
+ );
3131
+ }
3132
+
3133
+ // src/chrome/GoalSeekDialog.tsx
3134
+ import { useMemo as useMemo10, useState as useState13 } from "react";
3135
+ import "@univerjs/sheets-formula/facade";
3136
+ import { Fragment as Fragment10, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
3137
+ function getSolver(api) {
3138
+ const worksheet = api.univer.getActiveWorkbook()?.getActiveSheet() ?? null;
3139
+ if (!worksheet) return null;
3140
+ const formula = api.univer.getFormula?.();
3141
+ return {
3142
+ worksheet,
3143
+ settle: async () => {
3144
+ if (formula?.onCalculationEnd) {
3145
+ await formula.onCalculationEnd();
3146
+ return;
3147
+ }
3148
+ await new Promise((resolve) => {
3149
+ if (typeof requestAnimationFrame === "function") requestAnimationFrame(() => resolve());
3150
+ else setTimeout(resolve, 16);
3151
+ });
3152
+ }
3153
+ };
3154
+ }
3155
+ function toNumber(value) {
3156
+ if (typeof value === "number") return value;
3157
+ if (typeof value === "boolean") return value ? 1 : 0;
3158
+ if (typeof value === "string" && value.trim() !== "") return Number(value);
3159
+ return Number.NaN;
3160
+ }
3161
+ function isSingleCellA1(ref) {
3162
+ return /^[A-Za-z]{1,3}[1-9][0-9]*$/.test(ref.trim());
3163
+ }
3164
+ var INITIAL_STATE3 = { setCell: "", toValue: "", byChangingCell: "" };
3165
+ var TOLERANCE = 1e-6;
3166
+ var MAX_ITERATIONS = 100;
3167
+ async function goalSeek(solver, setCellRef, target, changeCellRef) {
3168
+ const setRange = solver.worksheet.getRange(setCellRef);
3169
+ const changeRange = solver.worksheet.getRange(changeCellRef);
3170
+ if (!setRange || !changeRange) return { ok: false, reason: "Could not resolve the cells." };
3171
+ const original = toNumber(changeRange.getValue());
3172
+ const x0Seed = Number.isFinite(original) ? original : 0;
3173
+ const evalAt = async (x) => {
3174
+ changeRange.setValue(x);
3175
+ await solver.settle();
3176
+ return toNumber(setRange.getValue());
3177
+ };
3178
+ const restore = async () => {
3179
+ changeRange.setValue(x0Seed);
3180
+ await solver.settle();
3181
+ };
3182
+ let x0 = x0Seed;
3183
+ let f0 = await evalAt(x0) - target;
3184
+ if (!Number.isFinite(f0)) {
3185
+ await restore();
3186
+ return { ok: false, reason: "The set cell is not a number (check that it holds a formula)." };
3187
+ }
3188
+ if (Math.abs(f0) <= TOLERANCE) return { ok: true, solution: x0, result: f0 + target };
3189
+ let x1 = x0 !== 0 ? x0 * 1.01 + 0.01 : 1;
3190
+ let f1 = await evalAt(x1) - target;
3191
+ for (let i = 0; i < MAX_ITERATIONS; i++) {
3192
+ if (Number.isFinite(f1) && Math.abs(f1) <= TOLERANCE) {
3193
+ return { ok: true, solution: x1, result: f1 + target };
3194
+ }
3195
+ const denom = f1 - f0;
3196
+ let x2;
3197
+ if (!Number.isFinite(f1) || denom === 0) {
3198
+ x2 = x1 + (x1 !== 0 ? x1 * 0.1 : 0.1);
3199
+ } else {
3200
+ const step = f1 * (x1 - x0) / denom;
3201
+ x2 = x1 - step;
3202
+ if (!Number.isFinite(x2)) x2 = x1 + (x1 !== 0 ? x1 * 0.1 : 0.1);
3203
+ }
3204
+ const f2 = await evalAt(x2) - target;
3205
+ x0 = x1;
3206
+ f0 = f1;
3207
+ x1 = x2;
3208
+ f1 = f2;
3209
+ }
3210
+ await restore();
3211
+ return {
3212
+ ok: false,
3213
+ reason: `Could not converge after ${MAX_ITERATIONS} iterations. Try an input cell whose value the set cell actually depends on.`
3214
+ };
3215
+ }
3216
+ var NOTE_STYLE = {
3217
+ fontSize: 12,
3218
+ color: "var(--cs-chrome-muted, #605e5c)",
3219
+ marginBottom: 12
3220
+ };
3221
+ var STATUS_OK_STYLE = {
3222
+ fontSize: 12,
3223
+ color: "var(--cs-chrome-active-fg, #0e7490)",
3224
+ marginTop: 4
3225
+ };
3226
+ var STATUS_ERR_STYLE = {
3227
+ fontSize: 12,
3228
+ color: "var(--cs-chrome-danger, #b91c1c)",
3229
+ marginTop: 4
3230
+ };
3231
+ function GoalSeekDialog({ api, onClose }) {
3232
+ const initialSetCell = useMemo10(() => {
3233
+ const range = api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange();
3234
+ const a1 = range?.getA1Notation?.();
3235
+ return a1 && isSingleCellA1(a1) ? a1 : "";
3236
+ }, [api]);
3237
+ const [state, setState] = useState13({ ...INITIAL_STATE3, setCell: initialSetCell });
3238
+ const [status, setStatus] = useState13({ kind: "idle" });
3239
+ const update = (key, value) => {
3240
+ setState((prev) => ({ ...prev, [key]: value }));
3241
+ setStatus({ kind: "idle" });
3242
+ };
3243
+ const setCellValid = isSingleCellA1(state.setCell);
3244
+ const changeCellValid = isSingleCellA1(state.byChangingCell);
3245
+ const targetNum = Number(state.toValue);
3246
+ const targetValid = state.toValue.trim() !== "" && Number.isFinite(targetNum);
3247
+ const canRun = setCellValid && changeCellValid && targetValid && state.setCell.trim().toUpperCase() !== state.byChangingCell.trim().toUpperCase() && status.kind !== "running";
3248
+ const run = async () => {
3249
+ const solver = getSolver(api);
3250
+ if (!solver) {
3251
+ setStatus({ kind: "error", message: "No active sheet." });
3252
+ return;
3253
+ }
3254
+ setStatus({ kind: "running" });
3255
+ try {
3256
+ const result = await goalSeek(
3257
+ solver,
3258
+ state.setCell.trim(),
3259
+ targetNum,
3260
+ state.byChangingCell.trim()
3261
+ );
3262
+ if (result.ok) {
3263
+ setStatus({ kind: "done", solution: result.solution, result: result.result });
3264
+ } else {
3265
+ setStatus({ kind: "error", message: result.reason });
3266
+ }
3267
+ } catch (err) {
3268
+ setStatus({
3269
+ kind: "error",
3270
+ message: err instanceof Error ? err.message : "Goal seek failed."
3271
+ });
3272
+ }
3273
+ };
3274
+ const running = status.kind === "running";
3275
+ return /* @__PURE__ */ jsxs14(
3276
+ Dialog,
3277
+ {
3278
+ title: "Goal seek",
3279
+ onClose,
3280
+ width: 420,
3281
+ "data-testid": "cs-goal-seek-dialog",
3282
+ footer: /* @__PURE__ */ jsxs14(Fragment10, { children: [
3283
+ /* @__PURE__ */ jsx15("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: status.kind === "done" ? "Done" : "Cancel" }),
3284
+ /* @__PURE__ */ jsx15(
3285
+ "button",
3286
+ {
3287
+ type: "button",
3288
+ style: { ...DIALOG_BTN_PRIMARY_STYLE, opacity: canRun ? 1 : 0.5 },
3289
+ "data-testid": "cs-goal-seek-run",
3290
+ disabled: !canRun,
3291
+ onClick: run,
3292
+ children: running ? "Solving\u2026" : "Solve"
3293
+ }
3294
+ )
3295
+ ] }),
3296
+ children: [
3297
+ /* @__PURE__ */ jsx15("div", { style: NOTE_STYLE, "data-testid": "cs-goal-seek-note", children: "Drives the input cell until the formula cell reaches your target value." }),
3298
+ /* @__PURE__ */ jsxs14("label", { style: DIALOG_FIELD_STYLE, children: [
3299
+ /* @__PURE__ */ jsx15("span", { style: DIALOG_LABEL_STYLE, children: "Set cell (formula cell)" }),
3300
+ /* @__PURE__ */ jsx15(
3301
+ "input",
3302
+ {
3303
+ style: DIALOG_INPUT_STYLE,
3304
+ "data-testid": "cs-goal-seek-set-cell",
3305
+ placeholder: "e.g. B5",
3306
+ value: state.setCell,
3307
+ onChange: (e) => update("setCell", e.target.value)
3308
+ }
3309
+ )
3310
+ ] }),
3311
+ /* @__PURE__ */ jsxs14("label", { style: DIALOG_FIELD_STYLE, children: [
3312
+ /* @__PURE__ */ jsx15("span", { style: DIALOG_LABEL_STYLE, children: "To value" }),
3313
+ /* @__PURE__ */ jsx15(
3314
+ "input",
3315
+ {
3316
+ style: DIALOG_INPUT_STYLE,
3317
+ "data-testid": "cs-goal-seek-to-value",
3318
+ type: "number",
3319
+ placeholder: "e.g. 1000",
3320
+ value: state.toValue,
3321
+ onChange: (e) => update("toValue", e.target.value)
3322
+ }
3323
+ )
3324
+ ] }),
3325
+ /* @__PURE__ */ jsxs14("label", { style: DIALOG_FIELD_STYLE, children: [
3326
+ /* @__PURE__ */ jsx15("span", { style: DIALOG_LABEL_STYLE, children: "By changing cell (input cell)" }),
3327
+ /* @__PURE__ */ jsx15(
3328
+ "input",
3329
+ {
3330
+ style: DIALOG_INPUT_STYLE,
3331
+ "data-testid": "cs-goal-seek-change-cell",
3332
+ placeholder: "e.g. B2",
3333
+ value: state.byChangingCell,
3334
+ onChange: (e) => update("byChangingCell", e.target.value)
3335
+ }
3336
+ )
3337
+ ] }),
3338
+ status.kind === "done" && /* @__PURE__ */ jsxs14("div", { style: STATUS_OK_STYLE, "data-testid": "cs-goal-seek-success", children: [
3339
+ "Solved: ",
3340
+ /* @__PURE__ */ jsx15("strong", { children: state.byChangingCell.trim().toUpperCase() }),
3341
+ " =",
3342
+ " ",
3343
+ formatNumber(status.solution),
3344
+ " makes",
3345
+ " ",
3346
+ /* @__PURE__ */ jsx15("strong", { children: state.setCell.trim().toUpperCase() }),
3347
+ " = ",
3348
+ formatNumber(status.result),
3349
+ "."
3350
+ ] }),
3351
+ status.kind === "error" && /* @__PURE__ */ jsx15("div", { style: STATUS_ERR_STYLE, "data-testid": "cs-goal-seek-error", children: status.message })
3352
+ ]
3353
+ }
3354
+ );
3355
+ }
3356
+ function formatNumber(n) {
3357
+ if (!Number.isFinite(n)) return String(n);
3358
+ const rounded = Math.round(n * 1e6) / 1e6;
3359
+ return String(rounded);
3360
+ }
3361
+
3362
+ // src/chrome/InsertChartDialog.tsx
3363
+ import { useMemo as useMemo11, useState as useState14 } from "react";
3364
+ import "@univerjs/sheets-drawing-ui/facade";
3365
+ import { Fragment as Fragment11, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
3366
+ var CHART_TYPE_OPTIONS = [
3367
+ { value: "column", label: "Column" },
3368
+ { value: "bar", label: "Bar" },
3369
+ { value: "line", label: "Line" },
3370
+ { value: "pie", label: "Pie" }
3371
+ ];
3372
+ var CHART_COMPONENT_KEY = "cs-builtin-chart-preview";
3373
+ var PALETTE = ["#0e7490", "#f59e0b", "#10b981", "#ef4444", "#6366f1", "#ec4899"];
3374
+ function activeRange9(api) {
3375
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
3376
+ }
3377
+ function activeSheet2(api) {
3378
+ return api.univer.getActiveWorkbook()?.getActiveSheet() ?? null;
3379
+ }
3380
+ function readRangeNumbers(api) {
3381
+ const snap = api.getSnapshot();
3382
+ const sel = api.getSelection();
3383
+ if (!snap || !sel) return [];
3384
+ const sheet = snap.sheets?.[sel.sheetId];
3385
+ if (!sheet) return [];
3386
+ const { startRow, endRow, startColumn, endColumn } = sel.range;
3387
+ const out = [];
3388
+ for (let r = startRow; r <= endRow; r++) {
3389
+ for (let c = startColumn; c <= endColumn; c++) {
3390
+ const raw = sheet.cellData?.[r]?.[c]?.v;
3391
+ const n = typeof raw === "number" ? raw : Number(raw);
3392
+ if (Number.isFinite(n)) out.push(n);
3393
+ }
3394
+ }
3395
+ return out;
3396
+ }
3397
+ function ensureChartComponent(api) {
3398
+ const uni = api.univer;
3399
+ if (uni.__csChartRegistered || typeof uni.registerComponent !== "function") return;
3400
+ uni.registerComponent(CHART_COMPONENT_KEY, ChartPreview);
3401
+ uni.__csChartRegistered = true;
3402
+ }
3403
+ function insertChart(api, s) {
3404
+ const range = activeRange9(api);
3405
+ const sheet = activeSheet2(api);
3406
+ if (!range || !sheet) return false;
3407
+ ensureChartComponent(api);
3408
+ const values = readRangeNumbers(api);
3409
+ const domSheet = sheet;
3410
+ if (typeof domSheet.addFloatDomToRange !== "function") return false;
3411
+ const result = domSheet.addFloatDomToRange(
3412
+ range,
3413
+ {
3414
+ componentKey: CHART_COMPONENT_KEY,
3415
+ allowTransform: true,
3416
+ data: { type: s.chartType, values, rangeA1: s.rangeA1 }
3417
+ },
3418
+ { width: 360, height: 240, marginX: 0, marginY: 0 },
3419
+ `cs-chart-${Date.now()}`
3420
+ );
3421
+ return result != null;
3422
+ }
3423
+ function ChartPreview({
3424
+ data
3425
+ }) {
3426
+ const type = data?.type ?? "column";
3427
+ const values = (data?.values ?? []).slice(0, 24);
3428
+ const label = data?.rangeA1 ?? "";
3429
+ const wrapStyle = {
3430
+ width: "100%",
3431
+ height: "100%",
3432
+ boxSizing: "border-box",
3433
+ background: "#ffffff",
3434
+ border: "1px solid #cdd3db",
3435
+ borderRadius: 6,
3436
+ padding: 8,
3437
+ display: "flex",
3438
+ flexDirection: "column",
3439
+ font: "12px system-ui, sans-serif",
3440
+ color: "#201f1e",
3441
+ overflow: "hidden"
3442
+ };
3443
+ const titleStyle = {
3444
+ fontWeight: 600,
3445
+ marginBottom: 4,
3446
+ whiteSpace: "nowrap",
3447
+ overflow: "hidden",
3448
+ textOverflow: "ellipsis"
3449
+ };
3450
+ const W = 340;
3451
+ const H = 176;
3452
+ const max = values.length ? Math.max(...values, 0) : 0;
3453
+ const min = values.length ? Math.min(...values, 0) : 0;
3454
+ const span = max - min || 1;
3455
+ let body;
3456
+ if (values.length === 0) {
3457
+ body = /* @__PURE__ */ jsx16("text", { x: W / 2, y: H / 2, textAnchor: "middle", fill: "#605e5c", children: "No numeric data in range" });
3458
+ } else if (type === "pie") {
3459
+ const total = values.reduce((a, v) => a + Math.abs(v), 0) || 1;
3460
+ const cx = W / 2;
3461
+ const cy = H / 2;
3462
+ const rad = Math.min(W, H) / 2 - 6;
3463
+ let angle = -Math.PI / 2;
3464
+ body = /* @__PURE__ */ jsx16(Fragment11, { children: values.map((v, i) => {
3465
+ const frac = Math.abs(v) / total;
3466
+ const next = angle + frac * Math.PI * 2;
3467
+ const x1 = cx + rad * Math.cos(angle);
3468
+ const y1 = cy + rad * Math.sin(angle);
3469
+ const x2 = cx + rad * Math.cos(next);
3470
+ const y2 = cy + rad * Math.sin(next);
3471
+ const large = frac > 0.5 ? 1 : 0;
3472
+ const d = `M ${cx} ${cy} L ${x1} ${y1} A ${rad} ${rad} 0 ${large} 1 ${x2} ${y2} Z`;
3473
+ angle = next;
3474
+ return /* @__PURE__ */ jsx16("path", { d, fill: PALETTE[i % PALETTE.length] }, i);
3475
+ }) });
3476
+ } else if (type === "line") {
3477
+ const step = values.length > 1 ? W / (values.length - 1) : W;
3478
+ const pts = values.map((v, i) => `${i * step},${H - (v - min) / span * H}`).join(" ");
3479
+ body = /* @__PURE__ */ jsx16("polyline", { points: pts, fill: "none", stroke: PALETTE[0], strokeWidth: 2 });
3480
+ } else {
3481
+ const horizontal = type === "bar";
3482
+ const n = values.length;
3483
+ const gap = 4;
3484
+ body = /* @__PURE__ */ jsx16(Fragment11, { children: values.map((v, i) => {
3485
+ const fill = PALETTE[i % PALETTE.length];
3486
+ if (horizontal) {
3487
+ const bh2 = H / n - gap;
3488
+ const bw2 = (v - min) / span * W;
3489
+ return /* @__PURE__ */ jsx16(
3490
+ "rect",
3491
+ {
3492
+ x: 0,
3493
+ y: i * (bh2 + gap),
3494
+ width: Math.max(bw2, 1),
3495
+ height: bh2,
3496
+ fill
3497
+ },
3498
+ i
3499
+ );
3500
+ }
3501
+ const bw = W / n - gap;
3502
+ const bh = (v - min) / span * H;
3503
+ return /* @__PURE__ */ jsx16(
3504
+ "rect",
3505
+ {
3506
+ x: i * (bw + gap),
3507
+ y: H - bh,
3508
+ width: bw,
3509
+ height: Math.max(bh, 1),
3510
+ fill
3511
+ },
3512
+ i
3513
+ );
3514
+ }) });
3515
+ }
3516
+ return /* @__PURE__ */ jsxs15("div", { style: wrapStyle, children: [
3517
+ label && /* @__PURE__ */ jsx16("div", { style: titleStyle, children: `${type[0].toUpperCase()}${type.slice(1)} chart \xB7 ${label}` }),
3518
+ /* @__PURE__ */ jsx16("svg", { viewBox: `0 0 ${W} ${H}`, width: "100%", height: "100%", preserveAspectRatio: "xMidYMid meet", children: body })
3519
+ ] });
3520
+ }
3521
+ var RANGE_NOTE_STYLE8 = {
3522
+ fontSize: 12,
3523
+ color: "var(--cs-chrome-muted, #605e5c)",
3524
+ marginBottom: 12
3525
+ };
3526
+ var TYPE_ROW_STYLE = {
3527
+ display: "grid",
3528
+ gridTemplateColumns: "repeat(4, 1fr)",
3529
+ gap: 8,
3530
+ marginBottom: 12
3531
+ };
3532
+ function typeCardStyle(selected) {
3533
+ return {
3534
+ display: "flex",
3535
+ flexDirection: "column",
3536
+ alignItems: "center",
3537
+ gap: 6,
3538
+ padding: "10px 4px",
3539
+ border: `1px solid ${selected ? "var(--cs-chrome-active-fg, #0e7490)" : "var(--cs-chrome-border, #cdd3db)"}`,
3540
+ borderRadius: 8,
3541
+ background: selected ? "var(--cs-chrome-active-bg, #ecfeff)" : "var(--cs-chrome-input-bg, #fff)",
3542
+ color: selected ? "var(--cs-chrome-active-fg, #0e7490)" : "var(--cs-chrome-fg, #201f1e)",
3543
+ font: "inherit",
3544
+ fontSize: 12,
3545
+ cursor: "pointer"
3546
+ };
3547
+ }
3548
+ function TypeGlyph({ type }) {
3549
+ const c = "currentColor";
3550
+ switch (type) {
3551
+ case "column":
3552
+ return /* @__PURE__ */ jsxs15("svg", { width: 22, height: 22, viewBox: "0 0 22 22", fill: c, "aria-hidden": "true", children: [
3553
+ /* @__PURE__ */ jsx16("rect", { x: 2, y: 10, width: 4, height: 10 }),
3554
+ /* @__PURE__ */ jsx16("rect", { x: 9, y: 5, width: 4, height: 15 }),
3555
+ /* @__PURE__ */ jsx16("rect", { x: 16, y: 2, width: 4, height: 18 })
3556
+ ] });
3557
+ case "bar":
3558
+ return /* @__PURE__ */ jsxs15("svg", { width: 22, height: 22, viewBox: "0 0 22 22", fill: c, "aria-hidden": "true", children: [
3559
+ /* @__PURE__ */ jsx16("rect", { x: 2, y: 2, width: 10, height: 4 }),
3560
+ /* @__PURE__ */ jsx16("rect", { x: 2, y: 9, width: 16, height: 4 }),
3561
+ /* @__PURE__ */ jsx16("rect", { x: 2, y: 16, width: 7, height: 4 })
3562
+ ] });
3563
+ case "line":
3564
+ return /* @__PURE__ */ jsx16(
3565
+ "svg",
3566
+ {
3567
+ width: 22,
3568
+ height: 22,
3569
+ viewBox: "0 0 22 22",
3570
+ fill: "none",
3571
+ stroke: c,
3572
+ strokeWidth: 2,
3573
+ "aria-hidden": "true",
3574
+ children: /* @__PURE__ */ jsx16("polyline", { points: "2,16 8,9 13,13 20,3" })
3575
+ }
3576
+ );
3577
+ case "pie":
3578
+ return /* @__PURE__ */ jsxs15("svg", { width: 22, height: 22, viewBox: "0 0 22 22", fill: c, "aria-hidden": "true", children: [
3579
+ /* @__PURE__ */ jsx16("path", { d: "M11 11 L11 2 A9 9 0 0 1 20 11 Z" }),
3580
+ /* @__PURE__ */ jsx16("circle", { cx: 11, cy: 11, r: 9, fill: "none", stroke: c, strokeWidth: 1.5 })
3581
+ ] });
3582
+ }
3583
+ }
3584
+ function InsertChartDialog({ api, onClose }) {
3585
+ const rangeLabel = useMemo11(() => {
3586
+ const fRange = activeRange9(api);
3587
+ return fRange?.getA1Notation?.() ?? null;
3588
+ }, [api]);
3589
+ const [state, setState] = useState14(() => ({
3590
+ chartType: "column",
3591
+ rangeA1: rangeLabel ?? ""
3592
+ }));
3593
+ const hasSelection = activeRange9(api) !== null;
3594
+ const update = (key, value) => setState((prev) => ({ ...prev, [key]: value }));
3595
+ const apply = () => {
3596
+ if (insertChart(api, state)) onClose();
3597
+ };
3598
+ return /* @__PURE__ */ jsxs15(
3599
+ Dialog,
3600
+ {
3601
+ title: "Insert chart",
3602
+ onClose,
3603
+ width: 440,
3604
+ "data-testid": "cs-insert-chart-dialog",
3605
+ footer: /* @__PURE__ */ jsxs15(Fragment11, { children: [
3606
+ /* @__PURE__ */ jsx16("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
3607
+ /* @__PURE__ */ jsx16(
3608
+ "button",
3609
+ {
3610
+ type: "button",
3611
+ style: DIALOG_BTN_PRIMARY_STYLE,
3612
+ "data-testid": "cs-insert-chart-apply",
3613
+ disabled: !hasSelection,
3614
+ onClick: apply,
3615
+ children: "Insert"
3616
+ }
3617
+ )
3618
+ ] }),
3619
+ children: [
3620
+ hasSelection ? /* @__PURE__ */ jsxs15("div", { style: RANGE_NOTE_STYLE8, "data-testid": "cs-insert-chart-range", children: [
3621
+ "Chart from ",
3622
+ /* @__PURE__ */ jsx16("strong", { children: rangeLabel ?? "the current selection" })
3623
+ ] }) : /* @__PURE__ */ jsx16("div", { style: RANGE_NOTE_STYLE8, "data-testid": "cs-insert-chart-no-selection", children: "Select the data range first, then reopen this dialog." }),
3624
+ /* @__PURE__ */ jsx16("div", { style: DIALOG_LABEL_STYLE, children: "Chart type" }),
3625
+ /* @__PURE__ */ jsx16("div", { style: TYPE_ROW_STYLE, role: "radiogroup", "aria-label": "Chart type", children: CHART_TYPE_OPTIONS.map((opt) => /* @__PURE__ */ jsxs15(
3626
+ "button",
3627
+ {
3628
+ type: "button",
3629
+ role: "radio",
3630
+ "aria-checked": state.chartType === opt.value,
3631
+ "data-testid": `cs-insert-chart-type-${opt.value}`,
3632
+ style: typeCardStyle(state.chartType === opt.value),
3633
+ onClick: () => update("chartType", opt.value),
3634
+ children: [
3635
+ /* @__PURE__ */ jsx16(TypeGlyph, { type: opt.value }),
3636
+ /* @__PURE__ */ jsx16("span", { children: opt.label })
3637
+ ]
3638
+ },
3639
+ opt.value
3640
+ )) }),
3641
+ /* @__PURE__ */ jsxs15("label", { style: DIALOG_FIELD_STYLE, children: [
3642
+ /* @__PURE__ */ jsx16("span", { style: DIALOG_LABEL_STYLE, children: "Data range" }),
3643
+ /* @__PURE__ */ jsx16(
3644
+ "input",
3645
+ {
3646
+ style: DIALOG_INPUT_STYLE,
3647
+ "data-testid": "cs-insert-chart-range-input",
3648
+ value: state.rangeA1,
3649
+ placeholder: "A1:B5",
3650
+ onChange: (e) => update("rangeA1", e.target.value)
3651
+ }
3652
+ )
3653
+ ] }),
3654
+ /* @__PURE__ */ jsx16("div", { style: RANGE_NOTE_STYLE8, children: "The chart is placed over the current selection. Numeric cells in the range become the series." })
3655
+ ]
3656
+ }
3657
+ );
3658
+ }
3659
+
3660
+ // src/chrome/InsertSparklineDialog.tsx
3661
+ import { useMemo as useMemo12, useState as useState15 } from "react";
3662
+ import { Fragment as Fragment12, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
3663
+ var SPARKLINES_RESOURCE_NAME = "__casual_sheets_sparklines__";
3664
+ var TYPE_OPTIONS = [
3665
+ { value: "line", label: "Line" },
3666
+ { value: "column", label: "Column" },
3667
+ { value: "win-loss", label: "Win / Loss" }
3668
+ ];
3669
+ function activeRange10(api) {
3670
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
3671
+ }
3672
+ function colLettersToIndex(letters) {
3673
+ let n = 0;
3674
+ for (let i = 0; i < letters.length; i += 1) {
3675
+ n = n * 26 + (letters.charCodeAt(i) - 64);
3676
+ }
3677
+ return n - 1;
3678
+ }
3679
+ function parseRange(s) {
3680
+ const m = /^\$?([A-Z]+)\$?(\d+)(?::\$?([A-Z]+)\$?(\d+))?$/.exec(s.trim().toUpperCase());
3681
+ if (!m) return null;
3682
+ const c1 = colLettersToIndex(m[1]);
3683
+ const r1 = parseInt(m[2], 10) - 1;
3684
+ const c2 = m[3] ? colLettersToIndex(m[3]) : c1;
3685
+ const r2 = m[4] ? parseInt(m[4], 10) - 1 : r1;
3686
+ return {
3687
+ startRow: Math.min(r1, r2),
3688
+ endRow: Math.max(r1, r2),
3689
+ startColumn: Math.min(c1, c2),
3690
+ endColumn: Math.max(c1, c2)
3691
+ };
3692
+ }
3693
+ function parseSingleCell(s) {
3694
+ const m = /^\$?([A-Z]+)\$?(\d+)$/.exec(s.trim().toUpperCase());
3695
+ if (!m) return null;
3696
+ return { col: colLettersToIndex(m[1]), row: parseInt(m[2], 10) - 1 };
3697
+ }
3698
+ function insertSparkline(api, model) {
3699
+ const data = api.getContent();
3700
+ if (!data) return false;
3701
+ const resources = data.resources ? [...data.resources] : [];
3702
+ const idx = resources.findIndex((r) => r.name === SPARKLINES_RESOURCE_NAME);
3703
+ let existing = [];
3704
+ if (idx >= 0 && resources[idx]?.data) {
3705
+ try {
3706
+ const parsed = JSON.parse(resources[idx].data);
3707
+ if (parsed?.v === 1 && Array.isArray(parsed.sparklines)) existing = parsed.sparklines;
3708
+ } catch {
3709
+ existing = [];
3710
+ }
3711
+ }
3712
+ const payload = { v: 1, sparklines: [...existing, model] };
3713
+ const entry = { name: SPARKLINES_RESOURCE_NAME, data: JSON.stringify(payload) };
3714
+ if (idx >= 0) resources[idx] = entry;
3715
+ else resources.push(entry);
3716
+ const next = { ...data, resources };
3717
+ api.setContent(next);
3718
+ return true;
3719
+ }
3720
+ function activeIds(api) {
3721
+ const wb = api.univer.getActiveWorkbook();
3722
+ const sheet = wb?.getActiveSheet();
3723
+ if (!wb || !sheet) return null;
3724
+ return { unitId: wb.getId(), sheetId: sheet.getSheetId() };
3725
+ }
3726
+ var RANGE_NOTE_STYLE9 = {
3727
+ fontSize: 12,
3728
+ color: "var(--cs-chrome-muted, #605e5c)",
3729
+ marginBottom: 12
3730
+ };
3731
+ var RADIO_ROW_STYLE = {
3732
+ display: "flex",
3733
+ gap: 16,
3734
+ marginTop: 2
3735
+ };
3736
+ var RADIO_OPT_STYLE = {
3737
+ display: "flex",
3738
+ alignItems: "center",
3739
+ gap: 6,
3740
+ cursor: "pointer"
3741
+ };
3742
+ var ERROR_STYLE2 = {
3743
+ fontSize: 12,
3744
+ color: "var(--cs-chrome-danger-fg, #b91c1c)",
3745
+ marginTop: 4
3746
+ };
3747
+ function InsertSparklineDialog({ api, onClose }) {
3748
+ const selectedA1 = useMemo12(() => {
3749
+ const fRange = activeRange10(api);
3750
+ return fRange?.getA1Notation?.() ?? "";
3751
+ }, [api]);
3752
+ const [state, setState] = useState15({
3753
+ type: "line",
3754
+ sourceA1: selectedA1,
3755
+ anchorA1: ""
3756
+ });
3757
+ const [error, setError] = useState15(null);
3758
+ const hasWorkbook = api.univer.getActiveWorkbook() != null;
3759
+ const update = (key, value) => {
3760
+ setState((prev) => ({ ...prev, [key]: value }));
3761
+ setError(null);
3762
+ };
3763
+ const apply = () => {
3764
+ const source = parseRange(state.sourceA1);
3765
+ if (!source) {
3766
+ setError("Data range must be a range like A1:F1.");
3767
+ return;
3768
+ }
3769
+ const anchor = parseSingleCell(state.anchorA1);
3770
+ if (!anchor) {
3771
+ setError("Location must be a single cell like G1.");
3772
+ return;
3773
+ }
3774
+ const ids = activeIds(api);
3775
+ if (!ids) {
3776
+ setError("No active sheet.");
3777
+ return;
3778
+ }
3779
+ const model = {
3780
+ id: `spark-${Math.random().toString(36).slice(2, 10)}`,
3781
+ type: state.type,
3782
+ unitId: ids.unitId,
3783
+ sheetId: ids.sheetId,
3784
+ source,
3785
+ anchor
3786
+ };
3787
+ if (insertSparkline(api, model)) onClose();
3788
+ else setError("Could not read the active workbook.");
3789
+ };
3790
+ return /* @__PURE__ */ jsxs16(
3791
+ Dialog,
3792
+ {
3793
+ title: "Insert sparkline",
3794
+ onClose,
3795
+ width: 420,
3796
+ "data-testid": "cs-insert-sparkline-dialog",
3797
+ footer: /* @__PURE__ */ jsxs16(Fragment12, { children: [
3798
+ /* @__PURE__ */ jsx17("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
3799
+ /* @__PURE__ */ jsx17(
3800
+ "button",
3801
+ {
3802
+ type: "button",
3803
+ style: DIALOG_BTN_PRIMARY_STYLE,
3804
+ "data-testid": "cs-insert-sparkline-apply",
3805
+ disabled: !hasWorkbook,
3806
+ onClick: apply,
3807
+ children: "Insert"
3808
+ }
3809
+ )
3810
+ ] }),
3811
+ children: [
3812
+ /* @__PURE__ */ jsx17("div", { style: RANGE_NOTE_STYLE9, children: "Draws an in-cell mini-chart in the location cell from the values in the data range." }),
3813
+ /* @__PURE__ */ jsxs16("label", { style: DIALOG_FIELD_STYLE, children: [
3814
+ /* @__PURE__ */ jsx17("span", { style: DIALOG_LABEL_STYLE, children: "Type" }),
3815
+ /* @__PURE__ */ jsx17(
3816
+ "div",
3817
+ {
3818
+ style: RADIO_ROW_STYLE,
3819
+ role: "radiogroup",
3820
+ "aria-label": "Sparkline type",
3821
+ "data-testid": "cs-insert-sparkline-type",
3822
+ children: TYPE_OPTIONS.map((opt) => /* @__PURE__ */ jsxs16("label", { style: RADIO_OPT_STYLE, children: [
3823
+ /* @__PURE__ */ jsx17(
3824
+ "input",
3825
+ {
3826
+ type: "radio",
3827
+ name: "cs-sparkline-type",
3828
+ value: opt.value,
3829
+ "data-testid": `cs-insert-sparkline-type-${opt.value}`,
3830
+ checked: state.type === opt.value,
3831
+ onChange: () => update("type", opt.value)
3832
+ }
3833
+ ),
3834
+ /* @__PURE__ */ jsx17("span", { children: opt.label })
3835
+ ] }, opt.value))
3836
+ }
3837
+ )
3838
+ ] }),
3839
+ /* @__PURE__ */ jsxs16("label", { style: DIALOG_FIELD_STYLE, children: [
3840
+ /* @__PURE__ */ jsx17("span", { style: DIALOG_LABEL_STYLE, children: "Data range" }),
3841
+ /* @__PURE__ */ jsx17(
3842
+ "input",
3843
+ {
3844
+ style: DIALOG_INPUT_STYLE,
3845
+ "data-testid": "cs-insert-sparkline-source",
3846
+ value: state.sourceA1,
3847
+ placeholder: "A1:F1",
3848
+ spellCheck: false,
3849
+ onChange: (e) => update("sourceA1", e.target.value.toUpperCase())
3850
+ }
3851
+ )
3852
+ ] }),
3853
+ /* @__PURE__ */ jsxs16("label", { style: DIALOG_FIELD_STYLE, children: [
3854
+ /* @__PURE__ */ jsx17("span", { style: DIALOG_LABEL_STYLE, children: "Location" }),
3855
+ /* @__PURE__ */ jsx17(
3856
+ "input",
3857
+ {
3858
+ style: DIALOG_INPUT_STYLE,
3859
+ "data-testid": "cs-insert-sparkline-anchor",
3860
+ value: state.anchorA1,
3861
+ placeholder: "G1",
3862
+ spellCheck: false,
3863
+ onChange: (e) => update("anchorA1", e.target.value.toUpperCase())
3864
+ }
3865
+ )
3866
+ ] }),
3867
+ error && /* @__PURE__ */ jsx17("div", { style: ERROR_STYLE2, "data-testid": "cs-insert-sparkline-error", children: error })
3868
+ ]
3869
+ }
3870
+ );
3871
+ }
3872
+
3873
+ // src/chrome/InsertPivotDialog.tsx
3874
+ import { useMemo as useMemo13, useState as useState16 } from "react";
3875
+ import { Fragment as Fragment13, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3876
+ var AGG_OPTIONS = [
3877
+ { value: "sum", label: "Sum" },
3878
+ { value: "count", label: "Count" },
3879
+ { value: "average", label: "Average" },
3880
+ { value: "min", label: "Min" },
3881
+ { value: "max", label: "Max" }
3882
+ ];
3883
+ function activeRange11(api) {
3884
+ return api.univer.getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
3885
+ }
3886
+ function readSource(api) {
3887
+ const range = activeRange11(api);
3888
+ const grid = range?.getValues?.() ?? [];
3889
+ return Array.isArray(grid) ? grid : [];
3890
+ }
3891
+ function columnLabel(index, headerRow, useHeader) {
3892
+ if (useHeader) {
3893
+ const raw = headerRow?.[index];
3894
+ if (raw != null && String(raw).trim().length > 0) return String(raw);
3895
+ }
3896
+ let n = index;
3897
+ let label = "";
3898
+ do {
3899
+ label = String.fromCharCode(65 + n % 26) + label;
3900
+ n = Math.floor(n / 26) - 1;
3901
+ } while (n >= 0);
3902
+ return `Column ${label}`;
3903
+ }
3904
+ function toNumber2(v) {
3905
+ if (typeof v === "number") return Number.isFinite(v) ? v : null;
3906
+ if (typeof v === "boolean") return v ? 1 : 0;
3907
+ if (typeof v === "string" && v.trim() !== "") {
3908
+ const n = Number(v);
3909
+ return Number.isFinite(n) ? n : null;
3910
+ }
3911
+ return null;
3912
+ }
3913
+ function aggregate(fn, values, rowCount) {
3914
+ if (fn === "count") return rowCount;
3915
+ if (values.length === 0) return 0;
3916
+ switch (fn) {
3917
+ case "sum":
3918
+ return values.reduce((a, b) => a + b, 0);
3919
+ case "average":
3920
+ return values.reduce((a, b) => a + b, 0) / values.length;
3921
+ case "min":
3922
+ return Math.min(...values);
3923
+ case "max":
3924
+ return Math.max(...values);
3925
+ }
3926
+ }
3927
+ function buildPivot(source, useHeader, groupCol, valueCol, fn) {
3928
+ if (source.length === 0) return null;
3929
+ const headerRow = useHeader ? source[0] : void 0;
3930
+ const dataRows = useHeader ? source.slice(1) : source;
3931
+ if (dataRows.length === 0) return null;
3932
+ const order = [];
3933
+ const buckets = /* @__PURE__ */ new Map();
3934
+ const counts = /* @__PURE__ */ new Map();
3935
+ for (const row of dataRows) {
3936
+ const rawKey = row[groupCol];
3937
+ const key = rawKey == null ? "" : String(rawKey);
3938
+ if (!buckets.has(key)) {
3939
+ buckets.set(key, []);
3940
+ counts.set(key, 0);
3941
+ order.push(key);
3942
+ }
3943
+ counts.set(key, (counts.get(key) ?? 0) + 1);
3944
+ const num = toNumber2(row[valueCol]);
3945
+ if (num != null) buckets.get(key).push(num);
3946
+ }
3947
+ const groupHeader = columnLabel(groupCol, headerRow, useHeader);
3948
+ const valueHeader = columnLabel(valueCol, headerRow, useHeader);
3949
+ const aggLabel = AGG_OPTIONS.find((o) => o.value === fn)?.label ?? "Sum";
3950
+ const grid = [[groupHeader, `${aggLabel} of ${valueHeader}`]];
3951
+ for (const key of order) {
3952
+ grid.push([key === "" ? "(blank)" : key, aggregate(fn, buckets.get(key), counts.get(key))]);
3953
+ }
3954
+ return { grid };
3955
+ }
3956
+ function toA1(row, col) {
3957
+ let n = col;
3958
+ let letters = "";
3959
+ do {
3960
+ letters = String.fromCharCode(65 + n % 26) + letters;
3961
+ n = Math.floor(n / 26) - 1;
3962
+ } while (n >= 0);
3963
+ return `${letters}${row + 1}`;
3964
+ }
3965
+ var RANGE_NOTE_STYLE10 = {
3966
+ fontSize: 12,
3967
+ color: "var(--cs-chrome-muted, #605e5c)",
3968
+ marginBottom: 12
3969
+ };
3970
+ var CHECK_STYLE5 = {
3971
+ display: "flex",
3972
+ alignItems: "center",
3973
+ gap: 6,
3974
+ marginBottom: 12,
3975
+ cursor: "pointer"
3976
+ };
3977
+ var RADIO_ROW_STYLE2 = {
3978
+ display: "flex",
3979
+ alignItems: "center",
3980
+ gap: 6,
3981
+ marginBottom: 6,
3982
+ cursor: "pointer"
3983
+ };
3984
+ function InsertPivotDialog({ api, onClose }) {
3985
+ const source = useMemo13(() => readSource(api), [api]);
3986
+ const rangeLabel = useMemo13(() => {
3987
+ const r = activeRange11(api);
3988
+ return r?.getA1Notation?.() ?? null;
3989
+ }, [api]);
3990
+ const hasSource = source.length > 0 && (source[0]?.length ?? 0) > 0;
3991
+ const colCount = hasSource ? source[0].length : 0;
3992
+ const [state, setState] = useState16({
3993
+ useHeader: true,
3994
+ groupCol: 0,
3995
+ valueCol: colCount > 1 ? 1 : 0,
3996
+ aggFn: "sum",
3997
+ destination: "newSheet",
3998
+ sheetName: "Pivot",
3999
+ anchor: ""
4000
+ });
4001
+ const [error, setError] = useState16(null);
4002
+ const update = (key, value) => {
4003
+ setState((prev) => ({ ...prev, [key]: value }));
4004
+ setError(null);
4005
+ };
4006
+ const columnOptions = useMemo13(() => {
4007
+ const header = state.useHeader ? source[0] : void 0;
4008
+ return Array.from({ length: colCount }, (_, i) => ({
4009
+ value: i,
4010
+ label: columnLabel(i, header, state.useHeader)
4011
+ }));
4012
+ }, [source, colCount, state.useHeader]);
4013
+ const apply = () => {
4014
+ const pivot = buildPivot(source, state.useHeader, state.groupCol, state.valueCol, state.aggFn);
4015
+ if (!pivot) {
4016
+ setError("The selection has no data rows to summarize.");
4017
+ return;
4018
+ }
4019
+ const wb = api.univer.getActiveWorkbook();
4020
+ if (!wb) {
4021
+ setError("No active workbook.");
4022
+ return;
4023
+ }
4024
+ try {
4025
+ if (state.destination === "newSheet") {
4026
+ const name = state.sheetName.trim() || "Pivot";
4027
+ const rows = Math.max(pivot.grid.length + 2, 10);
4028
+ const sheet = wb.create(name, rows, 4);
4029
+ const target = sheet.getRange(`A1:${toA1(pivot.grid.length - 1, 1)}`);
4030
+ target.setValues(pivot.grid);
4031
+ } else {
4032
+ const anchor = state.anchor.trim().toUpperCase();
4033
+ if (!/^[A-Z]+[0-9]+$/.test(anchor)) {
4034
+ setError("Enter a valid top-left cell, e.g. E1.");
4035
+ return;
4036
+ }
4037
+ const sheet = wb.getActiveSheet();
4038
+ if (!sheet) {
4039
+ setError("No active sheet to write into.");
4040
+ return;
4041
+ }
4042
+ const m = /^([A-Z]+)([0-9]+)$/.exec(anchor);
4043
+ let col = 0;
4044
+ for (const ch of m[1]) col = col * 26 + (ch.charCodeAt(0) - 64);
4045
+ col -= 1;
4046
+ const startRow = Number(m[2]) - 1;
4047
+ const end = toA1(startRow + pivot.grid.length - 1, col + 1);
4048
+ sheet.getRange(`${anchor}:${end}`).setValues(pivot.grid);
4049
+ }
4050
+ } catch (e) {
4051
+ setError(e instanceof Error ? e.message : "Failed to create the pivot table.");
4052
+ return;
4053
+ }
4054
+ onClose();
4055
+ };
4056
+ return /* @__PURE__ */ jsxs17(
4057
+ Dialog,
4058
+ {
4059
+ title: "Insert pivot table",
4060
+ onClose,
4061
+ width: 460,
4062
+ "data-testid": "cs-insert-pivot-dialog",
4063
+ footer: /* @__PURE__ */ jsxs17(Fragment13, { children: [
4064
+ /* @__PURE__ */ jsx18("button", { type: "button", style: DIALOG_BTN_SECONDARY_STYLE, onClick: onClose, children: "Cancel" }),
4065
+ /* @__PURE__ */ jsx18(
4066
+ "button",
4067
+ {
4068
+ type: "button",
4069
+ style: DIALOG_BTN_PRIMARY_STYLE,
4070
+ "data-testid": "cs-insert-pivot-create",
4071
+ disabled: !hasSource,
4072
+ onClick: apply,
4073
+ children: "Create"
4074
+ }
4075
+ )
4076
+ ] }),
4077
+ children: [
4078
+ hasSource ? /* @__PURE__ */ jsxs17("div", { style: RANGE_NOTE_STYLE10, "data-testid": "cs-insert-pivot-source", children: [
4079
+ "Source data ",
4080
+ /* @__PURE__ */ jsx18("strong", { children: rangeLabel ?? "the current selection" }),
4081
+ " (",
4082
+ source.length,
4083
+ " rows \xD7 ",
4084
+ colCount,
4085
+ " columns)"
4086
+ ] }) : /* @__PURE__ */ jsx18("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." }),
4087
+ /* @__PURE__ */ jsxs17("label", { style: CHECK_STYLE5, "data-testid": "cs-insert-pivot-header-label", children: [
4088
+ /* @__PURE__ */ jsx18(
4089
+ "input",
4090
+ {
4091
+ type: "checkbox",
4092
+ "data-testid": "cs-insert-pivot-header",
4093
+ checked: state.useHeader,
4094
+ onChange: (e) => update("useHeader", e.target.checked),
4095
+ disabled: !hasSource
4096
+ }
4097
+ ),
4098
+ /* @__PURE__ */ jsx18("span", { children: "First row is a header" })
4099
+ ] }),
4100
+ /* @__PURE__ */ jsxs17("label", { style: DIALOG_FIELD_STYLE, children: [
4101
+ /* @__PURE__ */ jsx18("span", { style: DIALOG_LABEL_STYLE, children: "Rows (group by)" }),
4102
+ /* @__PURE__ */ jsx18(
4103
+ "select",
4104
+ {
4105
+ style: DIALOG_INPUT_STYLE,
4106
+ "data-testid": "cs-insert-pivot-group-col",
4107
+ value: state.groupCol,
4108
+ disabled: !hasSource,
4109
+ onChange: (e) => update("groupCol", Number(e.target.value)),
4110
+ children: columnOptions.map((opt) => /* @__PURE__ */ jsx18("option", { value: opt.value, children: opt.label }, opt.value))
4111
+ }
4112
+ )
4113
+ ] }),
4114
+ /* @__PURE__ */ jsxs17("label", { style: DIALOG_FIELD_STYLE, children: [
4115
+ /* @__PURE__ */ jsx18("span", { style: DIALOG_LABEL_STYLE, children: "Values" }),
4116
+ /* @__PURE__ */ jsx18(
4117
+ "select",
4118
+ {
4119
+ style: DIALOG_INPUT_STYLE,
4120
+ "data-testid": "cs-insert-pivot-value-col",
4121
+ value: state.valueCol,
4122
+ disabled: !hasSource,
4123
+ onChange: (e) => update("valueCol", Number(e.target.value)),
4124
+ children: columnOptions.map((opt) => /* @__PURE__ */ jsx18("option", { value: opt.value, children: opt.label }, opt.value))
4125
+ }
4126
+ )
4127
+ ] }),
4128
+ /* @__PURE__ */ jsxs17("label", { style: DIALOG_FIELD_STYLE, children: [
4129
+ /* @__PURE__ */ jsx18("span", { style: DIALOG_LABEL_STYLE, children: "Summarize by" }),
4130
+ /* @__PURE__ */ jsx18(
4131
+ "select",
4132
+ {
4133
+ style: DIALOG_INPUT_STYLE,
4134
+ "data-testid": "cs-insert-pivot-agg",
4135
+ value: state.aggFn,
4136
+ disabled: !hasSource,
4137
+ onChange: (e) => update("aggFn", e.target.value),
4138
+ children: AGG_OPTIONS.map((opt) => /* @__PURE__ */ jsx18("option", { value: opt.value, children: opt.label }, opt.value))
4139
+ }
4140
+ )
4141
+ ] }),
4142
+ /* @__PURE__ */ jsxs17("div", { style: DIALOG_FIELD_STYLE, children: [
4143
+ /* @__PURE__ */ jsx18("span", { style: DIALOG_LABEL_STYLE, children: "Destination" }),
4144
+ /* @__PURE__ */ jsxs17("label", { style: RADIO_ROW_STYLE2, children: [
4145
+ /* @__PURE__ */ jsx18(
4146
+ "input",
4147
+ {
4148
+ type: "radio",
4149
+ name: "cs-insert-pivot-destination",
4150
+ "data-testid": "cs-insert-pivot-dest-new",
4151
+ checked: state.destination === "newSheet",
4152
+ onChange: () => update("destination", "newSheet")
4153
+ }
4154
+ ),
4155
+ /* @__PURE__ */ jsx18("span", { children: "New sheet" })
4156
+ ] }),
4157
+ /* @__PURE__ */ jsxs17("label", { style: RADIO_ROW_STYLE2, children: [
4158
+ /* @__PURE__ */ jsx18(
4159
+ "input",
4160
+ {
4161
+ type: "radio",
4162
+ name: "cs-insert-pivot-destination",
4163
+ "data-testid": "cs-insert-pivot-dest-existing",
4164
+ checked: state.destination === "existing",
4165
+ onChange: () => update("destination", "existing")
4166
+ }
4167
+ ),
4168
+ /* @__PURE__ */ jsx18("span", { children: "Existing sheet (choose top-left cell)" })
4169
+ ] })
4170
+ ] }),
4171
+ state.destination === "newSheet" ? /* @__PURE__ */ jsxs17("label", { style: DIALOG_FIELD_STYLE, children: [
4172
+ /* @__PURE__ */ jsx18("span", { style: DIALOG_LABEL_STYLE, children: "New sheet name" }),
4173
+ /* @__PURE__ */ jsx18(
4174
+ "input",
4175
+ {
4176
+ style: DIALOG_INPUT_STYLE,
4177
+ "data-testid": "cs-insert-pivot-sheet-name",
4178
+ value: state.sheetName,
4179
+ placeholder: "Pivot",
4180
+ onChange: (e) => update("sheetName", e.target.value)
4181
+ }
4182
+ )
4183
+ ] }) : /* @__PURE__ */ jsxs17("label", { style: DIALOG_FIELD_STYLE, children: [
4184
+ /* @__PURE__ */ jsx18("span", { style: DIALOG_LABEL_STYLE, children: "Top-left cell (on the active sheet)" }),
4185
+ /* @__PURE__ */ jsx18(
4186
+ "input",
4187
+ {
4188
+ style: DIALOG_INPUT_STYLE,
4189
+ "data-testid": "cs-insert-pivot-anchor",
4190
+ value: state.anchor,
4191
+ placeholder: "e.g. E1",
4192
+ onChange: (e) => update("anchor", e.target.value)
4193
+ }
4194
+ )
4195
+ ] }),
4196
+ error && /* @__PURE__ */ jsx18(
4197
+ "div",
4198
+ {
4199
+ style: {
4200
+ ...RANGE_NOTE_STYLE10,
4201
+ color: "var(--cs-chrome-danger, #b3261e)",
4202
+ marginBottom: 0
4203
+ },
4204
+ "data-testid": "cs-insert-pivot-error",
4205
+ role: "alert",
4206
+ children: error
4207
+ }
4208
+ )
4209
+ ]
4210
+ }
4211
+ );
4212
+ }
4213
+
1131
4214
  // src/chrome/dialog-context.tsx
1132
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
4215
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
1133
4216
  var BUILT_IN_DIALOGS = {
1134
- "format-cells": FormatCellsDialog
4217
+ "format-cells": FormatCellsDialog,
4218
+ "data-validation": DataValidationDialog,
4219
+ "conditional-formatting": ConditionalFormattingDialog,
4220
+ "custom-sort": CustomSortDialog,
4221
+ "paste-special": PasteSpecialDialog,
4222
+ "insert-function": InsertFunctionDialog,
4223
+ "name-manager": NameManagerDialog,
4224
+ "insert-cells": InsertCellsDialog,
4225
+ "delete-cells": DeleteCellsDialog,
4226
+ "goal-seek": GoalSeekDialog,
4227
+ "insert-chart": InsertChartDialog,
4228
+ "insert-sparkline": InsertSparklineDialog,
4229
+ "insert-pivot": InsertPivotDialog
1135
4230
  };
1136
4231
  function hasBuiltInDialog(kind) {
1137
4232
  return kind in BUILT_IN_DIALOGS || kind === "find-replace";
@@ -1158,10 +4253,10 @@ function DialogProvider({
1158
4253
  onOpenFindReplace,
1159
4254
  children
1160
4255
  }) {
1161
- const [active, setActive] = useState5(null);
4256
+ const [active, setActive] = useState17(null);
1162
4257
  const overrides = extensions?.dialogs;
1163
- const hostOwned = useMemo2(() => new Set(hostOwnedDialogs ?? []), [hostOwnedDialogs]);
1164
- const openDialog = useCallback(
4258
+ const hostOwned = useMemo14(() => new Set(hostOwnedDialogs ?? []), [hostOwnedDialogs]);
4259
+ const openDialog = useCallback2(
1165
4260
  (kind, context) => {
1166
4261
  if (overrides?.[kind]) {
1167
4262
  setActive({ kind, context });
@@ -1186,22 +4281,22 @@ function DialogProvider({
1186
4281
  },
1187
4282
  [overrides, onDialogRequest, hostOwned, onOpenFindReplace]
1188
4283
  );
1189
- const closeDialog = useCallback(() => setActive(null), []);
1190
- const canOpen = useCallback(
4284
+ const closeDialog = useCallback2(() => setActive(null), []);
4285
+ const canOpen = useCallback2(
1191
4286
  (kind) => !!overrides?.[kind] || hasBuiltInDialog(kind) || !!onDialogRequest || hostOwned.has(kind),
1192
4287
  [overrides, onDialogRequest, hostOwned]
1193
4288
  );
1194
- const controllerCanOpen = useCallback(
4289
+ const controllerCanOpen = useCallback2(
1195
4290
  (kind) => kind === "find-replace" ? !!onOpenFindReplace || canOpen(kind) : canOpen(kind),
1196
4291
  [canOpen, onOpenFindReplace]
1197
4292
  );
1198
- const controller = useMemo2(
4293
+ const controller = useMemo14(
1199
4294
  () => ({ openDialog, closeDialog, canOpen: controllerCanOpen }),
1200
4295
  [openDialog, closeDialog, controllerCanOpen]
1201
4296
  );
1202
- return /* @__PURE__ */ jsxs6(DialogContext.Provider, { value: controller, children: [
4297
+ return /* @__PURE__ */ jsxs18(DialogContext.Provider, { value: controller, children: [
1203
4298
  children,
1204
- /* @__PURE__ */ jsx7(DialogHost, { api, active, overrides, onClose: closeDialog })
4299
+ /* @__PURE__ */ jsx19(DialogHost, { api, active, overrides, onClose: closeDialog })
1205
4300
  ] });
1206
4301
  }
1207
4302
  function DialogHost({ api, active, overrides, onClose }) {
@@ -1209,11 +4304,11 @@ function DialogHost({ api, active, overrides, onClose }) {
1209
4304
  if (active.kind === "find-replace") return null;
1210
4305
  const Component = overrides?.[active.kind] ?? BUILT_IN_DIALOGS[active.kind];
1211
4306
  if (!Component) return null;
1212
- return /* @__PURE__ */ jsx7(Component, { api, onClose, context: active.context });
4307
+ return /* @__PURE__ */ jsx19(Component, { api, onClose, context: active.context });
1213
4308
  }
1214
4309
 
1215
4310
  // src/chrome/Toolbar.tsx
1216
- import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
4311
+ import { Fragment as Fragment14, jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
1217
4312
  var NO_STYLE = {
1218
4313
  bold: false,
1219
4314
  italic: false,
@@ -1547,7 +4642,7 @@ function isActive(id, s) {
1547
4642
  }
1548
4643
  function Toolbar({ api, features, extensions }) {
1549
4644
  const dialogs = useDialogs();
1550
- const [active, setActive] = useState6(NO_STYLE);
4645
+ const [active, setActive] = useState18(NO_STYLE);
1551
4646
  useEffect6(() => {
1552
4647
  ensureChromeFonts();
1553
4648
  }, []);
@@ -1584,7 +4679,7 @@ function Toolbar({ api, features, extensions }) {
1584
4679
  const renderActionButton = (a) => {
1585
4680
  const on = isActive(a.id, active);
1586
4681
  const baseBg = on ? "var(--cs-chrome-active, #e6f3f7)" : "transparent";
1587
- return /* @__PURE__ */ jsx8(
4682
+ return /* @__PURE__ */ jsx20(
1588
4683
  "button",
1589
4684
  {
1590
4685
  type: "button",
@@ -1610,12 +4705,12 @@ function Toolbar({ api, features, extensions }) {
1610
4705
  onMouseLeave: (e) => {
1611
4706
  e.currentTarget.style.background = baseBg;
1612
4707
  },
1613
- children: /* @__PURE__ */ jsx8(Icon, { name: a.icon, size: 20 })
4708
+ children: /* @__PURE__ */ jsx20(Icon, { name: a.icon, size: 20 })
1614
4709
  },
1615
4710
  a.id
1616
4711
  );
1617
4712
  };
1618
- const renderIconButton = (id, label, icon, onPress, testid) => /* @__PURE__ */ jsx8(
4713
+ const renderIconButton = (id, label, icon, onPress, testid) => /* @__PURE__ */ jsx20(
1619
4714
  "button",
1620
4715
  {
1621
4716
  type: "button",
@@ -1635,7 +4730,7 @@ function Toolbar({ api, features, extensions }) {
1635
4730
  onMouseLeave: (e) => {
1636
4731
  e.currentTarget.style.background = "transparent";
1637
4732
  },
1638
- children: /* @__PURE__ */ jsx8(Icon, { name: icon, size: 20 })
4733
+ children: /* @__PURE__ */ jsx20(Icon, { name: icon, size: 20 })
1639
4734
  },
1640
4735
  id
1641
4736
  );
@@ -1646,8 +4741,8 @@ function Toolbar({ api, features, extensions }) {
1646
4741
  if (visible.length === 0) return null;
1647
4742
  const showDivider = firstGroupRendered;
1648
4743
  firstGroupRendered = true;
1649
- return /* @__PURE__ */ jsxs7("span", { style: { display: "inline-flex", alignItems: "center" }, children: [
1650
- showDivider && /* @__PURE__ */ jsx8("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
4744
+ return /* @__PURE__ */ jsxs19("span", { style: { display: "inline-flex", alignItems: "center" }, children: [
4745
+ showDivider && /* @__PURE__ */ jsx20("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
1651
4746
  visible.map(renderActionButton)
1652
4747
  ] }, gi);
1653
4748
  });
@@ -1668,9 +4763,9 @@ function Toolbar({ api, features, extensions }) {
1668
4763
  if (e.command) void api.executeCommand(e.command, e.commandParams);
1669
4764
  else e.onClick?.(api);
1670
4765
  };
1671
- return /* @__PURE__ */ jsxs7("div", { style: BAR_STYLE, "data-testid": "casual-sheets-toolbar", role: "toolbar", "aria-label": "Editor", children: [
1672
- showFont && /* @__PURE__ */ jsxs7(Fragment2, { children: [
1673
- /* @__PURE__ */ jsx8(
4766
+ return /* @__PURE__ */ jsxs19("div", { style: BAR_STYLE, "data-testid": "casual-sheets-toolbar", role: "toolbar", "aria-label": "Editor", children: [
4767
+ showFont && /* @__PURE__ */ jsxs19(Fragment14, { children: [
4768
+ /* @__PURE__ */ jsx20(
1674
4769
  "select",
1675
4770
  {
1676
4771
  "aria-label": "Font family",
@@ -1679,10 +4774,10 @@ function Toolbar({ api, features, extensions }) {
1679
4774
  value: familyValue,
1680
4775
  disabled: !api,
1681
4776
  onChange: (e) => dispatch("sheet.command.set-range-font-family", { value: e.target.value }),
1682
- children: familyOptions.map((f) => /* @__PURE__ */ jsx8("option", { value: f, children: f }, f))
4777
+ children: familyOptions.map((f) => /* @__PURE__ */ jsx20("option", { value: f, children: f }, f))
1683
4778
  }
1684
4779
  ),
1685
- /* @__PURE__ */ jsx8(
4780
+ /* @__PURE__ */ jsx20(
1686
4781
  "select",
1687
4782
  {
1688
4783
  "aria-label": "Font size",
@@ -1691,7 +4786,7 @@ function Toolbar({ api, features, extensions }) {
1691
4786
  value: sizeValue,
1692
4787
  disabled: !api,
1693
4788
  onChange: (e) => applyFontSize(Number(e.target.value)),
1694
- children: sizeOptions.map((s) => /* @__PURE__ */ jsx8("option", { value: s, children: s }, s))
4789
+ children: sizeOptions.map((s) => /* @__PURE__ */ jsx20("option", { value: s, children: s }, s))
1695
4790
  }
1696
4791
  ),
1697
4792
  renderIconButton(
@@ -1708,15 +4803,15 @@ function Toolbar({ api, features, extensions }) {
1708
4803
  () => adjustFontSize(-1),
1709
4804
  "cs-font-size-down"
1710
4805
  ),
1711
- /* @__PURE__ */ jsx8("span", { style: DIVIDER_STYLE, "aria-hidden": true })
4806
+ /* @__PURE__ */ jsx20("span", { style: DIVIDER_STYLE, "aria-hidden": true })
1712
4807
  ] }),
1713
4808
  groupNodes,
1714
- (showColor || showBorders) && /* @__PURE__ */ jsx8("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
1715
- showColor && /* @__PURE__ */ jsx8(ColorPicker, { api }),
1716
- showBorders && /* @__PURE__ */ jsx8(BordersPicker, { api }),
1717
- showNumberDropdown && /* @__PURE__ */ jsxs7(Fragment2, { children: [
1718
- /* @__PURE__ */ jsx8("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
1719
- /* @__PURE__ */ jsx8(
4809
+ (showColor || showBorders) && /* @__PURE__ */ jsx20("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
4810
+ showColor && /* @__PURE__ */ jsx20(ColorPicker, { api }),
4811
+ showBorders && /* @__PURE__ */ jsx20(BordersPicker, { api }),
4812
+ showNumberDropdown && /* @__PURE__ */ jsxs19(Fragment14, { children: [
4813
+ /* @__PURE__ */ jsx20("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
4814
+ /* @__PURE__ */ jsx20(
1720
4815
  "select",
1721
4816
  {
1722
4817
  "aria-label": "Number format",
@@ -1725,16 +4820,16 @@ function Toolbar({ api, features, extensions }) {
1725
4820
  value: numberFormatValue,
1726
4821
  disabled: !api,
1727
4822
  onChange: (e) => applyNumberFormat(NUMBER_FORMAT_PATTERNS2[e.target.value]),
1728
- children: NUMBER_FORMAT_OPTIONS2.map((o) => /* @__PURE__ */ jsx8("option", { value: o.value, children: o.label }, o.value))
4823
+ children: NUMBER_FORMAT_OPTIONS2.map((o) => /* @__PURE__ */ jsx20("option", { value: o.value, children: o.label }, o.value))
1729
4824
  }
1730
4825
  )
1731
4826
  ] }),
1732
- showAutoSum && /* @__PURE__ */ jsxs7(Fragment2, { children: [
1733
- /* @__PURE__ */ jsx8("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
1734
- /* @__PURE__ */ jsx8(AutoSumPicker, { api })
4827
+ showAutoSum && /* @__PURE__ */ jsxs19(Fragment14, { children: [
4828
+ /* @__PURE__ */ jsx20("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
4829
+ /* @__PURE__ */ jsx20(AutoSumPicker, { api })
1735
4830
  ] }),
1736
- showDialogGroup && /* @__PURE__ */ jsxs7(Fragment2, { children: [
1737
- /* @__PURE__ */ jsx8("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
4831
+ showDialogGroup && /* @__PURE__ */ jsxs19(Fragment14, { children: [
4832
+ /* @__PURE__ */ jsx20("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
1738
4833
  showFormatCells && renderIconButton(
1739
4834
  "format-cells",
1740
4835
  "Format Cells\u2026",
@@ -1757,8 +4852,8 @@ function Toolbar({ api, features, extensions }) {
1757
4852
  "cs-pivot-table"
1758
4853
  )
1759
4854
  ] }),
1760
- toolbarExt.length > 0 && /* @__PURE__ */ jsxs7(Fragment2, { children: [
1761
- /* @__PURE__ */ jsx8("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
4855
+ toolbarExt.length > 0 && /* @__PURE__ */ jsxs19(Fragment14, { children: [
4856
+ /* @__PURE__ */ jsx20("span", { style: DIVIDER_STYLE, "aria-hidden": true }),
1762
4857
  toolbarExt.map(
1763
4858
  (e) => renderIconButton(e.id, e.label, e.icon, () => runExt(e), `cs-ext-${e.id}`)
1764
4859
  )
@@ -1769,16 +4864,16 @@ function Toolbar({ api, features, extensions }) {
1769
4864
  // src/chrome/FormulaBar.tsx
1770
4865
  import {
1771
4866
  useEffect as useEffect8,
1772
- useMemo as useMemo3,
4867
+ useMemo as useMemo15,
1773
4868
  useRef as useRef6,
1774
- useState as useState8
4869
+ useState as useState20
1775
4870
  } from "react";
1776
4871
  import { ICommandService as ICommandService3 } from "@univerjs/core";
1777
4872
 
1778
4873
  // src/chrome/NameBox.tsx
1779
- import { useEffect as useEffect7, useRef as useRef5, useState as useState7 } from "react";
4874
+ import { useEffect as useEffect7, useRef as useRef5, useState as useState19 } from "react";
1780
4875
  import { ICommandService as ICommandService2 } from "@univerjs/core";
1781
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
4876
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
1782
4877
  function readDefinedNames(api) {
1783
4878
  if (!api) return [];
1784
4879
  try {
@@ -1888,13 +4983,13 @@ var ITEM_REF_STYLE = {
1888
4983
  flex: "0 0 auto"
1889
4984
  };
1890
4985
  function NameBox({ api }) {
1891
- const [ref, setRef] = useState7("");
1892
- const [draft, setDraft] = useState7(null);
4986
+ const [ref, setRef] = useState19("");
4987
+ const [draft, setDraft] = useState19(null);
1893
4988
  const draftRef = useRef5(null);
1894
4989
  draftRef.current = draft;
1895
4990
  const inputRef = useRef5(null);
1896
- const [open, setOpen] = useState7(false);
1897
- const [names, setNames] = useState7([]);
4991
+ const [open, setOpen] = useState19(false);
4992
+ const [names, setNames] = useState19([]);
1898
4993
  const rootRef = useRef5(null);
1899
4994
  useEffect7(() => {
1900
4995
  if (!api) return;
@@ -1969,8 +5064,8 @@ function NameBox({ api }) {
1969
5064
  }
1970
5065
  };
1971
5066
  const shown = draft ?? ref;
1972
- return /* @__PURE__ */ jsxs8("div", { ref: rootRef, style: ROOT_STYLE, children: [
1973
- /* @__PURE__ */ jsx9(
5067
+ return /* @__PURE__ */ jsxs20("div", { ref: rootRef, style: ROOT_STYLE, children: [
5068
+ /* @__PURE__ */ jsx21(
1974
5069
  "input",
1975
5070
  {
1976
5071
  ref: inputRef,
@@ -1992,7 +5087,7 @@ function NameBox({ api }) {
1992
5087
  }
1993
5088
  }
1994
5089
  ),
1995
- /* @__PURE__ */ jsx9(
5090
+ /* @__PURE__ */ jsx21(
1996
5091
  "button",
1997
5092
  {
1998
5093
  type: "button",
@@ -2011,10 +5106,10 @@ function NameBox({ api }) {
2011
5106
  e.preventDefault();
2012
5107
  toggleDropdown();
2013
5108
  },
2014
- children: /* @__PURE__ */ jsx9(Icon, { name: "expand_more", size: 18 })
5109
+ children: /* @__PURE__ */ jsx21(Icon, { name: "expand_more", size: 18 })
2015
5110
  }
2016
5111
  ),
2017
- open && /* @__PURE__ */ jsx9("div", { style: MENU_STYLE, role: "menu", "data-testid": "cs-namebox-menu", children: names.length === 0 ? /* @__PURE__ */ jsx9("div", { style: MENU_EMPTY_STYLE, children: "No names" }) : names.map((entry, i) => /* @__PURE__ */ jsxs8(
5112
+ open && /* @__PURE__ */ jsx21("div", { style: MENU_STYLE, role: "menu", "data-testid": "cs-namebox-menu", children: names.length === 0 ? /* @__PURE__ */ jsx21("div", { style: MENU_EMPTY_STYLE, children: "No names" }) : names.map((entry, i) => /* @__PURE__ */ jsxs20(
2018
5113
  "button",
2019
5114
  {
2020
5115
  type: "button",
@@ -2033,8 +5128,8 @@ function NameBox({ api }) {
2033
5128
  e.currentTarget.style.background = "transparent";
2034
5129
  },
2035
5130
  children: [
2036
- /* @__PURE__ */ jsx9("span", { children: entry.name }),
2037
- entry.ref && /* @__PURE__ */ jsx9("span", { style: ITEM_REF_STYLE, children: entry.ref })
5131
+ /* @__PURE__ */ jsx21("span", { children: entry.name }),
5132
+ entry.ref && /* @__PURE__ */ jsx21("span", { style: ITEM_REF_STYLE, children: entry.ref })
2038
5133
  ]
2039
5134
  },
2040
5135
  entry.name
@@ -2043,8 +5138,8 @@ function NameBox({ api }) {
2043
5138
  }
2044
5139
 
2045
5140
  // src/chrome/FormulaBar.tsx
2046
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2047
- var FUNCTIONS = [
5141
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
5142
+ var FUNCTIONS2 = [
2048
5143
  "ABS",
2049
5144
  "AND",
2050
5145
  "AVERAGE",
@@ -2148,7 +5243,7 @@ function suggestFor(draft) {
2148
5243
  const m = TOKEN_RE.exec(draft);
2149
5244
  if (!m) return [];
2150
5245
  const prefix = m[1].toUpperCase();
2151
- return FUNCTIONS.filter((f) => f.startsWith(prefix) && f !== prefix).slice(0, 8);
5246
+ return FUNCTIONS2.filter((f) => f.startsWith(prefix) && f !== prefix).slice(0, 8);
2152
5247
  }
2153
5248
  function colToLetters2(col) {
2154
5249
  let s = "";
@@ -2231,12 +5326,12 @@ var AC_ITEM_STYLE = {
2231
5326
  cursor: "pointer"
2232
5327
  };
2233
5328
  function FormulaBar({ api }) {
2234
- const [cell, setCell] = useState8(null);
2235
- const [draft, setDraft] = useState8(null);
5329
+ const [cell, setCell] = useState20(null);
5330
+ const [draft, setDraft] = useState20(null);
2236
5331
  const draftRef = useRef6(null);
2237
5332
  draftRef.current = draft;
2238
- const [acIdx, setAcIdx] = useState8(0);
2239
- const [acDismissed, setAcDismissed] = useState8(false);
5333
+ const [acIdx, setAcIdx] = useState20(0);
5334
+ const [acDismissed, setAcDismissed] = useState20(false);
2240
5335
  useEffect8(() => {
2241
5336
  if (!api) return;
2242
5337
  const refresh = () => {
@@ -2249,7 +5344,7 @@ function FormulaBar({ api }) {
2249
5344
  const sub = cmd?.onCommandExecuted(() => refresh());
2250
5345
  return () => sub?.dispose();
2251
5346
  }, [api]);
2252
- const suggestions = useMemo3(() => suggestFor(draft), [draft]);
5347
+ const suggestions = useMemo15(() => suggestFor(draft), [draft]);
2253
5348
  const acOpen = !acDismissed && suggestions.length > 0;
2254
5349
  const commit = (text) => {
2255
5350
  setDraft(null);
@@ -2307,11 +5402,11 @@ function FormulaBar({ api }) {
2307
5402
  }
2308
5403
  };
2309
5404
  const shown = draft ?? cell?.text ?? "";
2310
- return /* @__PURE__ */ jsxs9("div", { style: BAR_STYLE2, "data-testid": "casual-sheets-formula-bar", children: [
2311
- /* @__PURE__ */ jsx10(NameBox, { api }),
2312
- /* @__PURE__ */ jsx10("span", { style: FX_STYLE, "aria-hidden": true, children: "fx" }),
2313
- /* @__PURE__ */ jsxs9("div", { style: INPUT_WRAP_STYLE, children: [
2314
- /* @__PURE__ */ jsx10(
5405
+ return /* @__PURE__ */ jsxs21("div", { style: BAR_STYLE2, "data-testid": "casual-sheets-formula-bar", children: [
5406
+ /* @__PURE__ */ jsx22(NameBox, { api }),
5407
+ /* @__PURE__ */ jsx22("span", { style: FX_STYLE, "aria-hidden": true, children: "fx" }),
5408
+ /* @__PURE__ */ jsxs21("div", { style: INPUT_WRAP_STYLE, children: [
5409
+ /* @__PURE__ */ jsx22(
2315
5410
  "input",
2316
5411
  {
2317
5412
  type: "text",
@@ -2327,7 +5422,7 @@ function FormulaBar({ api }) {
2327
5422
  disabled: !api
2328
5423
  }
2329
5424
  ),
2330
- acOpen && /* @__PURE__ */ jsx10("div", { style: AC_STYLE, "data-testid": "cs-formula-suggestions", role: "listbox", children: suggestions.map((fn, i) => /* @__PURE__ */ jsx10(
5425
+ acOpen && /* @__PURE__ */ jsx22("div", { style: AC_STYLE, "data-testid": "cs-formula-suggestions", role: "listbox", children: suggestions.map((fn, i) => /* @__PURE__ */ jsx22(
2331
5426
  "button",
2332
5427
  {
2333
5428
  type: "button",
@@ -2353,9 +5448,9 @@ function FormulaBar({ api }) {
2353
5448
  }
2354
5449
 
2355
5450
  // src/chrome/StatusBar.tsx
2356
- import { useEffect as useEffect9, useState as useState9 } from "react";
5451
+ import { useEffect as useEffect9, useState as useState21 } from "react";
2357
5452
  import { ICommandService as ICommandService4 } from "@univerjs/core";
2358
- import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
5453
+ import { Fragment as Fragment15, jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
2359
5454
  function readStats(api) {
2360
5455
  const sel = api.getSelection();
2361
5456
  const sheet = api.univer.getActiveWorkbook()?.getActiveSheet();
@@ -2438,8 +5533,8 @@ var ZOOM_LEVEL_STYLE = {
2438
5533
  textAlign: "center"
2439
5534
  };
2440
5535
  function StatusBar({ api }) {
2441
- const [stats, setStats] = useState9(null);
2442
- const [zoom, setZoom] = useState9(1);
5536
+ const [stats, setStats] = useState21(null);
5537
+ const [zoom, setZoom] = useState21(1);
2443
5538
  useEffect9(() => {
2444
5539
  if (!api) return;
2445
5540
  const refresh = () => {
@@ -2466,37 +5561,37 @@ function StatusBar({ api }) {
2466
5561
  };
2467
5562
  const zoomBy = (delta) => setZoomRatio(Math.round((zoom + delta) * 100) / 100);
2468
5563
  const resetZoom = () => setZoomRatio(1);
2469
- return /* @__PURE__ */ jsxs10("div", { style: BAR_STYLE3, "data-testid": "casual-sheets-status-bar", children: [
2470
- stats && /* @__PURE__ */ jsxs10(Fragment3, { children: [
2471
- stats.numCount > 0 && /* @__PURE__ */ jsxs10("span", { "data-stat": "average", children: [
5564
+ return /* @__PURE__ */ jsxs22("div", { style: BAR_STYLE3, "data-testid": "casual-sheets-status-bar", children: [
5565
+ stats && /* @__PURE__ */ jsxs22(Fragment15, { children: [
5566
+ stats.numCount > 0 && /* @__PURE__ */ jsxs22("span", { "data-stat": "average", children: [
2472
5567
  "Average: ",
2473
5568
  fmt(stats.avg)
2474
5569
  ] }),
2475
- /* @__PURE__ */ jsxs10("span", { "data-stat": "count", children: [
5570
+ /* @__PURE__ */ jsxs22("span", { "data-stat": "count", children: [
2476
5571
  "Count: ",
2477
5572
  stats.count
2478
5573
  ] }),
2479
- stats.numCount > 0 && /* @__PURE__ */ jsxs10(Fragment3, { children: [
2480
- /* @__PURE__ */ jsxs10("span", { "data-stat": "num-count", children: [
5574
+ stats.numCount > 0 && /* @__PURE__ */ jsxs22(Fragment15, { children: [
5575
+ /* @__PURE__ */ jsxs22("span", { "data-stat": "num-count", children: [
2481
5576
  "Numerical Count: ",
2482
5577
  stats.numCount
2483
5578
  ] }),
2484
- /* @__PURE__ */ jsxs10("span", { "data-stat": "min", children: [
5579
+ /* @__PURE__ */ jsxs22("span", { "data-stat": "min", children: [
2485
5580
  "Min: ",
2486
5581
  fmt(stats.min)
2487
5582
  ] }),
2488
- /* @__PURE__ */ jsxs10("span", { "data-stat": "max", children: [
5583
+ /* @__PURE__ */ jsxs22("span", { "data-stat": "max", children: [
2489
5584
  "Max: ",
2490
5585
  fmt(stats.max)
2491
5586
  ] }),
2492
- /* @__PURE__ */ jsxs10("span", { "data-stat": "sum", children: [
5587
+ /* @__PURE__ */ jsxs22("span", { "data-stat": "sum", children: [
2493
5588
  "Sum: ",
2494
5589
  fmt(stats.sum)
2495
5590
  ] })
2496
5591
  ] })
2497
5592
  ] }),
2498
- /* @__PURE__ */ jsxs10("span", { style: ZOOM_GROUP_STYLE, "data-testid": "cs-zoom", children: [
2499
- /* @__PURE__ */ jsx11(
5593
+ /* @__PURE__ */ jsxs22("span", { style: ZOOM_GROUP_STYLE, "data-testid": "cs-zoom", children: [
5594
+ /* @__PURE__ */ jsx23(
2500
5595
  "button",
2501
5596
  {
2502
5597
  type: "button",
@@ -2512,7 +5607,7 @@ function StatusBar({ api }) {
2512
5607
  children: "\u2212"
2513
5608
  }
2514
5609
  ),
2515
- /* @__PURE__ */ jsxs10(
5610
+ /* @__PURE__ */ jsxs22(
2516
5611
  "button",
2517
5612
  {
2518
5613
  type: "button",
@@ -2531,7 +5626,7 @@ function StatusBar({ api }) {
2531
5626
  ]
2532
5627
  }
2533
5628
  ),
2534
- /* @__PURE__ */ jsx11(
5629
+ /* @__PURE__ */ jsx23(
2535
5630
  "button",
2536
5631
  {
2537
5632
  type: "button",
@@ -2552,7 +5647,7 @@ function StatusBar({ api }) {
2552
5647
  }
2553
5648
 
2554
5649
  // src/chrome/MenuBar.tsx
2555
- import { useEffect as useEffect10, useRef as useRef7, useState as useState10 } from "react";
5650
+ import { useEffect as useEffect10, useRef as useRef7, useState as useState22 } from "react";
2556
5651
  import { BorderStyleTypes as BorderStyleTypes2, BorderType as BorderType2 } from "@univerjs/core";
2557
5652
 
2558
5653
  // src/chrome/openExternal.ts
@@ -2764,7 +5859,7 @@ function computeVisibleMenus(menus, features, canOpen, ext) {
2764
5859
  }
2765
5860
 
2766
5861
  // src/chrome/MenuBar.tsx
2767
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
5862
+ import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
2768
5863
  function fmtShortcut(shortcut) {
2769
5864
  const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/i.test(navigator.platform || "");
2770
5865
  if (!isMac) return shortcut;
@@ -2784,14 +5879,14 @@ function fmtShortcut(shortcut) {
2784
5879
  function fu(api) {
2785
5880
  return api.univer;
2786
5881
  }
2787
- function activeRange2(api) {
5882
+ function activeRange12(api) {
2788
5883
  return fu(api).getActiveWorkbook()?.getActiveSheet()?.getActiveRange() ?? null;
2789
5884
  }
2790
- function activeSheet(api) {
5885
+ function activeSheet3(api) {
2791
5886
  return fu(api).getActiveWorkbook()?.getActiveSheet() ?? null;
2792
5887
  }
2793
5888
  function selectionA1(api) {
2794
- const range = activeRange2(api);
5889
+ const range = activeRange12(api);
2795
5890
  if (!range) return null;
2796
5891
  try {
2797
5892
  return range.getA1Notation();
@@ -2806,38 +5901,38 @@ var copy = (api) => void api.executeCommand("univer.command.copy");
2806
5901
  var paste = (api) => void api.executeCommand("univer.command.paste");
2807
5902
  var pasteFormattingOnly = (api) => void api.executeCommand("sheet.command.paste-format");
2808
5903
  var insertRowAbove = (api) => {
2809
- const range = activeRange2(api);
2810
- const sheet = activeSheet(api);
5904
+ const range = activeRange12(api);
5905
+ const sheet = activeSheet3(api);
2811
5906
  if (!range || !sheet) return;
2812
5907
  sheet.insertRowBefore(range.getRow());
2813
5908
  };
2814
5909
  var insertRowBelow = (api) => {
2815
- const range = activeRange2(api);
2816
- const sheet = activeSheet(api);
5910
+ const range = activeRange12(api);
5911
+ const sheet = activeSheet3(api);
2817
5912
  if (!range || !sheet) return;
2818
5913
  sheet.insertRowAfter(range.getRow() + range.getHeight() - 1);
2819
5914
  };
2820
5915
  var insertColumnLeft = (api) => {
2821
- const range = activeRange2(api);
2822
- const sheet = activeSheet(api);
5916
+ const range = activeRange12(api);
5917
+ const sheet = activeSheet3(api);
2823
5918
  if (!range || !sheet) return;
2824
5919
  sheet.insertColumnBefore(range.getColumn());
2825
5920
  };
2826
5921
  var insertColumnRight = (api) => {
2827
- const range = activeRange2(api);
2828
- const sheet = activeSheet(api);
5922
+ const range = activeRange12(api);
5923
+ const sheet = activeSheet3(api);
2829
5924
  if (!range || !sheet) return;
2830
5925
  sheet.insertColumnAfter(range.getColumn() + range.getWidth() - 1);
2831
5926
  };
2832
5927
  var deleteSelectedRow = (api) => {
2833
- const range = activeRange2(api);
2834
- const sheet = activeSheet(api);
5928
+ const range = activeRange12(api);
5929
+ const sheet = activeSheet3(api);
2835
5930
  if (!range || !sheet) return;
2836
5931
  sheet.deleteRows(range.getRow(), range.getHeight());
2837
5932
  };
2838
5933
  var deleteSelectedColumn = (api) => {
2839
- const range = activeRange2(api);
2840
- const sheet = activeSheet(api);
5934
+ const range = activeRange12(api);
5935
+ const sheet = activeSheet3(api);
2841
5936
  if (!range || !sheet) return;
2842
5937
  sheet.deleteColumns(range.getColumn(), range.getWidth());
2843
5938
  };
@@ -2848,7 +5943,7 @@ var insertImage = (api) => void api.executeCommand("sheet.command.insert-float-i
2848
5943
  var insertHyperlink = (api) => void api.executeCommand("sheet.operation.insert-hyper-link");
2849
5944
  var insertComment = (api) => void api.executeCommand("sheet.operation.show-comment-modal");
2850
5945
  var insertTodayDate = (api) => {
2851
- const range = activeRange2(api);
5946
+ const range = activeRange12(api);
2852
5947
  if (!range) return;
2853
5948
  const today = /* @__PURE__ */ new Date();
2854
5949
  const pad = (n) => n.toString().padStart(2, "0");
@@ -2856,7 +5951,7 @@ var insertTodayDate = (api) => {
2856
5951
  range.setValue({ v });
2857
5952
  };
2858
5953
  var insertCurrentTime = (api) => {
2859
- const range = activeRange2(api);
5954
+ const range = activeRange12(api);
2860
5955
  if (!range) return;
2861
5956
  const now = /* @__PURE__ */ new Date();
2862
5957
  const pad = (n) => n.toString().padStart(2, "0");
@@ -2865,8 +5960,8 @@ var insertCurrentTime = (api) => {
2865
5960
  };
2866
5961
  var insertTable = (api) => {
2867
5962
  void (async () => {
2868
- const range = activeRange2(api);
2869
- const sheet = activeSheet(api);
5963
+ const range = activeRange12(api);
5964
+ const sheet = activeSheet3(api);
2870
5965
  const wb = fu(api).getActiveWorkbook();
2871
5966
  if (!range || !sheet || !wb) return;
2872
5967
  await ensurePluginByName("table");
@@ -2883,16 +5978,16 @@ var insertTable = (api) => {
2883
5978
  })();
2884
5979
  };
2885
5980
  var autoFitColumns = (api) => {
2886
- const range = activeRange2(api);
2887
- const sheet = activeSheet(api);
5981
+ const range = activeRange12(api);
5982
+ const sheet = activeSheet3(api);
2888
5983
  if (!range || !sheet) return;
2889
5984
  const withAutoWidth = sheet;
2890
5985
  withAutoWidth.setColumnAutoWidth?.(range.getColumn(), range.getWidth());
2891
5986
  };
2892
5987
  var AUTO_FIT_ROW_CAP = 500;
2893
5988
  var autoFitRows = (api) => {
2894
- const range = activeRange2(api);
2895
- const sheet = activeSheet(api);
5989
+ const range = activeRange12(api);
5990
+ const sheet = activeSheet3(api);
2896
5991
  if (!range || !sheet) return;
2897
5992
  const start = range.getRow();
2898
5993
  const count = Math.min(range.getHeight(), AUTO_FIT_ROW_CAP);
@@ -2931,14 +6026,14 @@ var NUM_FORMAT_SHORTCUT = {
2931
6026
  scientific: "Ctrl+Shift+6"
2932
6027
  };
2933
6028
  function setNumberFormatByKey(api, key) {
2934
- const range = activeRange2(api);
6029
+ const range = activeRange12(api);
2935
6030
  range?.setNumberFormat?.(NUMBER_FORMAT_PATTERNS3[key]);
2936
6031
  }
2937
6032
  var increaseDecimal = (api) => void api.executeCommand("sheet.command.numfmt.add.decimal.command");
2938
6033
  var decreaseDecimal = (api) => void api.executeCommand("sheet.command.numfmt.subtract.decimal.command");
2939
6034
  var clearFormat = (api) => void api.executeCommand("sheet.command.clear-selection-format");
2940
6035
  function applyBorders(api, choice) {
2941
- const range = activeRange2(api);
6036
+ const range = activeRange12(api);
2942
6037
  if (!range) return;
2943
6038
  const type = choice === "all" ? BorderType2.ALL : choice === "outside" ? BorderType2.OUTSIDE : BorderType2.NONE;
2944
6039
  const style = choice === "none" ? BorderStyleTypes2.NONE : BorderStyleTypes2.THIN;
@@ -2946,8 +6041,8 @@ function applyBorders(api, choice) {
2946
6041
  }
2947
6042
  function rowSpan(api) {
2948
6043
  const wb = fu(api).getActiveWorkbook();
2949
- const sheet = activeSheet(api);
2950
- const range = activeRange2(api);
6044
+ const sheet = activeSheet3(api);
6045
+ const range = activeRange12(api);
2951
6046
  if (!wb || !sheet || !range) return null;
2952
6047
  const startRow = range.getRow();
2953
6048
  const endRow = startRow + range.getHeight() - 1;
@@ -2956,8 +6051,8 @@ function rowSpan(api) {
2956
6051
  }
2957
6052
  function colSpan(api) {
2958
6053
  const wb = fu(api).getActiveWorkbook();
2959
- const sheet = activeSheet(api);
2960
- const range = activeRange2(api);
6054
+ const sheet = activeSheet3(api);
6055
+ const range = activeRange12(api);
2961
6056
  if (!wb || !sheet || !range) return null;
2962
6057
  const startColumn = range.getColumn();
2963
6058
  const endColumn = startColumn + range.getWidth() - 1;
@@ -3033,16 +6128,16 @@ var unhideSelectedColumns = (api) => {
3033
6128
  });
3034
6129
  };
3035
6130
  var freezeFirstRow = (api) => {
3036
- activeSheet(api)?.setFrozenRows(1);
6131
+ activeSheet3(api)?.setFrozenRows(1);
3037
6132
  };
3038
6133
  var freezeFirstColumn = (api) => {
3039
- activeSheet(api)?.setFrozenColumns(1);
6134
+ activeSheet3(api)?.setFrozenColumns(1);
3040
6135
  };
3041
6136
  var freezeAtSelection = (api) => void api.executeCommand("sheet.command.set-selection-frozen");
3042
6137
  var unfreezePanes = (api) => void api.executeCommand("sheet.command.cancel-frozen");
3043
6138
  var toggleGridlines = (api) => {
3044
6139
  const wb = fu(api).getActiveWorkbook();
3045
- const sheet = activeSheet(api);
6140
+ const sheet = activeSheet3(api);
3046
6141
  if (!wb || !sheet) return;
3047
6142
  void api.executeCommand("sheet.command.toggle-gridlines", {
3048
6143
  unitId: wb.getId(),
@@ -3052,7 +6147,7 @@ var toggleGridlines = (api) => {
3052
6147
  };
3053
6148
  var toggleCommentPanel = (api) => void api.executeCommand("sheet.operation.toggle-comment-panel");
3054
6149
  var jumpToFirstCell = (api) => {
3055
- activeSheet(api)?.getRange(0, 0).activate();
6150
+ activeSheet3(api)?.getRange(0, 0).activate();
3056
6151
  };
3057
6152
  var switchToPreviousSheet = (api) => switchSheetByDelta(api, -1);
3058
6153
  var switchToNextSheet = (api) => switchSheetByDelta(api, 1);
@@ -3072,7 +6167,7 @@ var showFormulas = (api) => void api.executeCommand("sheet.command.set-show-form
3072
6167
  var sortAsc = (api) => sortRange(api, true);
3073
6168
  var sortDesc = (api) => sortRange(api, false);
3074
6169
  function sortRange(api, ascending) {
3075
- const range = activeRange2(api);
6170
+ const range = activeRange12(api);
3076
6171
  if (!range) return;
3077
6172
  const withSort = range;
3078
6173
  withSort.sort?.({ column: range.getColumn(), ascending });
@@ -3081,8 +6176,8 @@ var toggleFilter = (api) => {
3081
6176
  void (async () => {
3082
6177
  await ensurePluginByName("filter");
3083
6178
  const wb = fu(api).getActiveWorkbook();
3084
- const sheet = activeSheet(api);
3085
- const range = activeRange2(api);
6179
+ const sheet = activeSheet3(api);
6180
+ const range = activeRange12(api);
3086
6181
  if (!wb || !sheet || !range) return;
3087
6182
  const sheetWithFilter = sheet;
3088
6183
  if (sheetWithFilter.getFilter?.()) {
@@ -3788,8 +6883,8 @@ var SUBMENU_PANEL_STYLE = {
3788
6883
  };
3789
6884
  function MenuBar({ api, features = {}, extensions }) {
3790
6885
  const dialogs = useDialogs();
3791
- const [open, setOpen] = useState10(null);
3792
- const [openSubmenu, setOpenSubmenu] = useState10(null);
6886
+ const [open, setOpen] = useState22(null);
6887
+ const [openSubmenu, setOpenSubmenu] = useState22(null);
3793
6888
  const rootRef = useRef7(null);
3794
6889
  useEffect10(() => {
3795
6890
  ensureChromeFonts();
@@ -3832,18 +6927,18 @@ function MenuBar({ api, features = {}, extensions }) {
3832
6927
  const visibleMenus = computeVisibleMenus(MENUS, features, dialogs.canOpen, extensions?.menu);
3833
6928
  const renderItems = (items) => items.map((item) => {
3834
6929
  if (item.kind === "separator") {
3835
- return /* @__PURE__ */ jsx12("div", { style: SEPARATOR_STYLE, role: "separator", "aria-hidden": true }, item.id);
6930
+ return /* @__PURE__ */ jsx24("div", { style: SEPARATOR_STYLE, role: "separator", "aria-hidden": true }, item.id);
3836
6931
  }
3837
6932
  if (item.kind === "submenu") {
3838
6933
  const isSubOpen = openSubmenu === item.id;
3839
- return /* @__PURE__ */ jsxs11(
6934
+ return /* @__PURE__ */ jsxs23(
3840
6935
  "div",
3841
6936
  {
3842
6937
  style: { position: "relative" },
3843
6938
  onMouseEnter: () => setOpenSubmenu(item.id),
3844
6939
  onMouseLeave: () => setOpenSubmenu((cur) => cur === item.id ? null : cur),
3845
6940
  children: [
3846
- /* @__PURE__ */ jsxs11(
6941
+ /* @__PURE__ */ jsxs23(
3847
6942
  "button",
3848
6943
  {
3849
6944
  type: "button",
@@ -3855,19 +6950,19 @@ function MenuBar({ api, features = {}, extensions }) {
3855
6950
  style: { ...ITEM_STYLE3, opacity: api ? 1 : 0.5 },
3856
6951
  onMouseDown: (e) => e.preventDefault(),
3857
6952
  children: [
3858
- item.icon ? /* @__PURE__ */ jsx12(Icon, { name: item.icon, size: 18 }) : /* @__PURE__ */ jsx12("span", { style: { width: 18 }, "aria-hidden": true }),
3859
- /* @__PURE__ */ jsx12("span", { children: item.label }),
3860
- /* @__PURE__ */ jsx12(Icon, { name: "chevron_right", size: 18, style: { marginLeft: "auto" } })
6953
+ item.icon ? /* @__PURE__ */ jsx24(Icon, { name: item.icon, size: 18 }) : /* @__PURE__ */ jsx24("span", { style: { width: 18 }, "aria-hidden": true }),
6954
+ /* @__PURE__ */ jsx24("span", { children: item.label }),
6955
+ /* @__PURE__ */ jsx24(Icon, { name: "chevron_right", size: 18, style: { marginLeft: "auto" } })
3861
6956
  ]
3862
6957
  }
3863
6958
  ),
3864
- isSubOpen && /* @__PURE__ */ jsx12("div", { style: SUBMENU_PANEL_STYLE, role: "menu", "aria-label": item.label, children: renderItems(item.items) })
6959
+ isSubOpen && /* @__PURE__ */ jsx24("div", { style: SUBMENU_PANEL_STYLE, role: "menu", "aria-label": item.label, children: renderItems(item.items) })
3865
6960
  ]
3866
6961
  },
3867
6962
  item.id
3868
6963
  );
3869
6964
  }
3870
- return /* @__PURE__ */ jsxs11(
6965
+ return /* @__PURE__ */ jsxs23(
3871
6966
  "button",
3872
6967
  {
3873
6968
  type: "button",
@@ -3887,15 +6982,15 @@ function MenuBar({ api, features = {}, extensions }) {
3887
6982
  e.currentTarget.style.background = "transparent";
3888
6983
  },
3889
6984
  children: [
3890
- item.icon ? /* @__PURE__ */ jsx12(Icon, { name: item.icon, size: 18 }) : /* @__PURE__ */ jsx12("span", { style: { width: 18 }, "aria-hidden": true }),
3891
- /* @__PURE__ */ jsx12("span", { children: item.label }),
3892
- item.shortcut && /* @__PURE__ */ jsx12("span", { style: SHORTCUT_STYLE, children: fmtShortcut(item.shortcut) })
6985
+ item.icon ? /* @__PURE__ */ jsx24(Icon, { name: item.icon, size: 18 }) : /* @__PURE__ */ jsx24("span", { style: { width: 18 }, "aria-hidden": true }),
6986
+ /* @__PURE__ */ jsx24("span", { children: item.label }),
6987
+ item.shortcut && /* @__PURE__ */ jsx24("span", { style: SHORTCUT_STYLE, children: fmtShortcut(item.shortcut) })
3893
6988
  ]
3894
6989
  },
3895
6990
  item.id
3896
6991
  );
3897
6992
  });
3898
- return /* @__PURE__ */ jsx12(
6993
+ return /* @__PURE__ */ jsx24(
3899
6994
  "div",
3900
6995
  {
3901
6996
  ref: rootRef,
@@ -3905,8 +7000,8 @@ function MenuBar({ api, features = {}, extensions }) {
3905
7000
  "aria-label": "Menu bar",
3906
7001
  children: visibleMenus.map((menu) => {
3907
7002
  const isOpen = open === menu.id;
3908
- return /* @__PURE__ */ jsxs11("div", { style: { position: "relative" }, children: [
3909
- /* @__PURE__ */ jsx12(
7003
+ return /* @__PURE__ */ jsxs23("div", { style: { position: "relative" }, children: [
7004
+ /* @__PURE__ */ jsx24(
3910
7005
  "button",
3911
7006
  {
3912
7007
  type: "button",
@@ -3937,7 +7032,7 @@ function MenuBar({ api, features = {}, extensions }) {
3937
7032
  children: menu.label
3938
7033
  }
3939
7034
  ),
3940
- isOpen && /* @__PURE__ */ jsx12("div", { style: DROPDOWN_STYLE, role: "menu", "aria-label": menu.label, children: renderItems(menu.items) })
7035
+ isOpen && /* @__PURE__ */ jsx24("div", { style: DROPDOWN_STYLE, role: "menu", "aria-label": menu.label, children: renderItems(menu.items) })
3941
7036
  ] }, menu.id);
3942
7037
  })
3943
7038
  }
@@ -3945,9 +7040,9 @@ function MenuBar({ api, features = {}, extensions }) {
3945
7040
  }
3946
7041
 
3947
7042
  // src/chrome/SheetTabs.tsx
3948
- import { useEffect as useEffect11, useState as useState11 } from "react";
7043
+ import { useEffect as useEffect11, useState as useState23 } from "react";
3949
7044
  import { createPortal as createPortal2 } from "react-dom";
3950
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
7045
+ import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
3951
7046
  var EMPTY = { tabs: [], activeId: null };
3952
7047
  var SHEET_LIST_MUTATIONS = /* @__PURE__ */ new Set([
3953
7048
  "sheet.mutation.insert-sheet",
@@ -3980,7 +7075,7 @@ var BAR_STYLE5 = {
3980
7075
  overflowX: "auto",
3981
7076
  overflowY: "hidden"
3982
7077
  };
3983
- var ADD_BTN_STYLE = {
7078
+ var ADD_BTN_STYLE2 = {
3984
7079
  flex: "0 0 auto",
3985
7080
  width: 28,
3986
7081
  border: "none",
@@ -4028,10 +7123,10 @@ var MENU_ITEM_STYLE2 = {
4028
7123
  cursor: "pointer"
4029
7124
  };
4030
7125
  function SheetTabs({ api }) {
4031
- const [{ tabs, activeId }, setSnapshot] = useState11(EMPTY);
4032
- const [renaming, setRenaming] = useState11(null);
4033
- const [draft, setDraft] = useState11("");
4034
- const [menu, setMenu] = useState11(null);
7126
+ const [{ tabs, activeId }, setSnapshot] = useState23(EMPTY);
7127
+ const [renaming, setRenaming] = useState23(null);
7128
+ const [draft, setDraft] = useState23("");
7129
+ const [menu, setMenu] = useState23(null);
4035
7130
  useEffect11(() => {
4036
7131
  if (!api) return;
4037
7132
  const refresh = () => setSnapshot(readSheets(api));
@@ -4071,7 +7166,7 @@ function SheetTabs({ api }) {
4071
7166
  };
4072
7167
  }, [menu]);
4073
7168
  if (!api) {
4074
- return /* @__PURE__ */ jsx13("div", { style: BAR_STYLE5, "data-testid": "casual-sheets-tabs" });
7169
+ return /* @__PURE__ */ jsx25("div", { style: BAR_STYLE5, "data-testid": "casual-sheets-tabs" });
4075
7170
  }
4076
7171
  const visible = tabs.filter((t) => !t.hidden);
4077
7172
  const wb = () => api.univer.getActiveWorkbook();
@@ -4111,11 +7206,11 @@ function SheetTabs({ api }) {
4111
7206
  setRenaming(null);
4112
7207
  }
4113
7208
  };
4114
- return /* @__PURE__ */ jsxs12("div", { style: BAR_STYLE5, "data-testid": "casual-sheets-tabs", role: "tablist", children: [
7209
+ return /* @__PURE__ */ jsxs24("div", { style: BAR_STYLE5, "data-testid": "casual-sheets-tabs", role: "tablist", children: [
4115
7210
  visible.map((tab) => {
4116
7211
  const active = tab.id === activeId;
4117
7212
  if (renaming === tab.id) {
4118
- return /* @__PURE__ */ jsx13(
7213
+ return /* @__PURE__ */ jsx25(
4119
7214
  "input",
4120
7215
  {
4121
7216
  autoFocus: true,
@@ -4129,7 +7224,7 @@ function SheetTabs({ api }) {
4129
7224
  tab.id
4130
7225
  );
4131
7226
  }
4132
- return /* @__PURE__ */ jsx13(
7227
+ return /* @__PURE__ */ jsx25(
4133
7228
  "button",
4134
7229
  {
4135
7230
  type: "button",
@@ -4168,11 +7263,11 @@ function SheetTabs({ api }) {
4168
7263
  tab.id
4169
7264
  );
4170
7265
  }),
4171
- /* @__PURE__ */ jsx13(
7266
+ /* @__PURE__ */ jsx25(
4172
7267
  "button",
4173
7268
  {
4174
7269
  type: "button",
4175
- style: ADD_BTN_STYLE,
7270
+ style: ADD_BTN_STYLE2,
4176
7271
  "aria-label": "Add sheet",
4177
7272
  title: "Add sheet",
4178
7273
  "data-testid": "cs-tab-add",
@@ -4184,7 +7279,7 @@ function SheetTabs({ api }) {
4184
7279
  }
4185
7280
  ),
4186
7281
  menu && createPortal2(
4187
- /* @__PURE__ */ jsxs12(
7282
+ /* @__PURE__ */ jsxs24(
4188
7283
  "div",
4189
7284
  {
4190
7285
  style: { ...MENU_STYLE2, left: menu.x, top: menu.y, transform: "translateY(-100%)" },
@@ -4192,7 +7287,7 @@ function SheetTabs({ api }) {
4192
7287
  role: "menu",
4193
7288
  onPointerDown: (e) => e.stopPropagation(),
4194
7289
  children: [
4195
- /* @__PURE__ */ jsx13(
7290
+ /* @__PURE__ */ jsx25(
4196
7291
  "button",
4197
7292
  {
4198
7293
  type: "button",
@@ -4207,7 +7302,7 @@ function SheetTabs({ api }) {
4207
7302
  children: "Rename"
4208
7303
  }
4209
7304
  ),
4210
- /* @__PURE__ */ jsx13(
7305
+ /* @__PURE__ */ jsx25(
4211
7306
  "button",
4212
7307
  {
4213
7308
  type: "button",
@@ -4236,11 +7331,11 @@ function SheetTabs({ api }) {
4236
7331
  // src/chrome/FindReplace.tsx
4237
7332
  import {
4238
7333
  useEffect as useEffect12,
4239
- useMemo as useMemo4,
7334
+ useMemo as useMemo16,
4240
7335
  useRef as useRef8,
4241
- useState as useState12
7336
+ useState as useState24
4242
7337
  } from "react";
4243
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
7338
+ import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
4244
7339
  function findMatches(api, query, matchCase) {
4245
7340
  if (!query) return [];
4246
7341
  const snap = api.getSnapshot();
@@ -4278,7 +7373,7 @@ var WRAP_STYLE = {
4278
7373
  fontSize: 13,
4279
7374
  color: "var(--cs-chrome-fg, #201f1e)"
4280
7375
  };
4281
- var ROW_STYLE4 = { display: "flex", alignItems: "center", gap: 6, marginBottom: 6 };
7376
+ var ROW_STYLE5 = { display: "flex", alignItems: "center", gap: 6, marginBottom: 6 };
4282
7377
  var INPUT_STYLE2 = {
4283
7378
  flex: "1 1 auto",
4284
7379
  height: 26,
@@ -4316,12 +7411,12 @@ var ICON_BTN_STYLE = {
4316
7411
  padding: 0
4317
7412
  };
4318
7413
  function FindReplace({ api, openSignal, openInReplaceMode }) {
4319
- const [open, setOpen] = useState12(false);
4320
- const [showReplace, setShowReplace] = useState12(false);
4321
- const [query, setQuery] = useState12("");
4322
- const [replaceText, setReplaceText] = useState12("");
4323
- const [matchCase, setMatchCase] = useState12(false);
4324
- const [idx, setIdx] = useState12(0);
7414
+ const [open, setOpen] = useState24(false);
7415
+ const [showReplace, setShowReplace] = useState24(false);
7416
+ const [query, setQuery] = useState24("");
7417
+ const [replaceText, setReplaceText] = useState24("");
7418
+ const [matchCase, setMatchCase] = useState24(false);
7419
+ const [idx, setIdx] = useState24(0);
4325
7420
  const inputRef = useRef8(null);
4326
7421
  useEffect12(() => {
4327
7422
  const onKey = (e) => {
@@ -4350,7 +7445,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4350
7445
  setOpen(true);
4351
7446
  requestAnimationFrame(() => inputRef.current?.focus());
4352
7447
  }, [openSignal, openInReplaceMode]);
4353
- const matches = useMemo4(
7448
+ const matches = useMemo16(
4354
7449
  () => api && open && query ? findMatches(api, query, matchCase) : [],
4355
7450
  [api, open, query, matchCase]
4356
7451
  );
@@ -4400,7 +7495,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4400
7495
  };
4401
7496
  const count = matches.length;
4402
7497
  const position = count === 0 ? 0 : Math.min(idx, count - 1) + 1;
4403
- return /* @__PURE__ */ jsxs13(
7498
+ return /* @__PURE__ */ jsxs25(
4404
7499
  "div",
4405
7500
  {
4406
7501
  style: WRAP_STYLE,
@@ -4408,8 +7503,8 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4408
7503
  role: "dialog",
4409
7504
  "aria-label": "Find and replace",
4410
7505
  children: [
4411
- /* @__PURE__ */ jsxs13("div", { style: ROW_STYLE4, children: [
4412
- /* @__PURE__ */ jsx14(
7506
+ /* @__PURE__ */ jsxs25("div", { style: ROW_STYLE5, children: [
7507
+ /* @__PURE__ */ jsx26(
4413
7508
  "input",
4414
7509
  {
4415
7510
  ref: inputRef,
@@ -4423,7 +7518,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4423
7518
  onKeyDown: onInputKey
4424
7519
  }
4425
7520
  ),
4426
- /* @__PURE__ */ jsxs13(
7521
+ /* @__PURE__ */ jsxs25(
4427
7522
  "span",
4428
7523
  {
4429
7524
  style: { minWidth: 54, textAlign: "center", color: "var(--cs-chrome-muted, #6b7280)" },
@@ -4435,7 +7530,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4435
7530
  ]
4436
7531
  }
4437
7532
  ),
4438
- /* @__PURE__ */ jsx14(
7533
+ /* @__PURE__ */ jsx26(
4439
7534
  "button",
4440
7535
  {
4441
7536
  type: "button",
@@ -4446,10 +7541,10 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4446
7541
  e.preventDefault();
4447
7542
  go(-1);
4448
7543
  },
4449
- children: /* @__PURE__ */ jsx14(Icon, { name: "keyboard_arrow_up", size: 18 })
7544
+ children: /* @__PURE__ */ jsx26(Icon, { name: "keyboard_arrow_up", size: 18 })
4450
7545
  }
4451
7546
  ),
4452
- /* @__PURE__ */ jsx14(
7547
+ /* @__PURE__ */ jsx26(
4453
7548
  "button",
4454
7549
  {
4455
7550
  type: "button",
@@ -4460,10 +7555,10 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4460
7555
  e.preventDefault();
4461
7556
  go(1);
4462
7557
  },
4463
- children: /* @__PURE__ */ jsx14(Icon, { name: "keyboard_arrow_down", size: 18 })
7558
+ children: /* @__PURE__ */ jsx26(Icon, { name: "keyboard_arrow_down", size: 18 })
4464
7559
  }
4465
7560
  ),
4466
- /* @__PURE__ */ jsx14(
7561
+ /* @__PURE__ */ jsx26(
4467
7562
  "button",
4468
7563
  {
4469
7564
  type: "button",
@@ -4474,12 +7569,12 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4474
7569
  e.preventDefault();
4475
7570
  setOpen(false);
4476
7571
  },
4477
- children: /* @__PURE__ */ jsx14(Icon, { name: "close", size: 18 })
7572
+ children: /* @__PURE__ */ jsx26(Icon, { name: "close", size: 18 })
4478
7573
  }
4479
7574
  )
4480
7575
  ] }),
4481
- showReplace && /* @__PURE__ */ jsxs13("div", { style: ROW_STYLE4, children: [
4482
- /* @__PURE__ */ jsx14(
7576
+ showReplace && /* @__PURE__ */ jsxs25("div", { style: ROW_STYLE5, children: [
7577
+ /* @__PURE__ */ jsx26(
4483
7578
  "input",
4484
7579
  {
4485
7580
  type: "text",
@@ -4491,7 +7586,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4491
7586
  onChange: (e) => setReplaceText(e.target.value)
4492
7587
  }
4493
7588
  ),
4494
- /* @__PURE__ */ jsx14(
7589
+ /* @__PURE__ */ jsx26(
4495
7590
  "button",
4496
7591
  {
4497
7592
  type: "button",
@@ -4504,7 +7599,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4504
7599
  children: "Replace"
4505
7600
  }
4506
7601
  ),
4507
- /* @__PURE__ */ jsx14(
7602
+ /* @__PURE__ */ jsx26(
4508
7603
  "button",
4509
7604
  {
4510
7605
  type: "button",
@@ -4518,9 +7613,9 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4518
7613
  }
4519
7614
  )
4520
7615
  ] }),
4521
- /* @__PURE__ */ jsxs13("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
4522
- /* @__PURE__ */ jsxs13("label", { style: { display: "inline-flex", alignItems: "center", gap: 4, cursor: "pointer" }, children: [
4523
- /* @__PURE__ */ jsx14(
7616
+ /* @__PURE__ */ jsxs25("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
7617
+ /* @__PURE__ */ jsxs25("label", { style: { display: "inline-flex", alignItems: "center", gap: 4, cursor: "pointer" }, children: [
7618
+ /* @__PURE__ */ jsx26(
4524
7619
  "input",
4525
7620
  {
4526
7621
  type: "checkbox",
@@ -4531,7 +7626,7 @@ function FindReplace({ api, openSignal, openInReplaceMode }) {
4531
7626
  ),
4532
7627
  "Match case"
4533
7628
  ] }),
4534
- !showReplace && /* @__PURE__ */ jsx14(
7629
+ !showReplace && /* @__PURE__ */ jsx26(
4535
7630
  "button",
4536
7631
  {
4537
7632
  type: "button",
@@ -4575,8 +7670,8 @@ function replaceInString(text, query, replacement, matchCase) {
4575
7670
  }
4576
7671
 
4577
7672
  // src/chrome/ChromeTop.tsx
4578
- import { useCallback as useCallback2, useState as useState13 } from "react";
4579
- import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
7673
+ import { useCallback as useCallback3, useState as useState25 } from "react";
7674
+ import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
4580
7675
  function ChromeTop({
4581
7676
  api,
4582
7677
  features,
@@ -4584,13 +7679,13 @@ function ChromeTop({
4584
7679
  hostOwnedDialogs,
4585
7680
  extensions
4586
7681
  }) {
4587
- const [findSignal, setFindSignal] = useState13(0);
4588
- const [findReplaceMode, setFindReplaceMode] = useState13(false);
4589
- const openFindReplace = useCallback2((replaceMode) => {
7682
+ const [findSignal, setFindSignal] = useState25(0);
7683
+ const [findReplaceMode, setFindReplaceMode] = useState25(false);
7684
+ const openFindReplace = useCallback3((replaceMode) => {
4590
7685
  setFindReplaceMode(replaceMode);
4591
7686
  setFindSignal((n) => n + 1);
4592
7687
  }, []);
4593
- return /* @__PURE__ */ jsxs14(
7688
+ return /* @__PURE__ */ jsxs26(
4594
7689
  DialogProvider,
4595
7690
  {
4596
7691
  api,
@@ -4599,10 +7694,10 @@ function ChromeTop({
4599
7694
  hostOwnedDialogs,
4600
7695
  onOpenFindReplace: openFindReplace,
4601
7696
  children: [
4602
- /* @__PURE__ */ jsx15(MenuBar, { api, features, extensions }),
4603
- /* @__PURE__ */ jsx15(Toolbar, { api, features, extensions }),
4604
- /* @__PURE__ */ jsx15(FormulaBar, { api }),
4605
- /* @__PURE__ */ jsx15(
7697
+ /* @__PURE__ */ jsx27(MenuBar, { api, features, extensions }),
7698
+ /* @__PURE__ */ jsx27(Toolbar, { api, features, extensions }),
7699
+ /* @__PURE__ */ jsx27(FormulaBar, { api }),
7700
+ /* @__PURE__ */ jsx27(
4606
7701
  FindReplace,
4607
7702
  {
4608
7703
  api,
@@ -4616,11 +7711,11 @@ function ChromeTop({
4616
7711
  }
4617
7712
 
4618
7713
  // src/chrome/ChromeBottom.tsx
4619
- import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
7714
+ import { Fragment as Fragment16, jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
4620
7715
  function ChromeBottom({ api }) {
4621
- return /* @__PURE__ */ jsxs15(Fragment4, { children: [
4622
- /* @__PURE__ */ jsx16(SheetTabs, { api }),
4623
- /* @__PURE__ */ jsx16(StatusBar, { api })
7716
+ return /* @__PURE__ */ jsxs27(Fragment16, { children: [
7717
+ /* @__PURE__ */ jsx28(SheetTabs, { api }),
7718
+ /* @__PURE__ */ jsx28(StatusBar, { api })
4624
7719
  ] });
4625
7720
  }
4626
7721
  export {