@xeplr/ui-table 1.0.1 → 1.0.2
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/package.json +4 -1
- package/src/CellZoom.jsx +77 -0
- package/src/XeplrTable.jsx +338 -22
- package/src/columnWidths.js +333 -0
- package/src/filters/FilterWrapper.jsx +79 -30
- package/src/index.js +14 -0
- package/src/tableStyles.js +236 -0
- package/src/useColumnWidths.js +280 -0
- package/src/useTableController.js +62 -6
- package/src/xeplr-table.css +151 -4
package/src/xeplr-table.css
CHANGED
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
/* ── Toolbar ── */
|
|
22
22
|
.xeplr-table-toolbar {
|
|
23
23
|
display: flex;
|
|
24
|
+
/* Centred so arbitrary host content in the leading slot sits on the same
|
|
25
|
+
line as the buttons instead of stretching to the row's full height. */
|
|
26
|
+
align-items: center;
|
|
24
27
|
gap: 8px;
|
|
25
28
|
padding: 8px 12px;
|
|
26
29
|
border-bottom: 1px solid var(--xeplr-border-primary, #2a2a4a);
|
|
@@ -54,17 +57,149 @@
|
|
|
54
57
|
table-layout: auto;
|
|
55
58
|
}
|
|
56
59
|
|
|
60
|
+
/* ── Content sizing (columnSizing="content") ──
|
|
61
|
+
Everything here is scoped to .xeplr-table-sized, so the default fill-the-
|
|
62
|
+
container behaviour is untouched for tables that don't opt in.
|
|
63
|
+
|
|
64
|
+
`fixed` is what makes the measured widths binding — under `auto` the
|
|
65
|
+
browser re-negotiates them against the content and the colgroup becomes a
|
|
66
|
+
suggestion. Wrapping is the trade for that: a column short of its natural
|
|
67
|
+
width has to put the overflow somewhere, and wrapped text stays readable
|
|
68
|
+
where a truncated cell just hides data. `anywhere` is the last resort for a
|
|
69
|
+
single unbreakable token wider than its whole column. */
|
|
70
|
+
.xeplr-table-sized {
|
|
71
|
+
table-layout: fixed;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.xeplr-table-sized .xeplr-table-th {
|
|
75
|
+
white-space: normal;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.xeplr-table-sized .xeplr-table-td,
|
|
79
|
+
.xeplr-table-sized .xeplr-table-header-label {
|
|
80
|
+
overflow-wrap: anywhere;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* ── Styled tables (cellStyle) ──
|
|
84
|
+
Separated borders, on purpose. Under the default `collapse`, adjacent cells
|
|
85
|
+
share one border and CSS picks the winner by width, then style — so a thin
|
|
86
|
+
border set on one cell next to a thicker neighbour never appears at all.
|
|
87
|
+
Per-side control would be dishonest: you'd set it, see nothing, and
|
|
88
|
+
reasonably call it broken.
|
|
89
|
+
|
|
90
|
+
`separate` with zero spacing renders identically to today for the default
|
|
91
|
+
borders (only bottoms are set, and horizontal neighbours don't share those),
|
|
92
|
+
but every border a user sets now actually draws. The trade is that two
|
|
93
|
+
adjacent cells each carrying a border on the SAME shared edge will show 2px
|
|
94
|
+
where collapse would have merged to 1px — style one side rather than all
|
|
95
|
+
four and it doesn't arise. */
|
|
96
|
+
.xeplr-table-styled {
|
|
97
|
+
border-collapse: separate;
|
|
98
|
+
border-spacing: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* ── Cell zoom (cellZoom) ──
|
|
102
|
+
Sized in em so it scales off whatever font the cell itself is using: a
|
|
103
|
+
compact theme's 11px cell zooms proportionally, rather than to some fixed
|
|
104
|
+
size that would be a huge jump from one table and barely a change in
|
|
105
|
+
another.
|
|
106
|
+
|
|
107
|
+
No cursor change on a zoomable cell, deliberately: a magnifier cursor
|
|
108
|
+
obscures the very text you're trying to aim at, which is backwards for a
|
|
109
|
+
reading aid. The plain arrow stays, so you can point precisely. */
|
|
110
|
+
.xeplr-table-cell-zoom {
|
|
111
|
+
position: fixed;
|
|
112
|
+
z-index: 300;
|
|
113
|
+
max-width: min(560px, 90vw);
|
|
114
|
+
max-height: 60vh;
|
|
115
|
+
overflow: auto;
|
|
116
|
+
padding: 12px 16px;
|
|
117
|
+
border-radius: 10px;
|
|
118
|
+
background: var(--xeplr-bg-secondary, #16162a);
|
|
119
|
+
border: 1px solid var(--xeplr-border-primary, #2a2a4a);
|
|
120
|
+
box-shadow: 0 12px 32px -8px rgba(0, 0, 0, .45);
|
|
121
|
+
/* Selectable on purpose — reading it is the point, and copying it out is
|
|
122
|
+
the next thing anyone wants to do. */
|
|
123
|
+
user-select: text;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.xeplr-table-cell-zoom:focus {
|
|
127
|
+
outline: none;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.xeplr-table-cell-zoom-label {
|
|
131
|
+
font-size: .75em;
|
|
132
|
+
text-transform: uppercase;
|
|
133
|
+
letter-spacing: .05em;
|
|
134
|
+
opacity: .6;
|
|
135
|
+
margin-bottom: 6px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.xeplr-table-cell-zoom-value {
|
|
139
|
+
font-size: 1.9em;
|
|
140
|
+
line-height: 1.35;
|
|
141
|
+
overflow-wrap: anywhere;
|
|
142
|
+
}
|
|
143
|
+
|
|
57
144
|
/* ── Header ── */
|
|
58
145
|
.xeplr-table-th {
|
|
59
146
|
padding: 0;
|
|
60
147
|
background: var(--xeplr-bg-secondary, #16162a);
|
|
61
148
|
border-bottom: 2px solid var(--xeplr-border-primary, #2a2a4a);
|
|
149
|
+
/* Thin by default between every header cell — a grouped table (a pivoted
|
|
150
|
+
date over several measures) reads as one solid block without SOME line
|
|
151
|
+
between its own columns, not just at the group's outer edge. */
|
|
152
|
+
border-right: 1px solid var(--xeplr-border-secondary, #2a2a4a);
|
|
62
153
|
text-align: left;
|
|
63
154
|
font-weight: 600;
|
|
64
155
|
white-space: nowrap;
|
|
65
156
|
color: var(--xeplr-text-secondary, inherit);
|
|
66
157
|
}
|
|
67
158
|
|
|
159
|
+
/* A darkened version of the SAME light-gray line already drawn everywhere
|
|
160
|
+
else in this table (--xeplr-border-secondary), not a separate color —
|
|
161
|
+
the group boundary is meant to read as "more of this table's own grid,"
|
|
162
|
+
not as a different, unrelated UI element sitting on top of it. */
|
|
163
|
+
.xeplr-table-th-group,
|
|
164
|
+
.xeplr-table-th-group-start,
|
|
165
|
+
.xeplr-table-th-group-end,
|
|
166
|
+
.xeplr-table-td-group-start,
|
|
167
|
+
.xeplr-table-td-group-end {
|
|
168
|
+
--xeplr-table-group-border: #f1eaea;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* The spanning cell itself (the date, not the measures under it) — centered
|
|
172
|
+
over what it covers, the way a merged cell reads in Excel. Top border
|
|
173
|
+
closes the frame's roof. */
|
|
174
|
+
.xeplr-table-th-group .xeplr-table-header-cell {
|
|
175
|
+
justify-content: center;
|
|
176
|
+
}
|
|
177
|
+
.xeplr-table-th-group {
|
|
178
|
+
text-align: center;
|
|
179
|
+
border-top: 2px solid var(--xeplr-table-group-border);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Every header cell in a row that ISN'T the last one gets the divider under
|
|
183
|
+
it — a real group (the date) AND a plain column beside it (Category Name)
|
|
184
|
+
alike — so the line drawn under "2025-05-01" runs the full width of the
|
|
185
|
+
header instead of stopping wherever a non-grouped column happens to sit. */
|
|
186
|
+
.xeplr-table-th-row-divider {
|
|
187
|
+
border-bottom: 1px solid var(--xeplr-border-secondary, #ccc);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* The frame's sides — one continuous line from the group's own header cell,
|
|
191
|
+
down through the measure-label row, down through every data row, so the
|
|
192
|
+
whole block reads as one unit instead of columns that happen to sit next
|
|
193
|
+
to each other. */
|
|
194
|
+
.xeplr-table-th-group-start,
|
|
195
|
+
.xeplr-table-td-group-start {
|
|
196
|
+
border-left: 2px solid var(--xeplr-table-group-border);
|
|
197
|
+
}
|
|
198
|
+
.xeplr-table-th-group-end,
|
|
199
|
+
.xeplr-table-td-group-end {
|
|
200
|
+
border-right: 2px solid var(--xeplr-table-group-border);
|
|
201
|
+
}
|
|
202
|
+
|
|
68
203
|
.xeplr-table-header-cell {
|
|
69
204
|
display: flex;
|
|
70
205
|
align-items: center;
|
|
@@ -137,13 +272,16 @@
|
|
|
137
272
|
}
|
|
138
273
|
|
|
139
274
|
/* ── Filter panel ── */
|
|
275
|
+
/* PORTALLED — see FilterWrapper. `top`/`left` are set inline from the
|
|
276
|
+
trigger's rect; everything here is appearance only. It sits on document.body
|
|
277
|
+
so no table's `overflow: auto` can clip it. */
|
|
140
278
|
.xeplr-table-filter-panel {
|
|
141
|
-
position:
|
|
142
|
-
|
|
143
|
-
right: 0;
|
|
144
|
-
z-index: 100;
|
|
279
|
+
position: fixed;
|
|
280
|
+
z-index: 3000;
|
|
145
281
|
min-width: 220px;
|
|
146
282
|
max-width: 300px;
|
|
283
|
+
max-height: 60vh;
|
|
284
|
+
overflow: auto;
|
|
147
285
|
background: var(--xeplr-bg-tertiary, #1e1e38);
|
|
148
286
|
border: 1px solid var(--xeplr-border-primary, #3a3a5a);
|
|
149
287
|
border-radius: 6px;
|
|
@@ -910,3 +1048,12 @@
|
|
|
910
1048
|
|
|
911
1049
|
.xeplr-r-avatar-img { object-fit: cover; }
|
|
912
1050
|
.xeplr-r-chip-avatar-img { object-fit: cover; }
|
|
1051
|
+
|
|
1052
|
+
/* ── Host-marked columns (columnClassName) ──
|
|
1053
|
+
Nothing here styles a specific mark — the class is the host's and so is its
|
|
1054
|
+
meaning. This only makes the header label clickable when the host has taken
|
|
1055
|
+
the click, so the cursor says so before anybody guesses. */
|
|
1056
|
+
.xeplr-table-header-label.clickable {
|
|
1057
|
+
cursor: pointer;
|
|
1058
|
+
user-select: none;
|
|
1059
|
+
}
|