@kanunilabs/datagrid 1.6.0 → 1.8.0
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 +9 -1
- package/dist/datagrid.umd.js +8 -8
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +301 -6
- package/dist/index.d.ts +301 -6
- package/dist/index.js +2 -2
- package/dist/styles.css +699 -80
- package/dist/themes/all.css +1588 -0
- package/dist/themes/amber.css +41 -0
- package/dist/themes/aubergine.css +49 -0
- package/dist/themes/azure.css +41 -0
- package/dist/themes/burgundy.css +49 -0
- package/dist/themes/charcoal.css +49 -0
- package/dist/themes/contrast-dark.css +49 -0
- package/dist/themes/contrast-light.css +41 -0
- package/dist/themes/coral.css +41 -0
- package/dist/themes/corporate.css +41 -0
- package/dist/themes/deep-sea.css +49 -0
- package/dist/themes/editorial.css +41 -0
- package/dist/themes/ember.css +49 -0
- package/dist/themes/emerald.css +41 -0
- package/dist/themes/forest.css +49 -0
- package/dist/themes/glacier.css +41 -0
- package/dist/themes/graphite.css +49 -0
- package/dist/themes/indigo-night.css +49 -0
- package/dist/themes/indigo.css +41 -0
- package/dist/themes/ivory.css +41 -0
- package/dist/themes/lagoon.css +41 -0
- package/dist/themes/linen.css +41 -0
- package/dist/themes/midnight.css +49 -0
- package/dist/themes/mist.css +41 -0
- package/dist/themes/monochrome.css +41 -0
- package/dist/themes/onyx.css +49 -0
- package/dist/themes/orchid.css +41 -0
- package/dist/themes/porcelain.css +41 -0
- package/dist/themes/rose.css +41 -0
- package/dist/themes/sandstone.css +41 -0
- package/dist/themes/slate-night.css +49 -0
- package/dist/themes/slate.css +41 -0
- package/dist/themes/steel.css +49 -0
- package/dist/themes/stone.css +41 -0
- package/dist/themes/taupe.css +41 -0
- package/dist/themes/teal.css +41 -0
- package/dist/themes/terminal.css +49 -0
- package/package.json +8 -6
package/dist/styles.css
CHANGED
|
@@ -47,6 +47,11 @@
|
|
|
47
47
|
--dg-primary: #0369a1; /* sky-700 */
|
|
48
48
|
--dg-primary-soft: #e0f2fe; /* sky-100 */
|
|
49
49
|
--dg-focus-ring: #0369a1; /* matches the accent */
|
|
50
|
+
/* Find without filtering (P-FIND-01): every match tinted, the current one
|
|
51
|
+
stronger and ringed. Translucent, so selection and zebra show through. */
|
|
52
|
+
--dg-find-match-bg: color-mix(in srgb, #facc15 24%, transparent);
|
|
53
|
+
--dg-find-active-bg: color-mix(in srgb, #f59e0b 45%, transparent);
|
|
54
|
+
--dg-find-active-ring: #b45309;
|
|
50
55
|
/* Cell flash (P1.7). Translucent so the row's own background — striped,
|
|
51
56
|
selected, dirty — stays visible under the pulse rather than being
|
|
52
57
|
replaced by it. */
|
|
@@ -93,7 +98,7 @@
|
|
|
93
98
|
--dg-scrollbar-track: transparent;
|
|
94
99
|
|
|
95
100
|
/* ── Elevation ──
|
|
96
|
-
A flat theme sets these to `none`;
|
|
101
|
+
A flat theme sets these to `none`; Elevated raises them. */
|
|
97
102
|
--dg-shadow-popup: 0 10px 25px -5px rgba(15, 23, 42, 0.25);
|
|
98
103
|
--dg-shadow-popup-sm: 0 8px 24px rgba(15, 23, 42, 0.16);
|
|
99
104
|
--dg-shadow-menu: 0 12px 28px rgba(15, 23, 42, 0.22);
|
|
@@ -114,14 +119,14 @@
|
|
|
114
119
|
/* ── Line work ─────────────────────────────────────────────
|
|
115
120
|
Whole SHORTHANDS rather than a colour and a width, so a theme can drop a
|
|
116
121
|
line entirely (`none`) instead of only fading it. This is most of what
|
|
117
|
-
separates the presets:
|
|
118
|
-
rules rows only,
|
|
122
|
+
separates the presets: Ledger rules every column and every row, Elevated
|
|
123
|
+
rules rows only, Minimal keeps the rows faint and skips the columns. */
|
|
119
124
|
--dg-cell-border: 1px solid var(--dg-border);
|
|
120
125
|
--dg-row-border: 1px solid var(--dg-border);
|
|
121
126
|
--dg-header-cell-border: 1px solid var(--dg-border);
|
|
122
127
|
--dg-header-border: 1px solid var(--dg-border-strong);
|
|
123
128
|
/* A band's EDGE is not a column separator, so it gets its own token rather
|
|
124
|
-
than riding on `--dg-header-cell-border`.
|
|
129
|
+
than riding on `--dg-header-cell-border`. Minimal and Elevated set that one
|
|
125
130
|
to `none` on purpose — they rule rows, not columns — and the bands went
|
|
126
131
|
with it: "Where" and "Sales" sat over their columns with nothing marking
|
|
127
132
|
where either one started or stopped. Same argument the band row's
|
|
@@ -130,7 +135,7 @@
|
|
|
130
135
|
|
|
131
136
|
Mixed from the header TEXT rather than taken from a border token, because
|
|
132
137
|
both border tokens are too faint for a 24px vertical segment: measured on
|
|
133
|
-
|
|
138
|
+
Minimal against the header background, `--dg-border` gives 1.17:1 and
|
|
134
139
|
`--dg-border-strong` 1.39:1 — lines that are technically drawn and
|
|
135
140
|
practically invisible, i.e. a fix that changes nothing the user sees. The
|
|
136
141
|
mix lands near 2:1 and follows the theme in both light and dark, since the
|
|
@@ -206,6 +211,7 @@
|
|
|
206
211
|
--dg-primary: #38bdf8;
|
|
207
212
|
--dg-primary-soft: #0c4a6e;
|
|
208
213
|
--dg-focus-ring: #7dd3fc;
|
|
214
|
+
--dg-find-active-ring: #fbbf24;
|
|
209
215
|
/* Lifted for a dark surface: crimson on near-black reads as brown. */
|
|
210
216
|
--dg-note-marker: #f87171;
|
|
211
217
|
--dg-shadow-pinned: 2px 0 4px -2px rgba(0, 0, 0, 0.55);
|
|
@@ -364,6 +370,41 @@
|
|
|
364
370
|
white-space: nowrap;
|
|
365
371
|
}
|
|
366
372
|
|
|
373
|
+
/* ── Header text wrapping (wrapHeaderText / autoHeaderHeight) ──
|
|
374
|
+
A wrapping caption breaks onto more lines instead of ending in an ellipsis.
|
|
375
|
+
Without `autoHeaderHeight` the header keeps its fixed height and the cell
|
|
376
|
+
clips what does not fit — the same box every other header has. */
|
|
377
|
+
.kanuni-datagrid-header-cell--wrap {
|
|
378
|
+
white-space: normal;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.kanuni-datagrid-header-cell--wrap .kanuni-datagrid-header-label {
|
|
382
|
+
white-space: normal;
|
|
383
|
+
overflow-wrap: break-word;
|
|
384
|
+
text-overflow: clip;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* `autoHeaderHeight`: the header row grows to its tallest cell. `min-height`
|
|
388
|
+
keeps a header with nothing to wrap exactly the height it was. The cells
|
|
389
|
+
drop `height: 100%`, which cannot resolve against an `auto` parent, and
|
|
390
|
+
stretch to the row instead — so a short caption beside a tall one still
|
|
391
|
+
fills the full height, with its border and hover reaching the bottom.
|
|
392
|
+
The rows below that are sticky under the header read the measured height
|
|
393
|
+
from `--dg-header-actual` (written by the renderer, only in this mode). */
|
|
394
|
+
.kanuni-datagrid-root[data-auto-header-height] .kanuni-datagrid-header {
|
|
395
|
+
height: auto;
|
|
396
|
+
min-height: var(--dg-header-height);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.kanuni-datagrid-root[data-auto-header-height] .kanuni-datagrid-header-cell {
|
|
400
|
+
height: auto;
|
|
401
|
+
align-self: stretch;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.kanuni-datagrid-root[data-auto-header-height] .kanuni-datagrid-header-cell--wrap {
|
|
405
|
+
padding-block: 4px;
|
|
406
|
+
}
|
|
407
|
+
|
|
367
408
|
.kanuni-datagrid-sort-indicator {
|
|
368
409
|
flex: none;
|
|
369
410
|
font-size: 10px;
|
|
@@ -487,7 +528,7 @@
|
|
|
487
528
|
out at 17.55px, so every wrapped row landed on a fractional boundary and
|
|
488
529
|
its 1px border rendered a pixel thick on some rows and two on others.
|
|
489
530
|
A token now, because a theme moves the body font under it — 18px is right
|
|
490
|
-
for 13px text and cramped for
|
|
531
|
+
for 13px text and cramped for Elevated's 14px. */
|
|
491
532
|
line-height: var(--dg-wrap-line-height);
|
|
492
533
|
}
|
|
493
534
|
|
|
@@ -1038,6 +1079,120 @@
|
|
|
1038
1079
|
border-inline-start: 3px solid var(--dg-primary);
|
|
1039
1080
|
}
|
|
1040
1081
|
|
|
1082
|
+
/* ── Card view (narrow grids, `cardView`) ─────────────────── */
|
|
1083
|
+
/* The heights here are the ones the virtualizer places the cards by
|
|
1084
|
+
(datagrid-core presentation/cardView.ts: CARD_PADDING 21 = 10 + 10 + the
|
|
1085
|
+
1px rule, CARD_TITLE_HEIGHT 22, CARD_LINE_HEIGHT 20). Change them together.
|
|
1086
|
+
The card is sticky to the scroller's start and as wide as the VIEWPORT, the
|
|
1087
|
+
in-grid edit form's pattern above: the row under it is as wide as every
|
|
1088
|
+
column, which is exactly the sideways scroll the cards are there to end. */
|
|
1089
|
+
.kanuni-datagrid-cards .kanuni-datagrid-header,
|
|
1090
|
+
.kanuni-datagrid-cards .kanuni-datagrid-band-row,
|
|
1091
|
+
.kanuni-datagrid-cards .kanuni-datagrid-filter-row {
|
|
1092
|
+
display: none;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
.kanuni-datagrid-cards .kanuni-datagrid-scroller {
|
|
1096
|
+
overflow-x: hidden;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
.kanuni-datagrid-card {
|
|
1100
|
+
position: sticky;
|
|
1101
|
+
inset-inline-start: 0;
|
|
1102
|
+
box-sizing: border-box;
|
|
1103
|
+
width: var(--dg-viewport-width, 100%);
|
|
1104
|
+
height: 100%;
|
|
1105
|
+
padding: 10px 14px;
|
|
1106
|
+
border-bottom: 1px solid var(--dg-border);
|
|
1107
|
+
overflow: hidden;
|
|
1108
|
+
color: var(--dg-text);
|
|
1109
|
+
font-size: 13px;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
.kanuni-datagrid-card-title {
|
|
1113
|
+
height: 22px;
|
|
1114
|
+
line-height: 22px;
|
|
1115
|
+
font-weight: 600;
|
|
1116
|
+
white-space: nowrap;
|
|
1117
|
+
overflow: hidden;
|
|
1118
|
+
text-overflow: ellipsis;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
.kanuni-datagrid-card-fields {
|
|
1122
|
+
margin: 0;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
.kanuni-datagrid-card-field {
|
|
1126
|
+
display: flex;
|
|
1127
|
+
gap: 12px;
|
|
1128
|
+
height: 20px;
|
|
1129
|
+
line-height: 20px;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
.kanuni-datagrid-card-field dt,
|
|
1133
|
+
.kanuni-datagrid-card-field dd {
|
|
1134
|
+
margin: 0;
|
|
1135
|
+
min-width: 0;
|
|
1136
|
+
white-space: nowrap;
|
|
1137
|
+
overflow: hidden;
|
|
1138
|
+
text-overflow: ellipsis;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
.kanuni-datagrid-card-field dt {
|
|
1142
|
+
flex: 0 0 38%;
|
|
1143
|
+
color: var(--dg-text-muted);
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
.kanuni-datagrid-card-field dd {
|
|
1147
|
+
flex: 1 1 auto;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
.kanuni-datagrid-cardbar {
|
|
1151
|
+
display: flex;
|
|
1152
|
+
align-items: center;
|
|
1153
|
+
gap: 8px;
|
|
1154
|
+
padding: 6px 10px;
|
|
1155
|
+
border-bottom: 1px solid var(--dg-border);
|
|
1156
|
+
background: var(--dg-surface-header);
|
|
1157
|
+
color: var(--dg-text);
|
|
1158
|
+
font-size: 13px;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
.kanuni-datagrid-cardbar-label {
|
|
1162
|
+
display: flex;
|
|
1163
|
+
flex: 1 1 auto;
|
|
1164
|
+
align-items: center;
|
|
1165
|
+
gap: 8px;
|
|
1166
|
+
min-width: 0;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
.kanuni-datagrid-cardbar-select,
|
|
1170
|
+
.kanuni-datagrid-cardbar-dir {
|
|
1171
|
+
min-height: 32px;
|
|
1172
|
+
border: 1px solid var(--dg-border-strong);
|
|
1173
|
+
border-radius: var(--dg-radius-control, 4px);
|
|
1174
|
+
background: var(--dg-surface);
|
|
1175
|
+
color: var(--dg-text);
|
|
1176
|
+
font: inherit;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
.kanuni-datagrid-cardbar-select {
|
|
1180
|
+
flex: 1 1 auto;
|
|
1181
|
+
min-width: 0;
|
|
1182
|
+
padding: 0 6px;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
.kanuni-datagrid-cardbar-dir {
|
|
1186
|
+
width: 32px;
|
|
1187
|
+
cursor: pointer;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
.kanuni-datagrid-cardbar-select:focus-visible,
|
|
1191
|
+
.kanuni-datagrid-cardbar-dir:focus-visible {
|
|
1192
|
+
outline: 2px solid var(--dg-focus-ring);
|
|
1193
|
+
outline-offset: 1px;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1041
1196
|
/* ── Summary bar ──────────────────────────────────────────── */
|
|
1042
1197
|
.kanuni-datagrid-summary-bar {
|
|
1043
1198
|
display: flex;
|
|
@@ -1114,6 +1269,16 @@
|
|
|
1114
1269
|
outline-offset: -2px;
|
|
1115
1270
|
}
|
|
1116
1271
|
|
|
1272
|
+
/* Find without filtering (P-FIND-01): every match tinted, the current one
|
|
1273
|
+
stronger and outlined so it reads at a glance among the others. */
|
|
1274
|
+
.kanuni-datagrid-cell--find-match {
|
|
1275
|
+
background: var(--dg-find-match-bg);
|
|
1276
|
+
}
|
|
1277
|
+
.kanuni-datagrid-cell--find-active {
|
|
1278
|
+
background: var(--dg-find-active-bg);
|
|
1279
|
+
box-shadow: inset 0 0 0 2px var(--dg-find-active-ring);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1117
1282
|
.kanuni-datagrid-scroller:focus {
|
|
1118
1283
|
outline: none;
|
|
1119
1284
|
}
|
|
@@ -1411,7 +1576,9 @@
|
|
|
1411
1576
|
variable here so density keeps working. Sticking at the header height alone
|
|
1412
1577
|
parked this row inside the header on any banded grid, and the two drew over
|
|
1413
1578
|
each other as soon as the user scrolled. */
|
|
1414
|
-
|
|
1579
|
+
/* `--dg-header-actual` is the header's measured height under
|
|
1580
|
+
`autoHeaderHeight`; unset otherwise, when the header is the token height. */
|
|
1581
|
+
top: calc(var(--dg-band-offset, 0px) + var(--dg-header-actual, var(--dg-header-height)));
|
|
1415
1582
|
z-index: 3;
|
|
1416
1583
|
display: flex;
|
|
1417
1584
|
height: var(--dg-header-height);
|
|
@@ -1454,6 +1621,41 @@
|
|
|
1454
1621
|
border-color: var(--dg-primary);
|
|
1455
1622
|
}
|
|
1456
1623
|
|
|
1624
|
+
.kanuni-datagrid-filter-input:disabled {
|
|
1625
|
+
opacity: 0.5;
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
/* A column with `filterOperators`: the operator menu before the box. Capped
|
|
1629
|
+
so a long label cannot squeeze the box out of a narrow column. */
|
|
1630
|
+
.kanuni-datagrid-filter-operator {
|
|
1631
|
+
flex: 0 1 auto;
|
|
1632
|
+
max-width: 45%;
|
|
1633
|
+
min-width: 0;
|
|
1634
|
+
height: var(--dg-filter-input-height);
|
|
1635
|
+
margin-inline-end: 2px;
|
|
1636
|
+
padding: 0 2px;
|
|
1637
|
+
border: 1px solid var(--dg-border-strong);
|
|
1638
|
+
border-radius: var(--dg-radius-control);
|
|
1639
|
+
background: var(--dg-surface);
|
|
1640
|
+
color: var(--dg-text);
|
|
1641
|
+
font: inherit;
|
|
1642
|
+
font-size: var(--dg-control-font-size);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
.kanuni-datagrid-filter-operator:focus {
|
|
1646
|
+
outline: none;
|
|
1647
|
+
border-color: var(--dg-primary);
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
/* A column's own filter UI (`renderFilter`) in the filter row. */
|
|
1651
|
+
.kanuni-datagrid-filter-custom {
|
|
1652
|
+
display: flex;
|
|
1653
|
+
align-items: center;
|
|
1654
|
+
width: 100%;
|
|
1655
|
+
min-width: 0;
|
|
1656
|
+
height: 100%;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1457
1659
|
/* ── Header filter popup (portaled — see GridPortal) ──────── */
|
|
1458
1660
|
.kanuni-datagrid-portal {
|
|
1459
1661
|
/* The portal host must not paint or capture anything itself. */
|
|
@@ -1529,6 +1731,14 @@
|
|
|
1529
1731
|
overflow-wrap: anywhere;
|
|
1530
1732
|
}
|
|
1531
1733
|
|
|
1734
|
+
/* An interactive tooltip (P-TOOL-01) takes the pointer: its text can be
|
|
1735
|
+
selected and a link in it clicked. The grace period in the hook lets the
|
|
1736
|
+
pointer cross the gap from the cell without closing it. */
|
|
1737
|
+
.kanuni-datagrid-tooltip--interactive {
|
|
1738
|
+
pointer-events: auto;
|
|
1739
|
+
user-select: text;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1532
1742
|
.kanuni-datagrid-filter-popup {
|
|
1533
1743
|
position: fixed;
|
|
1534
1744
|
z-index: 1000;
|
|
@@ -1547,6 +1757,13 @@
|
|
|
1547
1757
|
font-size: var(--dg-font-size);
|
|
1548
1758
|
}
|
|
1549
1759
|
|
|
1760
|
+
/* The app's own content (`renderFilter`): it decides its size, not the list. */
|
|
1761
|
+
.kanuni-datagrid-filter-popup--custom {
|
|
1762
|
+
width: auto;
|
|
1763
|
+
min-width: 200px;
|
|
1764
|
+
max-height: none;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1550
1767
|
.kanuni-datagrid-filter-search {
|
|
1551
1768
|
width: 100%;
|
|
1552
1769
|
height: var(--dg-control-height);
|
|
@@ -1947,7 +2164,10 @@
|
|
|
1947
2164
|
/* Sticky in the same stack as the header and the footer. `--dg-pinned-gap`
|
|
1948
2165
|
counts the header-height rows between this block and its edge (header +
|
|
1949
2166
|
filter row above, footer below), so the offset follows the THEME's header
|
|
1950
|
-
height instead of a number measured in JS at the previous theme's size.
|
|
2167
|
+
height instead of a number measured in JS at the previous theme's size.
|
|
2168
|
+
The one exception is the header itself under `autoHeaderHeight`: its
|
|
2169
|
+
height is the tallest wrapped caption, which only layout knows, so it
|
|
2170
|
+
counts as `--dg-header-actual` and the other rows of the stack as tokens. */
|
|
1951
2171
|
.kanuni-datagrid-pinned-rows {
|
|
1952
2172
|
position: sticky;
|
|
1953
2173
|
/* Above the data rows, below the header — a pinned row must not cover the
|
|
@@ -1959,7 +2179,8 @@
|
|
|
1959
2179
|
}
|
|
1960
2180
|
|
|
1961
2181
|
.kanuni-datagrid-pinned-rows--top {
|
|
1962
|
-
top: calc(var(--dg-band-offset, 0px) + var(--dg-header-height) * var(--dg-pinned-gap, 1))
|
|
2182
|
+
top: calc(var(--dg-band-offset, 0px) + var(--dg-header-height) * (var(--dg-pinned-gap, 1) - 1) +
|
|
2183
|
+
var(--dg-header-actual, var(--dg-header-height)));
|
|
1963
2184
|
border-bottom: var(--dg-header-border);
|
|
1964
2185
|
}
|
|
1965
2186
|
|
|
@@ -1975,8 +2196,8 @@
|
|
|
1975
2196
|
.kanuni-datagrid-sticky-groups {
|
|
1976
2197
|
position: sticky;
|
|
1977
2198
|
top: calc(
|
|
1978
|
-
var(--dg-band-offset, 0px) + var(--dg-header-height) * var(--dg-pinned-gap, 1) +
|
|
1979
|
-
var(--dg-sticky-below, 0px)
|
|
2199
|
+
var(--dg-band-offset, 0px) + var(--dg-header-height) * (var(--dg-pinned-gap, 1) - 1) +
|
|
2200
|
+
var(--dg-header-actual, var(--dg-header-height)) + var(--dg-sticky-below, 0px)
|
|
1980
2201
|
);
|
|
1981
2202
|
z-index: 2;
|
|
1982
2203
|
height: 0;
|
|
@@ -2020,7 +2241,8 @@
|
|
|
2020
2241
|
/* Totals at the TOP (P2.8) — same row, other edge. The border swaps sides so
|
|
2021
2242
|
the rule always separates the totals from the DATA, not from the header. */
|
|
2022
2243
|
.kanuni-datagrid-footer-row--top {
|
|
2023
|
-
top: calc(var(--dg-band-offset, 0px) + var(--dg-header-height) * var(--dg-pinned-gap, 1))
|
|
2244
|
+
top: calc(var(--dg-band-offset, 0px) + var(--dg-header-height) * (var(--dg-pinned-gap, 1) - 1) +
|
|
2245
|
+
var(--dg-header-actual, var(--dg-header-height)));
|
|
2024
2246
|
bottom: auto;
|
|
2025
2247
|
border-top: none;
|
|
2026
2248
|
border-bottom: var(--dg-header-border);
|
|
@@ -2534,15 +2756,412 @@
|
|
|
2534
2756
|
}
|
|
2535
2757
|
}
|
|
2536
2758
|
|
|
2759
|
+
/* ══ Editing (moved from the Enterprise stylesheet, 2026-10-12) ═══════════
|
|
2760
|
+
Single-cell editing is Community now, in both renderers, so the editor,
|
|
2761
|
+
the date and lookup editors and the confirm/error dialog are styled here;
|
|
2762
|
+
the Enterprise stylesheet keeps only what its own modes add. */
|
|
2763
|
+
|
|
2764
|
+
/* ── In-cell editor ───────────────────────────────────────── */
|
|
2765
|
+
/* One line, not two boxes.
|
|
2766
|
+
The editor used to draw a 2px rounded border INSIDE a cell that already had
|
|
2767
|
+
a 2px focus outline — two concentric blue rectangles a couple of pixels
|
|
2768
|
+
apart, which is the busiest possible way to say "you are typing here". A
|
|
2769
|
+
single underline on the cell being edited says the same thing (the
|
|
2770
|
+
DevExtreme convention), and the outline is dropped for that one cell below. */
|
|
2771
|
+
.kanuni-datagrid-root .kanuni-datagrid-editor {
|
|
2772
|
+
width: 100%;
|
|
2773
|
+
min-width: 0;
|
|
2774
|
+
height: calc(var(--dg-row-height) - 2px);
|
|
2775
|
+
padding: 0 4px;
|
|
2776
|
+
border: none;
|
|
2777
|
+
border-bottom: 2px solid var(--dg-primary);
|
|
2778
|
+
border-radius: 0;
|
|
2779
|
+
background: transparent;
|
|
2780
|
+
color: var(--dg-text);
|
|
2781
|
+
font: inherit;
|
|
2782
|
+
font-size: var(--dg-font-size);
|
|
2783
|
+
margin: 0;
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
/* Edge to edge of the CELL, not of its padding box.
|
|
2787
|
+
`width: 100%` resolves against the content box — the cell minus 2 ×
|
|
2788
|
+
--dg-cell-padding-x — and a negative margin only shifts a box, it does not
|
|
2789
|
+
widen it. The two together left the editor starting early and stopping short
|
|
2790
|
+
of the right edge, read as the field sliding out of its column and most
|
|
2791
|
+
visible on a pinned one, where the neighbouring cell does not move with it.
|
|
2792
|
+
|
|
2793
|
+
Applied to whatever is the cell's DIRECT CHILD, because that is the element
|
|
2794
|
+
whose `100%` means "the cell". Naming the input alone was wrong the moment an
|
|
2795
|
+
editor grew a wrapper — the date editor's box sat 8px inside its cell on the
|
|
2796
|
+
left and 9px on the right, while every plain editor beside it went edge to
|
|
2797
|
+
edge. Same reason the form's wrappers are excluded: they are not in a cell,
|
|
2798
|
+
and pulling them out by a cell's padding would misalign the form instead. */
|
|
2799
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell > .kanuni-datagrid-editor,
|
|
2800
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell > .kanuni-datagrid-date-editor {
|
|
2801
|
+
width: calc(100% + var(--dg-cell-padding-x) * 2);
|
|
2802
|
+
margin: 0 calc(var(--dg-cell-padding-x) * -1);
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
/* In a WRAPPED cell the editor takes the LINE BOX, not the row height.
|
|
2806
|
+
A wrapping cell is as tall as its own text: one line of it is
|
|
2807
|
+
`padding-block x2 + --dg-wrap-line-height`, which is shorter than a standard
|
|
2808
|
+
row. Giving the editor the row height there made the cell taller than the
|
|
2809
|
+
text it replaced, so the row grew the moment an editor opened and every row
|
|
2810
|
+
below it hopped down — most obvious on a theme with tall rows, but the
|
|
2811
|
+
default did it too.
|
|
2812
|
+
|
|
2813
|
+
Matching the line box means the box the user types into occupies exactly the
|
|
2814
|
+
space the text did, and the row does not move at all. */
|
|
2815
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--wrap > .kanuni-datagrid-editor,
|
|
2816
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--wrap > .kanuni-datagrid-date-editor {
|
|
2817
|
+
height: var(--dg-wrap-line-height);
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
.kanuni-datagrid-root .kanuni-datagrid-editor:focus {
|
|
2821
|
+
outline: none;
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2824
|
+
.kanuni-datagrid-root .kanuni-datagrid-editor--invalid {
|
|
2825
|
+
border-bottom-color: var(--dg-danger);
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
/* The cell holding an editor gives up its focus ring — the underline is the
|
|
2829
|
+
marker now, and the ring is the other half of the double rectangle.
|
|
2830
|
+
It also goes to the plain surface colour: the row underneath may be striped,
|
|
2831
|
+
selected, focused or in-range, and a blue underline drawn over a blue-tinted
|
|
2832
|
+
cell is the one thing it must not compete with. Listed after the row-state
|
|
2833
|
+
rules and with two classes, so it outranks all of them. */
|
|
2834
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--editing,
|
|
2835
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--editing.kanuni-datagrid-cell--focused,
|
|
2836
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--editing.kanuni-datagrid-cell--in-range,
|
|
2837
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--editing.kanuni-datagrid-cell--pinned {
|
|
2838
|
+
outline: none;
|
|
2839
|
+
background: var(--dg-surface);
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
.kanuni-datagrid-root input.kanuni-datagrid-editor[type='checkbox'] {
|
|
2843
|
+
width: auto;
|
|
2844
|
+
height: auto;
|
|
2845
|
+
margin: 0;
|
|
2846
|
+
border: none;
|
|
2847
|
+
accent-color: var(--dg-primary);
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
/* Validation message floats out of the cell so it is not clipped by overflow.
|
|
2851
|
+
That only works if the editing cell LETS it out and its row sits above the
|
|
2852
|
+
next one: cells are `overflow: hidden` and every row paints over the one
|
|
2853
|
+
before it, so until 2026-10-01 the message rendered into the DOM, positioned
|
|
2854
|
+
correctly, and was never seen — the user got a red underline and no reason
|
|
2855
|
+
(found shooting the order-editing demo; measured in Chrome, the message box
|
|
2856
|
+
at the right place and fully covered). With these two rules it shows;
|
|
2857
|
+
whether either alone would do was not measured. */
|
|
2858
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--editing {
|
|
2859
|
+
overflow: visible;
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2862
|
+
.kanuni-datagrid-root .kanuni-datagrid-row:has(.kanuni-datagrid-cell--editing) {
|
|
2863
|
+
position: relative;
|
|
2864
|
+
z-index: 4;
|
|
2865
|
+
overflow: visible;
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
.kanuni-datagrid-root .kanuni-datagrid-editor-error {
|
|
2869
|
+
position: absolute;
|
|
2870
|
+
z-index: 6;
|
|
2871
|
+
transform: translateY(calc(var(--dg-row-height) - 2px));
|
|
2872
|
+
max-width: 240px;
|
|
2873
|
+
padding: 2px 6px;
|
|
2874
|
+
border-radius: var(--dg-radius-control);
|
|
2875
|
+
background: var(--dg-danger);
|
|
2876
|
+
color: var(--dg-on-danger);
|
|
2877
|
+
font-size: 11px;
|
|
2878
|
+
white-space: nowrap;
|
|
2879
|
+
pointer-events: none;
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
/* ── Lookup combo box ─────────────────────────────────────── */
|
|
2883
|
+
/* Rendered in a portal on <body>, so it is NOT under .kanuni-datagrid-root and
|
|
2884
|
+
cannot inherit the theme tokens through the cascade. It reads them from
|
|
2885
|
+
:root, which is where the light/dark blocks define them. */
|
|
2886
|
+
/* ── Date editor ──────────────────────────────────────────── */
|
|
2887
|
+
/* The box and its calendar button share the cell: the input takes the space
|
|
2888
|
+
that is left, so the button never overlaps the text however narrow the
|
|
2889
|
+
column is. */
|
|
2890
|
+
.kanuni-datagrid-date-editor {
|
|
2891
|
+
display: flex;
|
|
2892
|
+
align-items: center;
|
|
2893
|
+
gap: 2px;
|
|
2894
|
+
width: 100%;
|
|
2895
|
+
min-width: 0;
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
/* Inside a box that already owns the cell — compensating twice would push the
|
|
2899
|
+
field back out by another padding on each side. */
|
|
2900
|
+
.kanuni-datagrid-date-editor > .kanuni-datagrid-editor {
|
|
2901
|
+
width: auto;
|
|
2902
|
+
margin: 0;
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
.kanuni-datagrid-date-editor > .kanuni-datagrid-editor {
|
|
2906
|
+
flex: 1;
|
|
2907
|
+
min-width: 0;
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2910
|
+
.kanuni-datagrid-date-button {
|
|
2911
|
+
flex: none;
|
|
2912
|
+
display: inline-flex;
|
|
2913
|
+
align-items: center;
|
|
2914
|
+
justify-content: center;
|
|
2915
|
+
width: 20px;
|
|
2916
|
+
height: 20px;
|
|
2917
|
+
padding: 0;
|
|
2918
|
+
border: 0;
|
|
2919
|
+
border-radius: 3px;
|
|
2920
|
+
background: transparent;
|
|
2921
|
+
color: var(--dg-text-muted, #64748b);
|
|
2922
|
+
cursor: pointer;
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
.kanuni-datagrid-date-button:hover:not(:disabled) {
|
|
2926
|
+
background: var(--dg-surface-hover, #f1f5f9);
|
|
2927
|
+
color: var(--dg-primary, #2563eb);
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
.kanuni-datagrid-date-button:disabled {
|
|
2931
|
+
opacity: 0.5;
|
|
2932
|
+
cursor: default;
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
.kanuni-datagrid-date-popup {
|
|
2936
|
+
position: fixed;
|
|
2937
|
+
z-index: 1200;
|
|
2938
|
+
padding: 8px;
|
|
2939
|
+
border: 1px solid var(--dg-border-strong, #cbd5e1);
|
|
2940
|
+
border-radius: var(--dg-radius);
|
|
2941
|
+
background: var(--dg-surface, #fff);
|
|
2942
|
+
box-shadow: var(--dg-shadow-popup-sm);
|
|
2943
|
+
color: var(--dg-text, #0f172a);
|
|
2944
|
+
font-size: var(--dg-font-size);
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
.kanuni-datagrid-date-popup-head {
|
|
2948
|
+
display: flex;
|
|
2949
|
+
align-items: center;
|
|
2950
|
+
justify-content: space-between;
|
|
2951
|
+
gap: 8px;
|
|
2952
|
+
margin-bottom: 6px;
|
|
2953
|
+
font-weight: 600;
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
.kanuni-datagrid-date-popup-head button {
|
|
2957
|
+
width: 24px;
|
|
2958
|
+
height: 24px;
|
|
2959
|
+
border: 0;
|
|
2960
|
+
border-radius: var(--dg-radius-control);
|
|
2961
|
+
background: transparent;
|
|
2962
|
+
color: inherit;
|
|
2963
|
+
font-size: 16px;
|
|
2964
|
+
line-height: 1;
|
|
2965
|
+
cursor: pointer;
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2968
|
+
.kanuni-datagrid-date-popup-head button:hover {
|
|
2969
|
+
background: var(--dg-surface-hover, #f1f5f9);
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
/* Seven fixed columns: a calendar that reflows is not a calendar. */
|
|
2973
|
+
.kanuni-datagrid-date-popup-grid {
|
|
2974
|
+
display: grid;
|
|
2975
|
+
grid-template-columns: repeat(7, 28px);
|
|
2976
|
+
gap: 1px;
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2979
|
+
.kanuni-datagrid-date-weekday {
|
|
2980
|
+
display: flex;
|
|
2981
|
+
align-items: center;
|
|
2982
|
+
justify-content: center;
|
|
2983
|
+
height: 22px;
|
|
2984
|
+
color: var(--dg-text-muted, #64748b);
|
|
2985
|
+
font-size: 11px;
|
|
2986
|
+
font-weight: 600;
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
.kanuni-datagrid-date-day {
|
|
2990
|
+
height: 26px;
|
|
2991
|
+
border: 0;
|
|
2992
|
+
border-radius: var(--dg-radius-control);
|
|
2993
|
+
background: transparent;
|
|
2994
|
+
color: inherit;
|
|
2995
|
+
font: inherit;
|
|
2996
|
+
cursor: pointer;
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
.kanuni-datagrid-date-day:hover {
|
|
3000
|
+
background: var(--dg-surface-hover, #f1f5f9);
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
/* Days spilling in from the neighbouring months stay clickable — paging to
|
|
3004
|
+
pick the 1st of next month is a step nobody should have to take — but they
|
|
3005
|
+
read as context rather than as part of this month. */
|
|
3006
|
+
.kanuni-datagrid-date-day--outside {
|
|
3007
|
+
opacity: 0.4;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
.kanuni-datagrid-date-day--selected {
|
|
3011
|
+
background: var(--dg-primary);
|
|
3012
|
+
color: var(--dg-on-primary);
|
|
3013
|
+
font-weight: 600;
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
.kanuni-datagrid-lookup-popup {
|
|
3017
|
+
position: fixed;
|
|
3018
|
+
z-index: 1200;
|
|
3019
|
+
overflow-y: auto;
|
|
3020
|
+
border: 1px solid var(--dg-border-strong, #cbd5e1);
|
|
3021
|
+
border-radius: var(--dg-radius-control);
|
|
3022
|
+
background: var(--dg-surface, #fff);
|
|
3023
|
+
box-shadow: var(--dg-shadow-popup-sm);
|
|
3024
|
+
color: var(--dg-text, #0f172a);
|
|
3025
|
+
font-size: var(--dg-font-size);
|
|
3026
|
+
}
|
|
3027
|
+
|
|
3028
|
+
.kanuni-datagrid-lookup-item {
|
|
3029
|
+
padding: 4px 8px;
|
|
3030
|
+
line-height: 18px;
|
|
3031
|
+
white-space: nowrap;
|
|
3032
|
+
overflow: hidden;
|
|
3033
|
+
text-overflow: ellipsis;
|
|
3034
|
+
cursor: pointer;
|
|
3035
|
+
}
|
|
3036
|
+
|
|
3037
|
+
.kanuni-datagrid-lookup-item--active {
|
|
3038
|
+
background: var(--dg-primary);
|
|
3039
|
+
color: var(--dg-on-primary);
|
|
3040
|
+
}
|
|
3041
|
+
|
|
3042
|
+
.kanuni-datagrid-lookup-empty {
|
|
3043
|
+
padding: 4px 8px;
|
|
3044
|
+
color: var(--dg-text-muted, #64748b);
|
|
3045
|
+
font-style: italic;
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3048
|
+
/* ── Confirmation / error dialog ──────────────────────────── */
|
|
3049
|
+
.kanuni-datagrid-dialog-root {
|
|
3050
|
+
position: fixed;
|
|
3051
|
+
inset: 0;
|
|
3052
|
+
z-index: 1400;
|
|
3053
|
+
display: flex;
|
|
3054
|
+
align-items: center;
|
|
3055
|
+
justify-content: center;
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
.kanuni-datagrid-dialog-overlay {
|
|
3059
|
+
position: absolute;
|
|
3060
|
+
inset: 0;
|
|
3061
|
+
background: var(--dg-overlay);
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
.kanuni-datagrid-dialog {
|
|
3065
|
+
position: relative;
|
|
3066
|
+
width: min(420px, 92vw);
|
|
3067
|
+
padding: 18px 20px 14px;
|
|
3068
|
+
border: 1px solid var(--dg-border-strong, #cbd5e1);
|
|
3069
|
+
border-radius: calc(var(--dg-radius) + 2px);
|
|
3070
|
+
background: var(--dg-surface, #fff);
|
|
3071
|
+
color: var(--dg-text, #0f172a);
|
|
3072
|
+
box-shadow: var(--dg-shadow-dialog);
|
|
3073
|
+
font-size: var(--dg-font-size);
|
|
3074
|
+
}
|
|
3075
|
+
|
|
3076
|
+
.kanuni-datagrid-dialog-title {
|
|
3077
|
+
margin-bottom: 8px;
|
|
3078
|
+
font-size: 15px;
|
|
3079
|
+
font-weight: 600;
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3082
|
+
.kanuni-datagrid-dialog-message {
|
|
3083
|
+
margin-bottom: 18px;
|
|
3084
|
+
line-height: 1.5;
|
|
3085
|
+
color: var(--dg-text, #0f172a);
|
|
3086
|
+
}
|
|
3087
|
+
|
|
3088
|
+
.kanuni-datagrid-dialog-actions {
|
|
3089
|
+
display: flex;
|
|
3090
|
+
justify-content: flex-end;
|
|
3091
|
+
gap: 8px;
|
|
3092
|
+
}
|
|
3093
|
+
|
|
3094
|
+
.kanuni-datagrid-dialog-actions button {
|
|
3095
|
+
padding: 5px 14px;
|
|
3096
|
+
border: 1px solid var(--dg-border-strong, #cbd5e1);
|
|
3097
|
+
border-radius: var(--dg-radius-control);
|
|
3098
|
+
background: var(--dg-surface, #fff);
|
|
3099
|
+
color: inherit;
|
|
3100
|
+
font: inherit;
|
|
3101
|
+
font-size: var(--dg-font-size);
|
|
3102
|
+
cursor: pointer;
|
|
3103
|
+
}
|
|
3104
|
+
|
|
3105
|
+
/* SCOPED TO THE ACTIONS ROW ON PURPOSE, and this is a fix rather than a style.
|
|
3106
|
+
`.kanuni-datagrid-dialog-actions button` above is (0,1,1) — a class and a
|
|
3107
|
+
type — while a bare `.kanuni-datagrid-dialog-primary` is (0,1,0). Specificity
|
|
3108
|
+
beats source order, so the generic rule won and the confirm button had never
|
|
3109
|
+
actually been painted in the accent: it rendered as a plain white button, and
|
|
3110
|
+
the only reason nobody read it as broken is that its label inherited the
|
|
3111
|
+
dialog's text colour instead of the white it was assigned. The sibling
|
|
3112
|
+
primaries elsewhere in this sheet (filter builder, form save) sidestep the
|
|
3113
|
+
same collision with `!important`; matching the selector shape is the same
|
|
3114
|
+
result without the escape hatch. */
|
|
3115
|
+
.kanuni-datagrid-dialog-actions button.kanuni-datagrid-dialog-primary {
|
|
3116
|
+
border-color: var(--dg-primary);
|
|
3117
|
+
background: var(--dg-primary);
|
|
3118
|
+
color: var(--dg-on-primary);
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
/* Composed WITH `--primary`, so it has to restate the foreground: the primary
|
|
3122
|
+
rule painted it `--dg-on-primary`, which is the right colour for the accent
|
|
3123
|
+
and the wrong one for a red fill (near-black on red in the gold themes). */
|
|
3124
|
+
.kanuni-datagrid-dialog-actions button.kanuni-datagrid-dialog-primary--danger {
|
|
3125
|
+
border-color: var(--dg-danger);
|
|
3126
|
+
background: var(--dg-danger);
|
|
3127
|
+
color: var(--dg-on-danger);
|
|
3128
|
+
}
|
|
3129
|
+
|
|
3130
|
+
/* ── Forced colours (Windows high contrast) ─────────────────────
|
|
3131
|
+
The browser replaces our colours with the user's system palette and drops
|
|
3132
|
+
box-shadows and background images, so anything drawn only by a fill or a
|
|
3133
|
+
shadow disappears — the focused cell, a selected row, the editor's
|
|
3134
|
+
underline. Restated with system colours, which survive (accessibility
|
|
3135
|
+
audit, 2026-10-12: there was no forced-colors rule anywhere). */
|
|
3136
|
+
@media (forced-colors: active) {
|
|
3137
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--focused,
|
|
3138
|
+
.kanuni-datagrid-root .kanuni-datagrid-group-row--focused {
|
|
3139
|
+
outline: 2px solid Highlight;
|
|
3140
|
+
outline-offset: -2px;
|
|
3141
|
+
}
|
|
3142
|
+
.kanuni-datagrid-root .kanuni-datagrid-row--selected,
|
|
3143
|
+
.kanuni-datagrid-root .kanuni-datagrid-row--selected .kanuni-datagrid-cell {
|
|
3144
|
+
forced-color-adjust: none;
|
|
3145
|
+
background: Highlight;
|
|
3146
|
+
color: HighlightText;
|
|
3147
|
+
}
|
|
3148
|
+
.kanuni-datagrid-root .kanuni-datagrid-editor {
|
|
3149
|
+
border: 1px solid CanvasText;
|
|
3150
|
+
}
|
|
3151
|
+
.kanuni-datagrid-root :focus-visible {
|
|
3152
|
+
outline: 2px solid Highlight;
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
|
|
2537
3156
|
/* ─────────────────────────────────────────────────────────────
|
|
2538
3157
|
KANUNILABS DataGrid — packaged themes
|
|
2539
3158
|
─────────────────────────────────────────────────────────────
|
|
2540
3159
|
Six presets, each in a light and a dark palette, each at three densities.
|
|
2541
3160
|
Nothing here is copied from a third-party stylesheet: every rule is a
|
|
2542
|
-
KanuniLabs class overriding a KanuniLabs --dg-* token
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
3161
|
+
KanuniLabs class overriding a KanuniLabs --dg-* token, and the names say
|
|
3162
|
+
what each theme does (minimal, ledger, elevated, framed). Until 2026-10-11
|
|
3163
|
+
four of them carried names another grid vendor also uses for its themes;
|
|
3164
|
+
they were renamed so nothing public reads as borrowed.
|
|
2546
3165
|
|
|
2547
3166
|
── How a theme is expressed ───────────────────────────────
|
|
2548
3167
|
A theme is a token override and (almost) nothing else. That is the whole
|
|
@@ -2565,15 +3184,15 @@
|
|
|
2565
3184
|
───────────────────────────────────────────────────────────── */
|
|
2566
3185
|
|
|
2567
3186
|
/* ═══════════════════════════════════════════════════════════
|
|
2568
|
-
|
|
3187
|
+
MINIMAL — modern, minimal chrome
|
|
2569
3188
|
═══════════════════════════════════════════════════════════
|
|
2570
3189
|
The least furniture that still reads as a table: no column separators at
|
|
2571
3190
|
all, hairline row rules, and a header that is the same white as the body,
|
|
2572
3191
|
separated only by one firm line. Generous radii. For product UIs where the
|
|
2573
3192
|
grid sits among cards rather than inside a terminal. */
|
|
2574
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
2575
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
2576
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3193
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-minimal,
|
|
3194
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-minimal,
|
|
3195
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-minimal {
|
|
2577
3196
|
--dg-bg: #ffffff;
|
|
2578
3197
|
--dg-surface: #ffffff;
|
|
2579
3198
|
--dg-surface-header: #ffffff;
|
|
@@ -2618,9 +3237,9 @@
|
|
|
2618
3237
|
--dg-chrome-padding-y: 8px;
|
|
2619
3238
|
}
|
|
2620
3239
|
|
|
2621
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
2622
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
2623
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3240
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-minimal.kanuni-datagrid-dark,
|
|
3241
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-minimal.kanuni-datagrid-dark,
|
|
3242
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-minimal.kanuni-datagrid-dark {
|
|
2624
3243
|
--dg-bg: #0d1117;
|
|
2625
3244
|
--dg-surface: #0d1117;
|
|
2626
3245
|
--dg-surface-header: #0d1117;
|
|
@@ -2641,14 +3260,14 @@
|
|
|
2641
3260
|
}
|
|
2642
3261
|
|
|
2643
3262
|
/* ═══════════════════════════════════════════════════════════
|
|
2644
|
-
|
|
3263
|
+
LEDGER — dense, ruled, financial
|
|
2645
3264
|
═══════════════════════════════════════════════════════════
|
|
2646
3265
|
Every column and every row is ruled, the type is small, the padding is
|
|
2647
3266
|
tight and the corners are nearly square. Built for the case where the grid
|
|
2648
3267
|
IS the application and the user is counting rows on screen. */
|
|
2649
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
2650
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
2651
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3268
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-ledger,
|
|
3269
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-ledger,
|
|
3270
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-ledger {
|
|
2652
3271
|
--dg-bg: #ffffff;
|
|
2653
3272
|
--dg-surface: #ffffff;
|
|
2654
3273
|
--dg-surface-header: #f2f4f6;
|
|
@@ -2703,9 +3322,9 @@
|
|
|
2703
3322
|
--dg-chrome-padding-y: 4px;
|
|
2704
3323
|
}
|
|
2705
3324
|
|
|
2706
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
2707
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
2708
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3325
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-ledger.kanuni-datagrid-dark,
|
|
3326
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-ledger.kanuni-datagrid-dark,
|
|
3327
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-ledger.kanuni-datagrid-dark {
|
|
2709
3328
|
--dg-bg: #1a2029;
|
|
2710
3329
|
--dg-surface: #1a2029;
|
|
2711
3330
|
--dg-surface-header: #232b36;
|
|
@@ -2726,14 +3345,14 @@
|
|
|
2726
3345
|
}
|
|
2727
3346
|
|
|
2728
3347
|
/* ═══════════════════════════════════════════════════════════
|
|
2729
|
-
|
|
3348
|
+
ELEVATED — tall, quiet lines, real elevation
|
|
2730
3349
|
═══════════════════════════════════════════════════════════
|
|
2731
3350
|
Rows only, no column rules; larger rhythm; a header set in medium weight
|
|
2732
3351
|
with open tracking rather than bold; pill-shaped controls; and shadows that
|
|
2733
3352
|
actually lift. The one preset whose type scale grows rather than shrinks. */
|
|
2734
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
2735
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
2736
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3353
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-elevated,
|
|
3354
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-elevated,
|
|
3355
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-elevated {
|
|
2737
3356
|
--dg-bg: #ffffff;
|
|
2738
3357
|
--dg-surface: #ffffff;
|
|
2739
3358
|
--dg-surface-header: #ffffff;
|
|
@@ -2785,9 +3404,9 @@
|
|
|
2785
3404
|
--dg-chrome-padding-y: 10px;
|
|
2786
3405
|
}
|
|
2787
3406
|
|
|
2788
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
2789
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
2790
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3407
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-elevated.kanuni-datagrid-dark,
|
|
3408
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-elevated.kanuni-datagrid-dark,
|
|
3409
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-elevated.kanuni-datagrid-dark {
|
|
2791
3410
|
--dg-bg: #141218;
|
|
2792
3411
|
--dg-surface: #141218;
|
|
2793
3412
|
--dg-surface-header: #141218;
|
|
@@ -2809,14 +3428,14 @@
|
|
|
2809
3428
|
}
|
|
2810
3429
|
|
|
2811
3430
|
/* ═══════════════════════════════════════════════════════════
|
|
2812
|
-
|
|
3431
|
+
FRAMED — airy, fully framed, high-chroma accent
|
|
2813
3432
|
═══════════════════════════════════════════════════════════
|
|
2814
3433
|
The middle position: both sets of rules are drawn but kept light, the rhythm
|
|
2815
3434
|
is roomy, and the header is anchored by a doubled rule and a heavy weight so
|
|
2816
3435
|
it reads as a distinct band even though it shares the body's palette. */
|
|
2817
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
2818
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
2819
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3436
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-framed,
|
|
3437
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-framed,
|
|
3438
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-framed {
|
|
2820
3439
|
--dg-bg: #ffffff;
|
|
2821
3440
|
--dg-surface: #ffffff;
|
|
2822
3441
|
--dg-surface-header: #f8f9fa;
|
|
@@ -2863,9 +3482,9 @@
|
|
|
2863
3482
|
--dg-chrome-padding-y: 7px;
|
|
2864
3483
|
}
|
|
2865
3484
|
|
|
2866
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
2867
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
2868
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3485
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-framed.kanuni-datagrid-dark,
|
|
3486
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-framed.kanuni-datagrid-dark,
|
|
3487
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-framed.kanuni-datagrid-dark {
|
|
2869
3488
|
--dg-bg: #181d1f;
|
|
2870
3489
|
--dg-surface: #181d1f;
|
|
2871
3490
|
--dg-surface-header: #222628;
|
|
@@ -3033,7 +3652,7 @@
|
|
|
3033
3652
|
together — row, header, cell padding, control height, toolbar and pager
|
|
3034
3653
|
padding, filter field — so the proportions hold and the grid stays usable
|
|
3035
3654
|
rather than merely smaller. Each theme scales from its OWN normal, because a
|
|
3036
|
-
|
|
3655
|
+
Elevated row starts at 40px and a Ledger row at 25px; one shared compact
|
|
3037
3656
|
value would have flattened the presets into each other at that density.
|
|
3038
3657
|
|
|
3039
3658
|
The ROW HEIGHT is deliberately absent here: it is a core value the
|
|
@@ -3046,10 +3665,10 @@
|
|
|
3046
3665
|
base sheet's presets are root-only, which left popup controls at their
|
|
3047
3666
|
normal size whatever the grid was set to. */
|
|
3048
3667
|
|
|
3049
|
-
/* ──
|
|
3050
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
3051
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
3052
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3668
|
+
/* ── Minimal ── */
|
|
3669
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-minimal.kanuni-datagrid-density-compact,
|
|
3670
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-minimal.kanuni-datagrid-density-compact,
|
|
3671
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-minimal.kanuni-datagrid-density-compact {
|
|
3053
3672
|
--dg-header-height: 30px;
|
|
3054
3673
|
--dg-cell-padding-x: 8px;
|
|
3055
3674
|
--dg-font-size: 12px;
|
|
@@ -3062,9 +3681,9 @@
|
|
|
3062
3681
|
--dg-chrome-padding-y: 4px;
|
|
3063
3682
|
}
|
|
3064
3683
|
|
|
3065
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
3066
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
3067
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3684
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-minimal.kanuni-datagrid-density-comfortable,
|
|
3685
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-minimal.kanuni-datagrid-density-comfortable,
|
|
3686
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-minimal.kanuni-datagrid-density-comfortable {
|
|
3068
3687
|
--dg-header-height: 48px;
|
|
3069
3688
|
--dg-cell-padding-x: 16px;
|
|
3070
3689
|
--dg-font-size: 14px;
|
|
@@ -3077,10 +3696,10 @@
|
|
|
3077
3696
|
--dg-chrome-padding-y: 10px;
|
|
3078
3697
|
}
|
|
3079
3698
|
|
|
3080
|
-
/* ──
|
|
3081
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
3082
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
3083
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3699
|
+
/* ── Ledger ── */
|
|
3700
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-ledger.kanuni-datagrid-density-compact,
|
|
3701
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-ledger.kanuni-datagrid-density-compact,
|
|
3702
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-ledger.kanuni-datagrid-density-compact {
|
|
3084
3703
|
--dg-header-height: 22px;
|
|
3085
3704
|
--dg-cell-padding-x: 4px;
|
|
3086
3705
|
--dg-font-size: 11px;
|
|
@@ -3093,9 +3712,9 @@
|
|
|
3093
3712
|
--dg-chrome-padding-y: 2px;
|
|
3094
3713
|
}
|
|
3095
3714
|
|
|
3096
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
3097
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
3098
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3715
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-ledger.kanuni-datagrid-density-comfortable,
|
|
3716
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-ledger.kanuni-datagrid-density-comfortable,
|
|
3717
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-ledger.kanuni-datagrid-density-comfortable {
|
|
3099
3718
|
--dg-header-height: 36px;
|
|
3100
3719
|
--dg-cell-padding-x: 10px;
|
|
3101
3720
|
--dg-font-size: 13px;
|
|
@@ -3108,10 +3727,10 @@
|
|
|
3108
3727
|
--dg-chrome-padding-y: 6px;
|
|
3109
3728
|
}
|
|
3110
3729
|
|
|
3111
|
-
/* ──
|
|
3112
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
3113
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
3114
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3730
|
+
/* ── Elevated ── */
|
|
3731
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-elevated.kanuni-datagrid-density-compact,
|
|
3732
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-elevated.kanuni-datagrid-density-compact,
|
|
3733
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-elevated.kanuni-datagrid-density-compact {
|
|
3115
3734
|
--dg-header-height: 36px;
|
|
3116
3735
|
--dg-cell-padding-x: 12px;
|
|
3117
3736
|
--dg-font-size: 13px;
|
|
@@ -3124,9 +3743,9 @@
|
|
|
3124
3743
|
--dg-chrome-padding-y: 6px;
|
|
3125
3744
|
}
|
|
3126
3745
|
|
|
3127
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
3128
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
3129
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3746
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-elevated.kanuni-datagrid-density-comfortable,
|
|
3747
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-elevated.kanuni-datagrid-density-comfortable,
|
|
3748
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-elevated.kanuni-datagrid-density-comfortable {
|
|
3130
3749
|
--dg-header-height: 56px;
|
|
3131
3750
|
--dg-cell-padding-x: 20px;
|
|
3132
3751
|
--dg-font-size: 15px;
|
|
@@ -3139,10 +3758,10 @@
|
|
|
3139
3758
|
--dg-chrome-padding-y: 12px;
|
|
3140
3759
|
}
|
|
3141
3760
|
|
|
3142
|
-
/* ──
|
|
3143
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
3144
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
3145
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3761
|
+
/* ── Framed ── */
|
|
3762
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-framed.kanuni-datagrid-density-compact,
|
|
3763
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-framed.kanuni-datagrid-density-compact,
|
|
3764
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-framed.kanuni-datagrid-density-compact {
|
|
3146
3765
|
--dg-header-height: 28px;
|
|
3147
3766
|
--dg-cell-padding-x: 8px;
|
|
3148
3767
|
--dg-font-size: 12px;
|
|
@@ -3155,9 +3774,9 @@
|
|
|
3155
3774
|
--dg-chrome-padding-y: 4px;
|
|
3156
3775
|
}
|
|
3157
3776
|
|
|
3158
|
-
.kanuni-datagrid-root.kanuni-datagrid-theme-
|
|
3159
|
-
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-
|
|
3160
|
-
.kanuni-datagrid-detached.kanuni-datagrid-theme-
|
|
3777
|
+
.kanuni-datagrid-root.kanuni-datagrid-theme-framed.kanuni-datagrid-density-comfortable,
|
|
3778
|
+
.kanuni-datagrid-enterprise.kanuni-datagrid-theme-framed.kanuni-datagrid-density-comfortable,
|
|
3779
|
+
.kanuni-datagrid-detached.kanuni-datagrid-theme-framed.kanuni-datagrid-density-comfortable {
|
|
3161
3780
|
--dg-header-height: 46px;
|
|
3162
3781
|
--dg-cell-padding-x: 16px;
|
|
3163
3782
|
--dg-font-size: 14px;
|
|
@@ -3263,17 +3882,17 @@
|
|
|
3263
3882
|
the edge element (there is exactly one per side, not one per cell) restores
|
|
3264
3883
|
it without bringing the column rules back.
|
|
3265
3884
|
|
|
3266
|
-
Every ruled preset —
|
|
3885
|
+
Every ruled preset — Ledger, Framed — needs nothing here: the seam is
|
|
3267
3886
|
already drawn by the cell borders they keep. */
|
|
3268
|
-
.kanuni-datagrid-theme-
|
|
3269
|
-
.kanuni-datagrid-theme-
|
|
3887
|
+
.kanuni-datagrid-theme-minimal .kanuni-datagrid-pin-edge-left,
|
|
3888
|
+
.kanuni-datagrid-theme-elevated .kanuni-datagrid-pin-edge-left,
|
|
3270
3889
|
.kanuni-datagrid-theme-kanuni .kanuni-datagrid-pin-edge-left,
|
|
3271
3890
|
.kanuni-datagrid-theme-kanuni-midnight .kanuni-datagrid-pin-edge-left {
|
|
3272
3891
|
border-inline-end: 1px solid var(--dg-border-strong);
|
|
3273
3892
|
}
|
|
3274
3893
|
|
|
3275
|
-
.kanuni-datagrid-theme-
|
|
3276
|
-
.kanuni-datagrid-theme-
|
|
3894
|
+
.kanuni-datagrid-theme-minimal .kanuni-datagrid-pin-edge-right,
|
|
3895
|
+
.kanuni-datagrid-theme-elevated .kanuni-datagrid-pin-edge-right,
|
|
3277
3896
|
.kanuni-datagrid-theme-kanuni .kanuni-datagrid-pin-edge-right,
|
|
3278
3897
|
.kanuni-datagrid-theme-kanuni-midnight .kanuni-datagrid-pin-edge-right {
|
|
3279
3898
|
border-inline-start: 1px solid var(--dg-border-strong);
|
|
@@ -3285,8 +3904,8 @@
|
|
|
3285
3904
|
A palette is a SECOND, independent axis: it changes the colours and nothing
|
|
3286
3905
|
else. The theme keeps deciding the structure — where the rules are drawn, how
|
|
3287
3906
|
tall a row is, how round a control is, how much the popups lift — so
|
|
3288
|
-
`theme="
|
|
3289
|
-
blues, and `theme="
|
|
3907
|
+
`theme="ledger" palette="nord"` is Ledger's dense ruled grid in Nord's arctic
|
|
3908
|
+
blues, and `theme="elevated" palette="nord"` is Elevated's tall airy one in
|
|
3290
3909
|
the same blues. Four themes and six palettes is twenty-four looks out of ten
|
|
3291
3910
|
class names, not twenty-four stylesheets.
|
|
3292
3911
|
|