@ricsam/react-spreadsheets 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -6
- package/dist/cjs/lib.cjs +163 -42
- package/dist/cjs/lib.cjs.map +7 -5
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/lib.mjs +148 -27
- package/dist/mjs/lib.mjs.map +7 -5
- package/dist/mjs/package.json +1 -1
- package/dist/styles.css +290 -71
- package/dist/types/lib.d.ts +1 -0
- package/dist/types/utils/contrast-text.d.ts +36 -0
- package/dist/types/utils/use-scheme-root.d.ts +16 -0
- package/package.json +2 -2
package/dist/cjs/package.json
CHANGED
package/dist/mjs/lib.mjs
CHANGED
|
@@ -69,6 +69,85 @@ function useColorScheme(element) {
|
|
|
69
69
|
return scheme;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// src/utils/contrast-text.ts
|
|
73
|
+
var DARK_INK = "#101828";
|
|
74
|
+
var LIGHT_INK = "#ffffff";
|
|
75
|
+
var NAMED_COLORS = {
|
|
76
|
+
white: [255, 255, 255],
|
|
77
|
+
black: [0, 0, 0],
|
|
78
|
+
red: [255, 0, 0],
|
|
79
|
+
green: [0, 128, 0],
|
|
80
|
+
blue: [0, 0, 255],
|
|
81
|
+
yellow: [255, 255, 0],
|
|
82
|
+
orange: [255, 165, 0],
|
|
83
|
+
purple: [128, 0, 128],
|
|
84
|
+
gray: [128, 128, 128],
|
|
85
|
+
grey: [128, 128, 128],
|
|
86
|
+
silver: [192, 192, 192]
|
|
87
|
+
};
|
|
88
|
+
var clamp255 = (value) => Math.min(255, Math.max(0, value));
|
|
89
|
+
function parseCssColor(input) {
|
|
90
|
+
const value = input.trim().toLowerCase();
|
|
91
|
+
if (!value || value === "transparent" || value === "currentcolor" || value === "inherit") {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (value.includes("var(") || value.includes("color-mix(") || value.includes("gradient")) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const named = NAMED_COLORS[value];
|
|
98
|
+
if (named) {
|
|
99
|
+
return { r: named[0], g: named[1], b: named[2], a: 1 };
|
|
100
|
+
}
|
|
101
|
+
if (value.startsWith("#")) {
|
|
102
|
+
const hex = value.slice(1);
|
|
103
|
+
const expand = (part) => parseInt(part + part, 16);
|
|
104
|
+
if (hex.length === 3 || hex.length === 4) {
|
|
105
|
+
const r = expand(hex[0]);
|
|
106
|
+
const g = expand(hex[1]);
|
|
107
|
+
const b = expand(hex[2]);
|
|
108
|
+
const a = hex.length === 4 ? expand(hex[3]) / 255 : 1;
|
|
109
|
+
return Number.isNaN(r + g + b) ? undefined : { r, g, b, a };
|
|
110
|
+
}
|
|
111
|
+
if (hex.length === 6 || hex.length === 8) {
|
|
112
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
113
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
114
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
115
|
+
const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1;
|
|
116
|
+
return Number.isNaN(r + g + b) ? undefined : { r, g, b, a };
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const rgbMatch = value.match(/^rgba?\(([^)]+)\)$/);
|
|
121
|
+
if (rgbMatch) {
|
|
122
|
+
const parts = rgbMatch[1].split(/[\s,/]+/).filter(Boolean);
|
|
123
|
+
if (parts.length < 3)
|
|
124
|
+
return;
|
|
125
|
+
const toChannel = (part) => part.endsWith("%") ? parseFloat(part) / 100 * 255 : parseFloat(part);
|
|
126
|
+
const r = toChannel(parts[0]);
|
|
127
|
+
const g = toChannel(parts[1]);
|
|
128
|
+
const b = toChannel(parts[2]);
|
|
129
|
+
const alphaPart = parts[3];
|
|
130
|
+
const a = alphaPart === undefined ? 1 : alphaPart.endsWith("%") ? parseFloat(alphaPart) / 100 : parseFloat(alphaPart);
|
|
131
|
+
if ([r, g, b, a].some((channel) => Number.isNaN(channel)))
|
|
132
|
+
return;
|
|
133
|
+
return { r: clamp255(r), g: clamp255(g), b: clamp255(b), a };
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
function relativeLuminance({ r, g, b }) {
|
|
138
|
+
const channel = (value) => {
|
|
139
|
+
const srgb = value / 255;
|
|
140
|
+
return srgb <= 0.03928 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);
|
|
141
|
+
};
|
|
142
|
+
return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
|
|
143
|
+
}
|
|
144
|
+
function getContrastingTextColor(background) {
|
|
145
|
+
const color = parseCssColor(background);
|
|
146
|
+
if (!color || color.a < 0.5)
|
|
147
|
+
return;
|
|
148
|
+
return relativeLuminance(color) > 0.45 ? DARK_INK : LIGHT_INK;
|
|
149
|
+
}
|
|
150
|
+
|
|
72
151
|
// src/utils/cn.ts
|
|
73
152
|
function cn(...values) {
|
|
74
153
|
const out = [];
|
|
@@ -1247,16 +1326,27 @@ var resizeCellSnapAnchorToNearestEdges = (anchor, rect, handle, columnWidths, ro
|
|
|
1247
1326
|
|
|
1248
1327
|
// src/spreadsheet/spreadsheet.tsx
|
|
1249
1328
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1250
|
-
var resolveGridLineColor = (
|
|
1251
|
-
const fallback = colorScheme === "dark" ? "#
|
|
1252
|
-
if (!
|
|
1329
|
+
var resolveGridLineColor = (probe, colorScheme) => {
|
|
1330
|
+
const fallback = colorScheme === "dark" ? "#232c3d" : "#e8ebf1";
|
|
1331
|
+
if (!probe || typeof getComputedStyle !== "function") {
|
|
1253
1332
|
return fallback;
|
|
1254
1333
|
}
|
|
1255
|
-
const
|
|
1256
|
-
if (!
|
|
1334
|
+
const resolved = getComputedStyle(probe).color?.trim();
|
|
1335
|
+
if (!resolved || resolved.includes("light-dark(") || resolved === "rgba(0, 0, 0, 0)") {
|
|
1257
1336
|
return fallback;
|
|
1258
1337
|
}
|
|
1259
|
-
return
|
|
1338
|
+
return resolved;
|
|
1339
|
+
};
|
|
1340
|
+
var withReadableTextColor = (style) => {
|
|
1341
|
+
if (!style?.backgroundColor || style.color)
|
|
1342
|
+
return style;
|
|
1343
|
+
const background = style.backgroundColor;
|
|
1344
|
+
if (typeof background !== "string")
|
|
1345
|
+
return style;
|
|
1346
|
+
const color = getContrastingTextColor(background);
|
|
1347
|
+
if (!color)
|
|
1348
|
+
return style;
|
|
1349
|
+
return { ...style, color };
|
|
1260
1350
|
};
|
|
1261
1351
|
var hasBorderStyle = (style) => Boolean(style?.borderColor || style?.borderTopColor || style?.borderRightColor || style?.borderBottomColor || style?.borderLeftColor);
|
|
1262
1352
|
var CellComponent = React2.memo(({
|
|
@@ -1299,7 +1389,7 @@ var CellComponent = React2.memo(({
|
|
|
1299
1389
|
isSelected,
|
|
1300
1390
|
isBeingEdited: isBeingEdited || false
|
|
1301
1391
|
};
|
|
1302
|
-
const customStyle = customCellStyle?.(cellStyleCallbackData);
|
|
1392
|
+
const customStyle = withReadableTextColor(customCellStyle?.(cellStyleCallbackData));
|
|
1303
1393
|
const canHaveFillHandle = useSelectionManager(selectionManager, () => {
|
|
1304
1394
|
return selectionManager.canCellHaveFillHandle({
|
|
1305
1395
|
row: rowIndex,
|
|
@@ -1331,7 +1421,8 @@ var CellComponent = React2.memo(({
|
|
|
1331
1421
|
top: y,
|
|
1332
1422
|
width: getColumnWidth(col) - 1,
|
|
1333
1423
|
height: getRowHeight(row) - 1,
|
|
1334
|
-
...customStyle
|
|
1424
|
+
...customStyle,
|
|
1425
|
+
...isBeingEdited ? { backgroundColor: undefined, color: undefined } : null
|
|
1335
1426
|
},
|
|
1336
1427
|
children: [
|
|
1337
1428
|
isBeingEdited ? /* @__PURE__ */ jsx3("textarea", {
|
|
@@ -1581,6 +1672,7 @@ var Spreadsheet = forwardRef(({
|
|
|
1581
1672
|
const [{ width, height }, containerRef] = useResizeObserver();
|
|
1582
1673
|
const [containerDivRef, setContainerDivRef] = useState4(null);
|
|
1583
1674
|
const colorScheme = useColorScheme(containerDivRef);
|
|
1675
|
+
const gridLineProbeRef = useRef3(null);
|
|
1584
1676
|
const selectionManager = useInitializeSelectionManager({
|
|
1585
1677
|
getNumCols: () => ({ type: "infinity" }),
|
|
1586
1678
|
getNumRows: () => ({ type: "infinity" }),
|
|
@@ -1774,7 +1866,7 @@ var Spreadsheet = forwardRef(({
|
|
|
1774
1866
|
if (!ctx)
|
|
1775
1867
|
return;
|
|
1776
1868
|
ctx.clearRect(0, 0, width, height);
|
|
1777
|
-
ctx.strokeStyle = resolveGridLineColor(
|
|
1869
|
+
ctx.strokeStyle = resolveGridLineColor(gridLineProbeRef.current, colorScheme);
|
|
1778
1870
|
ctx.lineWidth = 1;
|
|
1779
1871
|
let x = gridDims.headerWidth;
|
|
1780
1872
|
let colIndex = 0;
|
|
@@ -2522,6 +2614,7 @@ var Spreadsheet = forwardRef(({
|
|
|
2522
2614
|
}), [selectionManager]);
|
|
2523
2615
|
return /* @__PURE__ */ jsx3("div", {
|
|
2524
2616
|
className: cn("rsp-root", className),
|
|
2617
|
+
"data-rsp-scheme": colorScheme,
|
|
2525
2618
|
style: { position: "relative", ...style },
|
|
2526
2619
|
...containerProps,
|
|
2527
2620
|
children: /* @__PURE__ */ jsx3("div", {
|
|
@@ -2537,6 +2630,18 @@ var Spreadsheet = forwardRef(({
|
|
|
2537
2630
|
},
|
|
2538
2631
|
tabIndex: 0,
|
|
2539
2632
|
children: [
|
|
2633
|
+
/* @__PURE__ */ jsx3("span", {
|
|
2634
|
+
ref: gridLineProbeRef,
|
|
2635
|
+
"aria-hidden": "true",
|
|
2636
|
+
style: {
|
|
2637
|
+
position: "absolute",
|
|
2638
|
+
width: 0,
|
|
2639
|
+
height: 0,
|
|
2640
|
+
visibility: "hidden",
|
|
2641
|
+
pointerEvents: "none",
|
|
2642
|
+
color: "var(--rsp-gridline)"
|
|
2643
|
+
}
|
|
2644
|
+
}),
|
|
2540
2645
|
/* @__PURE__ */ jsx3("canvas", {
|
|
2541
2646
|
ref: canvasRef,
|
|
2542
2647
|
className: "rsp-canvas",
|
|
@@ -2716,7 +2821,15 @@ import {
|
|
|
2716
2821
|
parseCellReference as parseCellReference2,
|
|
2717
2822
|
getCellReference as getCellReference3
|
|
2718
2823
|
} from "@ricsam/formula-engine";
|
|
2719
|
-
import React3, { useCallback as useCallback4, useRef as useRef4, useState as
|
|
2824
|
+
import React3, { useCallback as useCallback4, useRef as useRef4, useState as useState6 } from "react";
|
|
2825
|
+
|
|
2826
|
+
// src/utils/use-scheme-root.ts
|
|
2827
|
+
import { useState as useState5 } from "react";
|
|
2828
|
+
function useSchemeRoot() {
|
|
2829
|
+
const [element, setElement] = useState5(null);
|
|
2830
|
+
const scheme = useColorScheme(element);
|
|
2831
|
+
return { ref: setElement, "data-rsp-scheme": scheme };
|
|
2832
|
+
}
|
|
2720
2833
|
|
|
2721
2834
|
// src/workbook/border-sides.ts
|
|
2722
2835
|
function normalizeBorderSides(sides, defaultAllWhenUnset = false) {
|
|
@@ -3122,7 +3235,7 @@ var MinusIcon = ({ className = "", ...props }) => /* @__PURE__ */ jsx4("svg", {
|
|
|
3122
3235
|
})
|
|
3123
3236
|
});
|
|
3124
3237
|
function useEngine(engine) {
|
|
3125
|
-
const [state, setState] =
|
|
3238
|
+
const [state, setState] = useState6(() => engine.getState());
|
|
3126
3239
|
React3.useEffect(() => {
|
|
3127
3240
|
return engine.onUpdate(() => {
|
|
3128
3241
|
setState(engine.getState());
|
|
@@ -3227,7 +3340,8 @@ function FormulaSheet({
|
|
|
3227
3340
|
showFormulas = false,
|
|
3228
3341
|
...rest
|
|
3229
3342
|
}) {
|
|
3230
|
-
const
|
|
3343
|
+
const schemeRoot = useSchemeRoot();
|
|
3344
|
+
const [selectedArea, setSelectedArea] = useState6(null);
|
|
3231
3345
|
const clipboardManager = React3.useMemo(() => controlledClipboardManager ?? new WorkbookClipboardManager(engine), [controlledClipboardManager, engine]);
|
|
3232
3346
|
const state = useEngine(engine);
|
|
3233
3347
|
const sheet = state.workbooks.get(workbookName)?.sheets.get(sheetName);
|
|
@@ -3372,6 +3486,7 @@ function FormulaSheet({
|
|
|
3372
3486
|
if (!sheet) {
|
|
3373
3487
|
return /* @__PURE__ */ jsxs3("div", {
|
|
3374
3488
|
className: "rsp-root rsp-workbook",
|
|
3489
|
+
...schemeRoot,
|
|
3375
3490
|
children: [
|
|
3376
3491
|
toolbar,
|
|
3377
3492
|
/* @__PURE__ */ jsx4("div", {
|
|
@@ -3382,6 +3497,7 @@ function FormulaSheet({
|
|
|
3382
3497
|
}
|
|
3383
3498
|
return /* @__PURE__ */ jsxs3("div", {
|
|
3384
3499
|
className: "rsp-root rsp-workbook",
|
|
3500
|
+
...schemeRoot,
|
|
3385
3501
|
children: [
|
|
3386
3502
|
toolbar,
|
|
3387
3503
|
/* @__PURE__ */ jsx4("div", {
|
|
@@ -3452,32 +3568,32 @@ function FormulaSheet({
|
|
|
3452
3568
|
const isLastColumn = cell.colIndex === tableInfo.start.colIndex + tableInfo.headers.size - 1;
|
|
3453
3569
|
const isLastRow = tableInfo.endRow.type === "number" ? cell.rowIndex === tableInfo.endRow.value : false;
|
|
3454
3570
|
const style = {
|
|
3455
|
-
border: "1px solid var(--table-border-light)"
|
|
3571
|
+
border: "1px solid var(--rsp-table-border-light)"
|
|
3456
3572
|
};
|
|
3457
3573
|
if (isHeaderRow) {
|
|
3458
|
-
style.backgroundColor = "var(--table-header-bg)";
|
|
3459
|
-
style.color = "var(--table-header-color)";
|
|
3574
|
+
style.backgroundColor = "var(--rsp-table-header-bg)";
|
|
3575
|
+
style.color = "var(--rsp-table-header-color)";
|
|
3460
3576
|
style.fontWeight = "bold";
|
|
3461
|
-
style.borderBottom = "2px solid var(--table-header-border)";
|
|
3577
|
+
style.borderBottom = "2px solid var(--rsp-table-header-border)";
|
|
3462
3578
|
} else {
|
|
3463
3579
|
const dataRowIndex = cell.rowIndex - tableInfo.start.rowIndex - 1;
|
|
3464
3580
|
if (dataRowIndex % 2 === 0) {
|
|
3465
|
-
style.backgroundColor = "var(--table-even-row-bg)";
|
|
3581
|
+
style.backgroundColor = "var(--rsp-table-even-row-bg)";
|
|
3466
3582
|
} else {
|
|
3467
|
-
style.backgroundColor = "var(--table-odd-row-bg)";
|
|
3583
|
+
style.backgroundColor = "var(--rsp-table-odd-row-bg)";
|
|
3468
3584
|
}
|
|
3469
3585
|
}
|
|
3470
3586
|
if (isFirstColumn) {
|
|
3471
|
-
style.borderLeft = "2px solid var(--table-border-color)";
|
|
3587
|
+
style.borderLeft = "2px solid var(--rsp-table-border-color)";
|
|
3472
3588
|
}
|
|
3473
3589
|
if (isLastColumn) {
|
|
3474
|
-
style.borderRight = "2px solid var(--table-border-color)";
|
|
3590
|
+
style.borderRight = "2px solid var(--rsp-table-border-color)";
|
|
3475
3591
|
}
|
|
3476
3592
|
if (isHeaderRow) {
|
|
3477
|
-
style.borderTop = "2px solid var(--table-border-color)";
|
|
3593
|
+
style.borderTop = "2px solid var(--rsp-table-border-color)";
|
|
3478
3594
|
}
|
|
3479
3595
|
if (isLastRow) {
|
|
3480
|
-
style.borderBottom = "2px solid var(--table-border-color)";
|
|
3596
|
+
style.borderBottom = "2px solid var(--rsp-table-border-color)";
|
|
3481
3597
|
}
|
|
3482
3598
|
if (conditionalStyle?.backgroundColor) {
|
|
3483
3599
|
style.backgroundColor = conditionalStyle.backgroundColor;
|
|
@@ -3613,14 +3729,15 @@ function FormulaWorkbook({
|
|
|
3613
3729
|
showFormulas = false,
|
|
3614
3730
|
...rest
|
|
3615
3731
|
}) {
|
|
3732
|
+
const schemeRoot = useSchemeRoot();
|
|
3616
3733
|
const state = useEngine(engine);
|
|
3617
|
-
const [renamingSheet, setRenamingSheet] =
|
|
3618
|
-
const [newSheetName, setNewSheetName] =
|
|
3619
|
-
const [spreadsheetZoom, setSpreadsheetZoom] =
|
|
3734
|
+
const [renamingSheet, setRenamingSheet] = useState6(null);
|
|
3735
|
+
const [newSheetName, setNewSheetName] = useState6("");
|
|
3736
|
+
const [spreadsheetZoom, setSpreadsheetZoom] = useState6(1);
|
|
3620
3737
|
const renameCommittedRef = useRef4(false);
|
|
3621
3738
|
const clipboardManager = React3.useMemo(() => controlledClipboardManager ?? new WorkbookClipboardManager(engine), [controlledClipboardManager, engine]);
|
|
3622
3739
|
const sheetNames = engine.getOrderedSheetNames(workbookName);
|
|
3623
|
-
const [internalActiveSheet, setInternalActiveSheet] =
|
|
3740
|
+
const [internalActiveSheet, setInternalActiveSheet] = useState6(() => {
|
|
3624
3741
|
return sheetNames[0] || "";
|
|
3625
3742
|
});
|
|
3626
3743
|
const isControlledRef = useRef4(controlledActiveSheet !== undefined);
|
|
@@ -3719,6 +3836,7 @@ function FormulaWorkbook({
|
|
|
3719
3836
|
};
|
|
3720
3837
|
return /* @__PURE__ */ jsxs3("div", {
|
|
3721
3838
|
className: "rsp-root rsp-workbook",
|
|
3839
|
+
...schemeRoot,
|
|
3722
3840
|
children: [
|
|
3723
3841
|
toolbar,
|
|
3724
3842
|
/* @__PURE__ */ jsxs3("div", {
|
|
@@ -3967,6 +4085,7 @@ export {
|
|
|
3967
4085
|
getCellReference,
|
|
3968
4086
|
getCellSnapAnchorFromRect,
|
|
3969
4087
|
getColumnEdgePosition,
|
|
4088
|
+
getContrastingTextColor,
|
|
3970
4089
|
getNearestColumnEdgeIndex,
|
|
3971
4090
|
getNearestRowEdgeIndex,
|
|
3972
4091
|
getRectFromCellSnapAnchor,
|
|
@@ -3980,7 +4099,9 @@ export {
|
|
|
3980
4099
|
normalizeCellSnapAnchor,
|
|
3981
4100
|
onCellEditError,
|
|
3982
4101
|
parseCellReference,
|
|
4102
|
+
parseCssColor,
|
|
3983
4103
|
queueCellEditError,
|
|
4104
|
+
relativeLuminance,
|
|
3984
4105
|
resizeCellSnapAnchorToNearestEdges,
|
|
3985
4106
|
rowToLetter,
|
|
3986
4107
|
useClickAway,
|
|
@@ -3988,4 +4109,4 @@ export {
|
|
|
3988
4109
|
useResizeObserver
|
|
3989
4110
|
};
|
|
3990
4111
|
|
|
3991
|
-
//# debugId=
|
|
4112
|
+
//# debugId=93A3B97B45C8788264756E2164756E21
|