@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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/react-spreadsheets",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "commonjs"
5
5
  }
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 = (element, colorScheme) => {
1251
- const fallback = colorScheme === "dark" ? "#4b5563" : "#e1e5e9";
1252
- if (!element || typeof getComputedStyle !== "function") {
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 declared = getComputedStyle(element).getPropertyValue("--rsp-gridline").trim();
1256
- if (!declared || declared.includes("light-dark(")) {
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 declared;
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(canvasRef.current, colorScheme);
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=FCE294496834A26064756E2164756E21
4098
+ //# debugId=EDFA14971A4FFD6964756E2164756E21