@ricsam/react-spreadsheets 0.0.1 → 0.0.3
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 +31 -6
- package/dist/cjs/lib.cjs +127 -20
- package/dist/cjs/lib.cjs.map +6 -5
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/lib.mjs +127 -20
- package/dist/mjs/lib.mjs.map +6 -5
- package/dist/mjs/package.json +1 -1
- package/dist/styles.css +231 -73
- package/dist/types/lib.d.ts +1 -0
- package/dist/types/utils/contrast-text.d.ts +36 -0
- package/package.json +3 -3
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;
|
|
@@ -2537,6 +2629,18 @@ var Spreadsheet = forwardRef(({
|
|
|
2537
2629
|
},
|
|
2538
2630
|
tabIndex: 0,
|
|
2539
2631
|
children: [
|
|
2632
|
+
/* @__PURE__ */ jsx3("span", {
|
|
2633
|
+
ref: gridLineProbeRef,
|
|
2634
|
+
"aria-hidden": "true",
|
|
2635
|
+
style: {
|
|
2636
|
+
position: "absolute",
|
|
2637
|
+
width: 0,
|
|
2638
|
+
height: 0,
|
|
2639
|
+
visibility: "hidden",
|
|
2640
|
+
pointerEvents: "none",
|
|
2641
|
+
color: "var(--rsp-gridline)"
|
|
2642
|
+
}
|
|
2643
|
+
}),
|
|
2540
2644
|
/* @__PURE__ */ jsx3("canvas", {
|
|
2541
2645
|
ref: canvasRef,
|
|
2542
2646
|
className: "rsp-canvas",
|
|
@@ -3452,32 +3556,32 @@ function FormulaSheet({
|
|
|
3452
3556
|
const isLastColumn = cell.colIndex === tableInfo.start.colIndex + tableInfo.headers.size - 1;
|
|
3453
3557
|
const isLastRow = tableInfo.endRow.type === "number" ? cell.rowIndex === tableInfo.endRow.value : false;
|
|
3454
3558
|
const style = {
|
|
3455
|
-
border: "1px solid var(--table-border-light)"
|
|
3559
|
+
border: "1px solid var(--rsp-table-border-light)"
|
|
3456
3560
|
};
|
|
3457
3561
|
if (isHeaderRow) {
|
|
3458
|
-
style.backgroundColor = "var(--table-header-bg)";
|
|
3459
|
-
style.color = "var(--table-header-color)";
|
|
3562
|
+
style.backgroundColor = "var(--rsp-table-header-bg)";
|
|
3563
|
+
style.color = "var(--rsp-table-header-color)";
|
|
3460
3564
|
style.fontWeight = "bold";
|
|
3461
|
-
style.borderBottom = "2px solid var(--table-header-border)";
|
|
3565
|
+
style.borderBottom = "2px solid var(--rsp-table-header-border)";
|
|
3462
3566
|
} else {
|
|
3463
3567
|
const dataRowIndex = cell.rowIndex - tableInfo.start.rowIndex - 1;
|
|
3464
3568
|
if (dataRowIndex % 2 === 0) {
|
|
3465
|
-
style.backgroundColor = "var(--table-even-row-bg)";
|
|
3569
|
+
style.backgroundColor = "var(--rsp-table-even-row-bg)";
|
|
3466
3570
|
} else {
|
|
3467
|
-
style.backgroundColor = "var(--table-odd-row-bg)";
|
|
3571
|
+
style.backgroundColor = "var(--rsp-table-odd-row-bg)";
|
|
3468
3572
|
}
|
|
3469
3573
|
}
|
|
3470
3574
|
if (isFirstColumn) {
|
|
3471
|
-
style.borderLeft = "2px solid var(--table-border-color)";
|
|
3575
|
+
style.borderLeft = "2px solid var(--rsp-table-border-color)";
|
|
3472
3576
|
}
|
|
3473
3577
|
if (isLastColumn) {
|
|
3474
|
-
style.borderRight = "2px solid var(--table-border-color)";
|
|
3578
|
+
style.borderRight = "2px solid var(--rsp-table-border-color)";
|
|
3475
3579
|
}
|
|
3476
3580
|
if (isHeaderRow) {
|
|
3477
|
-
style.borderTop = "2px solid var(--table-border-color)";
|
|
3581
|
+
style.borderTop = "2px solid var(--rsp-table-border-color)";
|
|
3478
3582
|
}
|
|
3479
3583
|
if (isLastRow) {
|
|
3480
|
-
style.borderBottom = "2px solid var(--table-border-color)";
|
|
3584
|
+
style.borderBottom = "2px solid var(--rsp-table-border-color)";
|
|
3481
3585
|
}
|
|
3482
3586
|
if (conditionalStyle?.backgroundColor) {
|
|
3483
3587
|
style.backgroundColor = conditionalStyle.backgroundColor;
|
|
@@ -3967,6 +4071,7 @@ export {
|
|
|
3967
4071
|
getCellReference,
|
|
3968
4072
|
getCellSnapAnchorFromRect,
|
|
3969
4073
|
getColumnEdgePosition,
|
|
4074
|
+
getContrastingTextColor,
|
|
3970
4075
|
getNearestColumnEdgeIndex,
|
|
3971
4076
|
getNearestRowEdgeIndex,
|
|
3972
4077
|
getRectFromCellSnapAnchor,
|
|
@@ -3980,7 +4085,9 @@ export {
|
|
|
3980
4085
|
normalizeCellSnapAnchor,
|
|
3981
4086
|
onCellEditError,
|
|
3982
4087
|
parseCellReference,
|
|
4088
|
+
parseCssColor,
|
|
3983
4089
|
queueCellEditError,
|
|
4090
|
+
relativeLuminance,
|
|
3984
4091
|
resizeCellSnapAnchorToNearestEdges,
|
|
3985
4092
|
rowToLetter,
|
|
3986
4093
|
useClickAway,
|
|
@@ -3988,4 +4095,4 @@ export {
|
|
|
3988
4095
|
useResizeObserver
|
|
3989
4096
|
};
|
|
3990
4097
|
|
|
3991
|
-
//# debugId=
|
|
4098
|
+
//# debugId=EDFA14971A4FFD6964756E2164756E21
|