@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/mjs/package.json
CHANGED
package/dist/styles.css
CHANGED
|
@@ -4,45 +4,78 @@
|
|
|
4
4
|
* Import once in your app:
|
|
5
5
|
* import "@ricsam/react-spreadsheets/styles.css";
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* ---------------------------------------------------------------------------
|
|
8
|
+
* Theming
|
|
9
|
+
* ---------------------------------------------------------------------------
|
|
10
|
+
* Every visual is driven by `--rsp-*` custom properties. Because the tokens are
|
|
11
|
+
* declared on `:root` (not on `.rsp-root`), you can override them from *any*
|
|
12
|
+
* ancestor and the grid will pick them up:
|
|
9
13
|
*
|
|
10
|
-
* .
|
|
14
|
+
* .my-panel { --rsp-accent: #7c3aed; --rsp-cell-font-size: 13px; }
|
|
11
15
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
16
|
+
* ---------------------------------------------------------------------------
|
|
17
|
+
* Light / dark
|
|
18
|
+
* ---------------------------------------------------------------------------
|
|
19
|
+
* Colors resolve through `light-dark()`, which follows the inherited
|
|
20
|
+
* `color-scheme`. The grid deliberately does NOT declare `color-scheme` on
|
|
21
|
+
* `.rsp-root`, because doing so would override a `color-scheme` pin set by an
|
|
22
|
+
* ancestor and de-sync the grid from the surrounding page.
|
|
23
|
+
*
|
|
24
|
+
* To pin a subtree, set `color-scheme` on any ancestor (or on `.rsp-root`):
|
|
25
|
+
*
|
|
26
|
+
* .workbook-stage { color-scheme: light; } // always light
|
|
27
|
+
* .workbook-stage { color-scheme: dark; } // always dark
|
|
28
|
+
*
|
|
29
|
+
* Or use the helper classes shipped below:
|
|
30
|
+
*
|
|
31
|
+
* <FormulaWorkbook className="rsp-theme-light" />
|
|
32
|
+
* <FormulaWorkbook className="rsp-theme-dark" />
|
|
14
33
|
*/
|
|
15
34
|
|
|
16
|
-
|
|
17
|
-
color-scheme: light dark;
|
|
18
|
-
|
|
35
|
+
:root {
|
|
19
36
|
/* Surfaces */
|
|
20
|
-
--rsp-bg: light-dark(#ffffff, #
|
|
21
|
-
--rsp-
|
|
22
|
-
--rsp-
|
|
23
|
-
--rsp-
|
|
37
|
+
--rsp-bg: light-dark(#ffffff, #0f1523);
|
|
38
|
+
--rsp-surface: light-dark(#ffffff, #151c2c);
|
|
39
|
+
--rsp-header-bg: light-dark(#f7f8fa, #1a2233);
|
|
40
|
+
--rsp-header-active-bg: light-dark(#e9edf5, #24304a);
|
|
41
|
+
--rsp-corner-bg: light-dark(#eef1f6, #1a2233);
|
|
42
|
+
--rsp-editor-bg: light-dark(#ffffff, #1a2233);
|
|
24
43
|
|
|
25
44
|
/* Lines */
|
|
26
|
-
--rsp-border: light-dark(#
|
|
27
|
-
--rsp-corner-border: light-dark(#
|
|
28
|
-
--rsp-gridline: light-dark(#
|
|
45
|
+
--rsp-border: light-dark(#e3e7ee, #2a3346);
|
|
46
|
+
--rsp-corner-border: light-dark(#d7dce6, #2a3346);
|
|
47
|
+
--rsp-gridline: light-dark(#e8ebf1, #232c3d);
|
|
29
48
|
|
|
30
49
|
/* Text */
|
|
31
|
-
--rsp-text: light-dark(#
|
|
32
|
-
--rsp-header-text: light-dark(#
|
|
33
|
-
--rsp-muted-text: light-dark(#6b7280, #
|
|
34
|
-
|
|
35
|
-
/* Accent / selection
|
|
36
|
-
|
|
50
|
+
--rsp-text: light-dark(#101828, #e8ecf4);
|
|
51
|
+
--rsp-header-text: light-dark(#5a6478, #99a4bb);
|
|
52
|
+
--rsp-muted-text: light-dark(#6b7280, #8c97ad);
|
|
53
|
+
|
|
54
|
+
/* Accent / selection.
|
|
55
|
+
NOTE: `@ricsam/selection-manager` paints the selection *perimeter* as an
|
|
56
|
+
inline box-shadow using a hardcoded `#2196F3`, which CSS cannot recolor.
|
|
57
|
+
The default accent stays in that blue family so the perimeter agrees with
|
|
58
|
+
the rest of the chrome out of the box. Overriding `--rsp-accent` with a
|
|
59
|
+
distant hue will make the perimeter read slightly differently. */
|
|
60
|
+
--rsp-accent: light-dark(#2196f3, #58a6ff);
|
|
37
61
|
--rsp-accent-contrast: #ffffff;
|
|
38
|
-
--rsp-selection-bg: light-dark(#
|
|
39
|
-
--rsp-selection-range-bg: light-dark(#
|
|
40
|
-
--rsp-hover-bg: light-dark(#
|
|
41
|
-
--rsp-focus-ring: light-dark(rgba(33, 150, 243, 0.
|
|
62
|
+
--rsp-selection-bg: light-dark(#e8f2fe, #17304f);
|
|
63
|
+
--rsp-selection-range-bg: light-dark(#f1f7fe, #14263d);
|
|
64
|
+
--rsp-hover-bg: light-dark(#f5f7fa, #1c2436);
|
|
65
|
+
--rsp-focus-ring: light-dark(rgba(33, 150, 243, 0.22), rgba(88, 166, 255, 0.28));
|
|
42
66
|
|
|
43
67
|
/* Danger (delete buttons, invalid input) */
|
|
44
|
-
--rsp-danger: light-dark(#
|
|
45
|
-
--rsp-danger-bg: light-dark(#
|
|
68
|
+
--rsp-danger: light-dark(#d92d20, #ff8a80);
|
|
69
|
+
--rsp-danger-bg: light-dark(#fef3f2, #3a1512);
|
|
70
|
+
|
|
71
|
+
/* Tables (consumed by the workbook's inline cell styles) */
|
|
72
|
+
--rsp-table-header-bg: light-dark(#2196f3, #1c3a5e);
|
|
73
|
+
--rsp-table-header-color: light-dark(#ffffff, #e8ecf4);
|
|
74
|
+
--rsp-table-header-border: light-dark(#1877c9, #2a5384);
|
|
75
|
+
--rsp-table-even-row-bg: light-dark(#f7f9fc, #161e2e);
|
|
76
|
+
--rsp-table-odd-row-bg: light-dark(#ffffff, #131a28);
|
|
77
|
+
--rsp-table-border-color: light-dark(#2196f3, #34405c);
|
|
78
|
+
--rsp-table-border-light: light-dark(#dfe4ec, #2a3346);
|
|
46
79
|
|
|
47
80
|
/* Typography */
|
|
48
81
|
--rsp-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
@@ -50,15 +83,41 @@
|
|
|
50
83
|
--rsp-mono-font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo,
|
|
51
84
|
Consolas, "Liberation Mono", monospace;
|
|
52
85
|
--rsp-cell-font-size: 12px;
|
|
53
|
-
--rsp-header-font-size:
|
|
86
|
+
--rsp-header-font-size: 11px;
|
|
54
87
|
|
|
55
|
-
/* Shape */
|
|
56
|
-
--rsp-radius:
|
|
88
|
+
/* Shape + motion */
|
|
89
|
+
--rsp-radius: 8px;
|
|
90
|
+
--rsp-radius-sm: 5px;
|
|
91
|
+
--rsp-cell-padding: 0 7px;
|
|
92
|
+
--rsp-transition: 120ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
57
93
|
|
|
58
94
|
/* Fill handle */
|
|
59
95
|
--rsp-fill-handle-size: 8px;
|
|
60
96
|
}
|
|
61
97
|
|
|
98
|
+
/* Opt-in scheme pins. Applied to `.rsp-root` (or any ancestor) these force one
|
|
99
|
+
mode regardless of the OS preference, and every `light-dark()` token below
|
|
100
|
+
follows because `color-scheme` inherits. */
|
|
101
|
+
.rsp-theme-light {
|
|
102
|
+
color-scheme: light;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.rsp-theme-dark {
|
|
106
|
+
color-scheme: dark;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.rsp-root {
|
|
110
|
+
/* No `color-scheme` here on purpose — see the file header. */
|
|
111
|
+
color: var(--rsp-text);
|
|
112
|
+
font-family: var(--rsp-font-family);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.rsp-root *,
|
|
116
|
+
.rsp-root *::before,
|
|
117
|
+
.rsp-root *::after {
|
|
118
|
+
box-sizing: border-box;
|
|
119
|
+
}
|
|
120
|
+
|
|
62
121
|
/* ------------------------------------------------------------------ *
|
|
63
122
|
* Spreadsheet grid
|
|
64
123
|
* ------------------------------------------------------------------ */
|
|
@@ -77,7 +136,7 @@
|
|
|
77
136
|
}
|
|
78
137
|
|
|
79
138
|
.rsp-container.rsp-focused {
|
|
80
|
-
box-shadow: 0 0 0
|
|
139
|
+
box-shadow: inset 0 0 0 1px var(--rsp-accent);
|
|
81
140
|
}
|
|
82
141
|
|
|
83
142
|
.rsp-canvas,
|
|
@@ -92,9 +151,10 @@
|
|
|
92
151
|
position: absolute;
|
|
93
152
|
border: 1px solid transparent;
|
|
94
153
|
background: transparent;
|
|
95
|
-
padding:
|
|
154
|
+
padding: var(--rsp-cell-padding);
|
|
96
155
|
font-size: var(--rsp-cell-font-size);
|
|
97
156
|
font-family: var(--rsp-font-family);
|
|
157
|
+
font-variant-numeric: tabular-nums;
|
|
98
158
|
overflow: hidden;
|
|
99
159
|
white-space: pre;
|
|
100
160
|
text-overflow: ellipsis;
|
|
@@ -108,30 +168,47 @@
|
|
|
108
168
|
|
|
109
169
|
.rsp-cell.rsp-cell-multiline {
|
|
110
170
|
align-items: flex-start;
|
|
171
|
+
padding-top: 4px;
|
|
111
172
|
}
|
|
112
173
|
|
|
113
|
-
|
|
174
|
+
/* Hover tint must never repaint a cell the consumer has colored, so it is
|
|
175
|
+
restricted to "plain" cells (no custom background). */
|
|
176
|
+
.rsp-cell.rsp-cell-plain:hover {
|
|
114
177
|
background: var(--rsp-hover-bg);
|
|
115
178
|
}
|
|
116
179
|
|
|
117
|
-
.rsp-cell.rsp-cell-selected {
|
|
118
|
-
border-color: var(--rsp-accent);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
180
|
/* `rsp-cell-plain` marks cells whose background is not overridden by a
|
|
122
181
|
consumer-supplied custom style, so selection tinting is safe to apply. */
|
|
182
|
+
.rsp-cell.rsp-cell-in-selection.rsp-cell-plain {
|
|
183
|
+
background: var(--rsp-selection-range-bg);
|
|
184
|
+
}
|
|
185
|
+
|
|
123
186
|
.rsp-cell.rsp-cell-selected.rsp-cell-plain {
|
|
124
187
|
background: var(--rsp-selection-bg);
|
|
125
188
|
}
|
|
126
189
|
|
|
127
|
-
|
|
128
|
-
|
|
190
|
+
/* The selection perimeter is painted by the selection manager as an inline
|
|
191
|
+
`box-shadow` on the individual edge cells, so this rule must NOT declare a
|
|
192
|
+
box-shadow of its own: `rsp-cell-selected` is present on every cell of a
|
|
193
|
+
multi-cell range, and a full outline here would box each interior cell.
|
|
194
|
+
Only the stacking order is raised so the perimeter is not clipped by
|
|
195
|
+
neighbouring cells. */
|
|
196
|
+
.rsp-cell.rsp-cell-selected {
|
|
197
|
+
z-index: 2;
|
|
129
198
|
}
|
|
130
199
|
|
|
131
|
-
|
|
200
|
+
/* The editor surface must win over the selection tint above (equal specificity
|
|
201
|
+
would otherwise leave the selected-cell background showing through), and over
|
|
202
|
+
a consumer background so the text being typed stays legible. */
|
|
203
|
+
.rsp-cell.rsp-cell-editing,
|
|
204
|
+
.rsp-cell.rsp-cell-editing.rsp-cell-plain,
|
|
205
|
+
.rsp-cell.rsp-cell-selected.rsp-cell-editing,
|
|
206
|
+
.rsp-cell.rsp-cell-selected.rsp-cell-editing.rsp-cell-plain {
|
|
132
207
|
background: var(--rsp-editor-bg);
|
|
133
|
-
|
|
134
|
-
box-shadow:
|
|
208
|
+
color: var(--rsp-text);
|
|
209
|
+
box-shadow:
|
|
210
|
+
inset 0 0 0 2px var(--rsp-accent),
|
|
211
|
+
0 6px 16px -4px var(--rsp-focus-ring);
|
|
135
212
|
z-index: 999;
|
|
136
213
|
pointer-events: none;
|
|
137
214
|
}
|
|
@@ -148,6 +225,7 @@
|
|
|
148
225
|
font-family: var(--rsp-font-family);
|
|
149
226
|
background: transparent;
|
|
150
227
|
color: var(--rsp-text);
|
|
228
|
+
caret-color: var(--rsp-accent);
|
|
151
229
|
resize: none;
|
|
152
230
|
overflow: hidden;
|
|
153
231
|
z-index: 1000;
|
|
@@ -157,12 +235,15 @@
|
|
|
157
235
|
|
|
158
236
|
.rsp-fill-handle {
|
|
159
237
|
position: absolute;
|
|
160
|
-
bottom:
|
|
161
|
-
right:
|
|
238
|
+
bottom: -1px;
|
|
239
|
+
right: -1px;
|
|
162
240
|
width: var(--rsp-fill-handle-size);
|
|
163
241
|
height: var(--rsp-fill-handle-size);
|
|
164
242
|
background-color: var(--rsp-accent);
|
|
243
|
+
border: 1px solid var(--rsp-bg);
|
|
244
|
+
border-radius: 1px;
|
|
165
245
|
cursor: crosshair;
|
|
246
|
+
z-index: 3;
|
|
166
247
|
}
|
|
167
248
|
|
|
168
249
|
/* Headers ---------------------------------------------------------- */
|
|
@@ -175,14 +256,34 @@
|
|
|
175
256
|
align-items: center;
|
|
176
257
|
justify-content: center;
|
|
177
258
|
font-size: var(--rsp-header-font-size);
|
|
259
|
+
font-weight: 500;
|
|
260
|
+
letter-spacing: 0.02em;
|
|
178
261
|
cursor: pointer;
|
|
179
262
|
user-select: none;
|
|
180
263
|
color: var(--rsp-header-text);
|
|
181
264
|
box-sizing: border-box;
|
|
265
|
+
transition: background-color var(--rsp-transition), color var(--rsp-transition);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.rsp-header:hover {
|
|
269
|
+
background-color: var(--rsp-header-active-bg);
|
|
270
|
+
color: var(--rsp-text);
|
|
182
271
|
}
|
|
183
272
|
|
|
184
273
|
.rsp-header.rsp-header-selected {
|
|
185
|
-
background-color: var(--rsp-
|
|
274
|
+
background-color: var(--rsp-header-active-bg);
|
|
275
|
+
color: var(--rsp-accent);
|
|
276
|
+
font-weight: 600;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* A crisp accent edge on the side that faces the grid marks the active
|
|
280
|
+
row/column without changing the header's box metrics. */
|
|
281
|
+
.rsp-header.rsp-header-col.rsp-header-selected {
|
|
282
|
+
box-shadow: inset 0 -2px 0 var(--rsp-accent);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.rsp-header.rsp-header-row.rsp-header-selected {
|
|
286
|
+
box-shadow: inset -2px 0 0 var(--rsp-accent);
|
|
186
287
|
}
|
|
187
288
|
|
|
188
289
|
.rsp-column-headers,
|
|
@@ -231,6 +332,11 @@
|
|
|
231
332
|
z-index: 10;
|
|
232
333
|
}
|
|
233
334
|
|
|
335
|
+
.rsp-col-resize-handle:hover,
|
|
336
|
+
.rsp-row-resize-handle:hover {
|
|
337
|
+
background: var(--rsp-accent);
|
|
338
|
+
}
|
|
339
|
+
|
|
234
340
|
/* Overlays --------------------------------------------------------- */
|
|
235
341
|
|
|
236
342
|
.rsp-overlays {
|
|
@@ -249,7 +355,7 @@
|
|
|
249
355
|
opacity: 0.5;
|
|
250
356
|
pointer-events: none;
|
|
251
357
|
border: 2px dashed var(--rsp-accent);
|
|
252
|
-
border-radius:
|
|
358
|
+
border-radius: var(--rsp-radius-sm);
|
|
253
359
|
background-color: var(--rsp-focus-ring);
|
|
254
360
|
}
|
|
255
361
|
|
|
@@ -283,7 +389,7 @@
|
|
|
283
389
|
display: flex;
|
|
284
390
|
align-items: center;
|
|
285
391
|
gap: 8px;
|
|
286
|
-
padding:
|
|
392
|
+
padding: 7px 10px;
|
|
287
393
|
border-bottom: 1px solid var(--rsp-border);
|
|
288
394
|
background: var(--rsp-header-bg);
|
|
289
395
|
flex: none;
|
|
@@ -291,8 +397,9 @@
|
|
|
291
397
|
|
|
292
398
|
.rsp-workbook-name {
|
|
293
399
|
font-weight: 600;
|
|
294
|
-
font-size:
|
|
295
|
-
|
|
400
|
+
font-size: 12px;
|
|
401
|
+
letter-spacing: -0.01em;
|
|
402
|
+
color: var(--rsp-text);
|
|
296
403
|
white-space: nowrap;
|
|
297
404
|
}
|
|
298
405
|
|
|
@@ -305,8 +412,8 @@
|
|
|
305
412
|
.rsp-sheet-tabs {
|
|
306
413
|
display: flex;
|
|
307
414
|
align-items: center;
|
|
308
|
-
gap:
|
|
309
|
-
padding:
|
|
415
|
+
gap: 6px;
|
|
416
|
+
padding: 6px 10px;
|
|
310
417
|
border-top: 1px solid var(--rsp-border);
|
|
311
418
|
background: var(--rsp-header-bg);
|
|
312
419
|
flex: none;
|
|
@@ -324,27 +431,38 @@
|
|
|
324
431
|
display: inline-flex;
|
|
325
432
|
align-items: center;
|
|
326
433
|
gap: 6px;
|
|
327
|
-
padding:
|
|
434
|
+
padding: 5px 11px;
|
|
328
435
|
border: 1px solid transparent;
|
|
329
|
-
border-radius: var(--rsp-radius);
|
|
436
|
+
border-radius: var(--rsp-radius-sm);
|
|
330
437
|
font-size: 12px;
|
|
331
438
|
line-height: 1.4;
|
|
332
439
|
cursor: pointer;
|
|
333
440
|
white-space: nowrap;
|
|
334
441
|
color: var(--rsp-header-text);
|
|
335
442
|
background: transparent;
|
|
443
|
+
transition: background-color var(--rsp-transition), color var(--rsp-transition);
|
|
336
444
|
}
|
|
337
445
|
|
|
338
446
|
.rsp-sheet-tab:hover {
|
|
339
447
|
background: var(--rsp-hover-bg);
|
|
448
|
+
color: var(--rsp-text);
|
|
340
449
|
}
|
|
341
450
|
|
|
342
451
|
.rsp-sheet-tab.rsp-sheet-tab-active {
|
|
343
|
-
background: var(--rsp-
|
|
344
|
-
border-color:
|
|
345
|
-
color: var(--rsp-
|
|
452
|
+
background: var(--rsp-accent);
|
|
453
|
+
border-color: transparent;
|
|
454
|
+
color: var(--rsp-accent-contrast);
|
|
346
455
|
font-weight: 600;
|
|
347
|
-
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/* Icon buttons inside the active tab must read against the accent fill. */
|
|
459
|
+
.rsp-sheet-tab.rsp-sheet-tab-active .rsp-icon-button {
|
|
460
|
+
color: var(--rsp-accent-contrast);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.rsp-sheet-tab.rsp-sheet-tab-active .rsp-icon-button:hover {
|
|
464
|
+
background: rgba(255, 255, 255, 0.22);
|
|
465
|
+
color: var(--rsp-accent-contrast);
|
|
348
466
|
}
|
|
349
467
|
|
|
350
468
|
/* Per-tab action buttons reveal on hover / when the tab is active. */
|
|
@@ -353,7 +471,7 @@
|
|
|
353
471
|
align-items: center;
|
|
354
472
|
gap: 2px;
|
|
355
473
|
opacity: 0;
|
|
356
|
-
transition: opacity
|
|
474
|
+
transition: opacity var(--rsp-transition);
|
|
357
475
|
}
|
|
358
476
|
|
|
359
477
|
.rsp-sheet-tab:hover .sheet-tab-actions,
|
|
@@ -364,12 +482,14 @@
|
|
|
364
482
|
|
|
365
483
|
.rsp-sheet-tab-input {
|
|
366
484
|
font: inherit;
|
|
367
|
-
color:
|
|
485
|
+
color: var(--rsp-text);
|
|
368
486
|
background: var(--rsp-editor-bg);
|
|
369
487
|
border: 1px solid var(--rsp-accent);
|
|
370
|
-
border-radius:
|
|
371
|
-
padding:
|
|
488
|
+
border-radius: var(--rsp-radius-sm);
|
|
489
|
+
padding: 2px 6px;
|
|
372
490
|
min-width: 80px;
|
|
491
|
+
outline: none;
|
|
492
|
+
box-shadow: 0 0 0 3px var(--rsp-focus-ring);
|
|
373
493
|
}
|
|
374
494
|
|
|
375
495
|
.rsp-icon-button {
|
|
@@ -380,12 +500,13 @@
|
|
|
380
500
|
height: 22px;
|
|
381
501
|
padding: 0;
|
|
382
502
|
border: none;
|
|
383
|
-
border-radius:
|
|
503
|
+
border-radius: var(--rsp-radius-sm);
|
|
384
504
|
background: transparent;
|
|
385
505
|
color: var(--rsp-muted-text);
|
|
386
506
|
cursor: pointer;
|
|
387
507
|
font-size: 14px;
|
|
388
508
|
line-height: 1;
|
|
509
|
+
transition: background-color var(--rsp-transition), color var(--rsp-transition);
|
|
389
510
|
}
|
|
390
511
|
|
|
391
512
|
.rsp-icon-button:hover {
|
|
@@ -393,6 +514,11 @@
|
|
|
393
514
|
color: var(--rsp-text);
|
|
394
515
|
}
|
|
395
516
|
|
|
517
|
+
.rsp-icon-button:disabled {
|
|
518
|
+
opacity: 0.4;
|
|
519
|
+
cursor: not-allowed;
|
|
520
|
+
}
|
|
521
|
+
|
|
396
522
|
.rsp-icon-button.rsp-icon-button-delete:hover {
|
|
397
523
|
background: var(--rsp-danger-bg);
|
|
398
524
|
color: var(--rsp-danger);
|
|
@@ -403,19 +529,21 @@
|
|
|
403
529
|
align-items: center;
|
|
404
530
|
justify-content: center;
|
|
405
531
|
gap: 4px;
|
|
406
|
-
height:
|
|
407
|
-
padding: 0
|
|
532
|
+
height: 26px;
|
|
533
|
+
padding: 0 11px;
|
|
408
534
|
border: 1px dashed var(--rsp-border);
|
|
409
|
-
border-radius: var(--rsp-radius);
|
|
535
|
+
border-radius: var(--rsp-radius-sm);
|
|
410
536
|
background: transparent;
|
|
411
537
|
color: var(--rsp-header-text);
|
|
412
538
|
font-size: 12px;
|
|
413
539
|
cursor: pointer;
|
|
414
540
|
white-space: nowrap;
|
|
541
|
+
transition: border-color var(--rsp-transition), color var(--rsp-transition);
|
|
415
542
|
}
|
|
416
543
|
|
|
417
544
|
.rsp-add-sheet-button:hover {
|
|
418
545
|
border-color: var(--rsp-accent);
|
|
546
|
+
border-style: solid;
|
|
419
547
|
color: var(--rsp-accent);
|
|
420
548
|
}
|
|
421
549
|
|
|
@@ -430,7 +558,7 @@
|
|
|
430
558
|
.rsp-zoom-value {
|
|
431
559
|
min-width: 44px;
|
|
432
560
|
text-align: center;
|
|
433
|
-
font-size:
|
|
561
|
+
font-size: 11px;
|
|
434
562
|
color: var(--rsp-muted-text);
|
|
435
563
|
font-variant-numeric: tabular-nums;
|
|
436
564
|
}
|
|
@@ -441,7 +569,7 @@
|
|
|
441
569
|
display: flex;
|
|
442
570
|
align-items: center;
|
|
443
571
|
gap: 8px;
|
|
444
|
-
padding:
|
|
572
|
+
padding: 6px 10px;
|
|
445
573
|
border-bottom: 1px solid var(--rsp-border);
|
|
446
574
|
background: var(--rsp-bg);
|
|
447
575
|
flex: none;
|
|
@@ -449,12 +577,12 @@
|
|
|
449
577
|
|
|
450
578
|
.rsp-name-box {
|
|
451
579
|
min-width: 84px;
|
|
452
|
-
padding:
|
|
580
|
+
padding: 4px 8px;
|
|
453
581
|
border: 1px solid var(--rsp-border);
|
|
454
|
-
border-radius:
|
|
582
|
+
border-radius: var(--rsp-radius-sm);
|
|
455
583
|
background: var(--rsp-header-bg);
|
|
456
584
|
font-family: var(--rsp-mono-font-family);
|
|
457
|
-
font-size:
|
|
585
|
+
font-size: 11px;
|
|
458
586
|
text-align: center;
|
|
459
587
|
color: var(--rsp-text);
|
|
460
588
|
}
|
|
@@ -462,22 +590,52 @@
|
|
|
462
590
|
.rsp-formula-input {
|
|
463
591
|
flex: 1;
|
|
464
592
|
min-width: 0;
|
|
465
|
-
padding:
|
|
593
|
+
padding: 4px 9px;
|
|
466
594
|
border: 1px solid var(--rsp-border);
|
|
467
|
-
border-radius:
|
|
595
|
+
border-radius: var(--rsp-radius-sm);
|
|
468
596
|
background: var(--rsp-editor-bg);
|
|
469
597
|
color: var(--rsp-text);
|
|
470
598
|
font-family: var(--rsp-mono-font-family);
|
|
471
599
|
font-size: 12px;
|
|
600
|
+
transition: border-color var(--rsp-transition), box-shadow var(--rsp-transition);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
.rsp-formula-input::placeholder {
|
|
604
|
+
color: var(--rsp-muted-text);
|
|
472
605
|
}
|
|
473
606
|
|
|
474
607
|
.rsp-formula-input:focus {
|
|
475
608
|
outline: none;
|
|
476
609
|
border-color: var(--rsp-accent);
|
|
477
|
-
box-shadow: 0 0 0
|
|
610
|
+
box-shadow: 0 0 0 3px var(--rsp-focus-ring);
|
|
478
611
|
}
|
|
479
612
|
|
|
480
613
|
.rsp-formula-input:disabled {
|
|
481
614
|
opacity: 0.6;
|
|
482
615
|
cursor: not-allowed;
|
|
483
616
|
}
|
|
617
|
+
|
|
618
|
+
/* Scrollbars ------------------------------------------------------- */
|
|
619
|
+
|
|
620
|
+
.rsp-root {
|
|
621
|
+
scrollbar-color: var(--rsp-border) transparent;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.rsp-root ::-webkit-scrollbar {
|
|
625
|
+
width: 10px;
|
|
626
|
+
height: 10px;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.rsp-root ::-webkit-scrollbar-track {
|
|
630
|
+
background: transparent;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.rsp-root ::-webkit-scrollbar-thumb {
|
|
634
|
+
background: var(--rsp-border);
|
|
635
|
+
border: 2px solid var(--rsp-bg);
|
|
636
|
+
border-radius: 99px;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.rsp-root ::-webkit-scrollbar-thumb:hover {
|
|
640
|
+
background: var(--rsp-muted-text);
|
|
641
|
+
}
|
package/dist/types/lib.d.ts
CHANGED
|
@@ -23,4 +23,5 @@ export { cn } from "./utils/cn";
|
|
|
23
23
|
export { useResizeObserver } from "./utils/use-resize-observer";
|
|
24
24
|
export { useColorScheme, type ColorScheme } from "./utils/use-color-scheme";
|
|
25
25
|
export { useClickAway } from "./utils/use-click-away";
|
|
26
|
+
export { getContrastingTextColor, parseCssColor, relativeLuminance, } from "./utils/contrast-text";
|
|
26
27
|
export { ViewportStream, type ViewportState, type ResizeHandle } from "./grid/types";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contrast helpers for consumer-supplied cell backgrounds.
|
|
3
|
+
*
|
|
4
|
+
* The grid's default text color is theme-aware (`--rsp-text` resolves through
|
|
5
|
+
* `light-dark()`), but a consumer-supplied `backgroundColor` usually is not —
|
|
6
|
+
* spreadsheet fills typically come from a document model that stores one
|
|
7
|
+
* literal color, e.g. `#f1f5f9`.
|
|
8
|
+
*
|
|
9
|
+
* Without help, a light literal fill combined with the dark theme's near-white
|
|
10
|
+
* text renders as white-on-white and the cell becomes unreadable. These helpers
|
|
11
|
+
* pick a readable ink for a known background instead.
|
|
12
|
+
*
|
|
13
|
+
* Only values we can actually parse are considered. Anything dynamic
|
|
14
|
+
* (`var(...)`, `color-mix(...)`, gradients, `transparent`, unknown keywords)
|
|
15
|
+
* returns `undefined` so the caller keeps the inherited themed color.
|
|
16
|
+
*/
|
|
17
|
+
type Rgba = {
|
|
18
|
+
r: number;
|
|
19
|
+
g: number;
|
|
20
|
+
b: number;
|
|
21
|
+
a: number;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Parses hex (#rgb, #rgba, #rrggbb, #rrggbbaa), rgb()/rgba() and a small set of
|
|
25
|
+
* common keywords. Returns `undefined` for anything else.
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseCssColor(input: string): Rgba | undefined;
|
|
28
|
+
/** Relative luminance per WCAG 2.1. */
|
|
29
|
+
export declare function relativeLuminance({ r, g, b }: Pick<Rgba, "r" | "g" | "b">): number;
|
|
30
|
+
/**
|
|
31
|
+
* Returns a readable ink for `background`, or `undefined` when the background
|
|
32
|
+
* is unparseable or too translucent to classify (in which case the themed
|
|
33
|
+
* default should keep applying).
|
|
34
|
+
*/
|
|
35
|
+
export declare function getContrastingTextColor(background: string): string | undefined;
|
|
36
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ricsam/react-spreadsheets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Headless-friendly React spreadsheet and workbook components: infinite virtualized grid, zoom, resizing, clipboard, fill handles and formula-engine bindings.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/mjs/lib.mjs",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"build": "bun build-lib.ts",
|
|
21
|
+
"build": "NODE_ENV=production bun build-lib.ts",
|
|
22
22
|
"test": "bun test",
|
|
23
23
|
"typecheck": "tsc --noEmit",
|
|
24
|
-
"demo": "bun
|
|
24
|
+
"demo": "bun demo/serve.ts"
|
|
25
25
|
},
|
|
26
26
|
"keywords": [
|
|
27
27
|
"react",
|