@kanunilabs/datagrid 1.9.0 → 1.9.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/dist/datagrid.umd.js +8 -8
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +123 -11
- package/dist/index.d.ts +123 -11
- package/dist/index.js +2 -2
- package/dist/styles.css +541 -1
- package/dist/themes/all.css +108 -0
- package/dist/themes/amber.css +3 -0
- package/dist/themes/aubergine.css +3 -0
- package/dist/themes/azure.css +3 -0
- package/dist/themes/burgundy.css +3 -0
- package/dist/themes/charcoal.css +3 -0
- package/dist/themes/contrast-dark.css +3 -0
- package/dist/themes/contrast-light.css +3 -0
- package/dist/themes/coral.css +3 -0
- package/dist/themes/corporate.css +3 -0
- package/dist/themes/deep-sea.css +3 -0
- package/dist/themes/editorial.css +3 -0
- package/dist/themes/ember.css +3 -0
- package/dist/themes/emerald.css +3 -0
- package/dist/themes/forest.css +3 -0
- package/dist/themes/glacier.css +3 -0
- package/dist/themes/graphite.css +3 -0
- package/dist/themes/indigo-night.css +3 -0
- package/dist/themes/indigo.css +3 -0
- package/dist/themes/ivory.css +3 -0
- package/dist/themes/lagoon.css +3 -0
- package/dist/themes/linen.css +3 -0
- package/dist/themes/midnight.css +3 -0
- package/dist/themes/mist.css +3 -0
- package/dist/themes/monochrome.css +3 -0
- package/dist/themes/onyx.css +3 -0
- package/dist/themes/orchid.css +3 -0
- package/dist/themes/porcelain.css +3 -0
- package/dist/themes/rose.css +3 -0
- package/dist/themes/sandstone.css +3 -0
- package/dist/themes/slate-night.css +3 -0
- package/dist/themes/slate.css +3 -0
- package/dist/themes/steel.css +3 -0
- package/dist/themes/stone.css +3 -0
- package/dist/themes/taupe.css +3 -0
- package/dist/themes/teal.css +3 -0
- package/dist/themes/terminal.css +3 -0
- package/package.json +4 -4
package/dist/styles.css
CHANGED
|
@@ -84,6 +84,9 @@
|
|
|
84
84
|
--dg-danger: #dc2626; /* red-600 — borders, solid fills */
|
|
85
85
|
--dg-danger-text: #b91c1c; /* red-700 — text on a light surface */
|
|
86
86
|
--dg-on-danger: #ffffff; /* text ON a solid --dg-danger fill */
|
|
87
|
+
--dg-success: #15803d; /* green-700 — fills ("saved" marks) */
|
|
88
|
+
--dg-success-text: #166534; /* success as text on a light surface */
|
|
89
|
+
--dg-on-success: #ffffff; /* text ON a solid --dg-success fill */
|
|
87
90
|
--dg-warning: #b45309; /* amber-700 */
|
|
88
91
|
--dg-selected-bg: var(--dg-primary-soft);
|
|
89
92
|
/* Search highlight (P2.4). Amber rather than the accent: the accent already
|
|
@@ -171,10 +174,20 @@
|
|
|
171
174
|
color: var(--dg-text);
|
|
172
175
|
}
|
|
173
176
|
|
|
177
|
+
/* Typeface. Inherited from the page unless --dg-font-family names one — set
|
|
178
|
+
it once (on :root, or in a palette class) and the grid, the Enterprise
|
|
179
|
+
chrome around it and every popup portalled to <body> use it. Without the
|
|
180
|
+
variable, a font set only on the grid's container never reached the menus
|
|
181
|
+
and dialogs, which inherit from <body> (2026-10-16, customer request). */
|
|
182
|
+
.kanuni-datagrid-enterprise,
|
|
183
|
+
.kanuni-datagrid-detached {
|
|
184
|
+
font-family: var(--dg-font-family, inherit);
|
|
185
|
+
}
|
|
186
|
+
|
|
174
187
|
/* The grid's own box. */
|
|
175
188
|
.kanuni-datagrid-root {
|
|
176
189
|
box-sizing: border-box;
|
|
177
|
-
font-family: inherit;
|
|
190
|
+
font-family: var(--dg-font-family, inherit);
|
|
178
191
|
-webkit-font-smoothing: antialiased;
|
|
179
192
|
-moz-osx-font-smoothing: grayscale;
|
|
180
193
|
position: relative;
|
|
@@ -229,6 +242,9 @@
|
|
|
229
242
|
/* The dark danger is a LIGHT red, so what sits on it has to be dark. White
|
|
230
243
|
on #f87171 measures 2.4:1 — the delete button's own label. */
|
|
231
244
|
--dg-on-danger: #450a0a;
|
|
245
|
+
--dg-success: #4ade80;
|
|
246
|
+
--dg-success-text: #86efac;
|
|
247
|
+
--dg-on-success: #0d2817;
|
|
232
248
|
--dg-warning: #fbbf24;
|
|
233
249
|
--dg-overlay: rgba(2, 6, 23, 0.7);
|
|
234
250
|
--dg-scrollbar-thumb: #475569;
|
|
@@ -3181,6 +3197,491 @@
|
|
|
3181
3197
|
}
|
|
3182
3198
|
}
|
|
3183
3199
|
|
|
3200
|
+
/* ─────────────────────────────────────────────────────────────
|
|
3201
|
+
Editing modes: batch, row, form, popup.
|
|
3202
|
+
─────────────────────────────────────────────────────────────
|
|
3203
|
+
Moved here from the Enterprise sheet when these modes became Community
|
|
3204
|
+
(owner decision, 2026-10-16). The Enterprise sheet loads after this one,
|
|
3205
|
+
so the Enterprise grid looks exactly as before; the plain-JS grid reads
|
|
3206
|
+
this file too. The command column's rules stay in the Enterprise sheet. */
|
|
3207
|
+
|
|
3208
|
+
/* ── Pending (unsaved) edits ──────────────────────────────── */
|
|
3209
|
+
/* A corner triangle rather than a background tint: the row may already be
|
|
3210
|
+
striped, selected or in-range, and those must stay distinguishable. */
|
|
3211
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--dirty {
|
|
3212
|
+
position: relative;
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--dirty::before {
|
|
3216
|
+
content: '';
|
|
3217
|
+
position: absolute;
|
|
3218
|
+
top: 0;
|
|
3219
|
+
left: 0;
|
|
3220
|
+
border-width: 5px 5px 0 0;
|
|
3221
|
+
border-style: solid;
|
|
3222
|
+
border-color: var(--dg-primary) transparent transparent transparent;
|
|
3223
|
+
pointer-events: none;
|
|
3224
|
+
}
|
|
3225
|
+
|
|
3226
|
+
/* Marked for deletion, not yet saved (batch mode). Still readable, clearly on
|
|
3227
|
+
its way out, and still right-clickable so the delete can be undone. */
|
|
3228
|
+
.kanuni-datagrid-root .kanuni-datagrid-cell--removed {
|
|
3229
|
+
text-decoration: line-through;
|
|
3230
|
+
opacity: 0.55;
|
|
3231
|
+
background: color-mix(in srgb, var(--dg-danger) 10%, transparent);
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
/* ── The Save / Cancel strip (and the Enterprise filter strip) ── */
|
|
3235
|
+
.kanuni-datagrid-filter-bar {
|
|
3236
|
+
display: flex;
|
|
3237
|
+
align-items: center;
|
|
3238
|
+
gap: 8px;
|
|
3239
|
+
padding: 6px 8px;
|
|
3240
|
+
border: 1px solid var(--dg-border);
|
|
3241
|
+
border-bottom: none;
|
|
3242
|
+
border-radius: var(--dg-radius) var(--dg-radius) 0 0;
|
|
3243
|
+
background: var(--dg-surface-header);
|
|
3244
|
+
font-size: var(--dg-chrome-font-size);
|
|
3245
|
+
}
|
|
3246
|
+
|
|
3247
|
+
.kanuni-datagrid-filter-bar button {
|
|
3248
|
+
padding: 2px 8px;
|
|
3249
|
+
border: 1px solid var(--dg-border-strong);
|
|
3250
|
+
border-radius: var(--dg-radius-control);
|
|
3251
|
+
background: var(--dg-surface);
|
|
3252
|
+
color: inherit;
|
|
3253
|
+
font: inherit;
|
|
3254
|
+
font-size: var(--dg-chrome-font-size);
|
|
3255
|
+
cursor: pointer;
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
.kanuni-datagrid-filter-active {
|
|
3259
|
+
color: var(--dg-primary);
|
|
3260
|
+
font-weight: 600;
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
/* Inside the free grid's root, whose own border is the frame: the strip is
|
|
3264
|
+
a band across the top rather than a tab sitting on the grid. */
|
|
3265
|
+
.kanuni-datagrid-root > .kanuni-datagrid-edit-bar {
|
|
3266
|
+
flex: none;
|
|
3267
|
+
border: 0;
|
|
3268
|
+
border-bottom: 1px solid var(--dg-border);
|
|
3269
|
+
border-radius: 0;
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
/* The filter, in words. Truncated rather than wrapped: the strip is one line
|
|
3273
|
+
tall, and a growing bar would push the grid around as conditions are added.
|
|
3274
|
+
The full sentence is on the element's title. */
|
|
3275
|
+
.kanuni-datagrid-filter-active {
|
|
3276
|
+
overflow: hidden;
|
|
3277
|
+
text-overflow: ellipsis;
|
|
3278
|
+
white-space: nowrap;
|
|
3279
|
+
max-width: min(60ch, 50%);
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
/* ── Row / form / popup editing (G2) ──────────────────────── */
|
|
3283
|
+
/*
|
|
3284
|
+
* One panel, two placements: in the row flow (`form`, the `--inline` variant
|
|
3285
|
+
* below, inside a row slot the virtualizer sized) and in a dialog over the
|
|
3286
|
+
* grid (`popup`).
|
|
3287
|
+
*/
|
|
3288
|
+
.kanuni-datagrid-edit-form {
|
|
3289
|
+
flex: none;
|
|
3290
|
+
display: flex;
|
|
3291
|
+
flex-direction: column;
|
|
3292
|
+
max-height: 60vh;
|
|
3293
|
+
margin-bottom: 8px;
|
|
3294
|
+
border: 1px solid var(--dg-border-strong);
|
|
3295
|
+
border-radius: var(--dg-radius);
|
|
3296
|
+
background: var(--dg-surface);
|
|
3297
|
+
color: var(--dg-text);
|
|
3298
|
+
box-shadow: var(--dg-shadow-panel);
|
|
3299
|
+
font-size: var(--dg-font-size);
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3302
|
+
/* Drawn inside a row slot: the row is already the card, so the panel drops the
|
|
3303
|
+
chrome that exists to lift a FLOATING panel off the page. `max-height: 100%`
|
|
3304
|
+
rather than 60vh — the slot's height is the budget here, and overflowing it
|
|
3305
|
+
would spill over the rows below, which the virtualizer has already placed. */
|
|
3306
|
+
.kanuni-datagrid-edit-form--inline {
|
|
3307
|
+
height: 100%;
|
|
3308
|
+
max-height: 100%;
|
|
3309
|
+
margin-bottom: 0;
|
|
3310
|
+
border: 0;
|
|
3311
|
+
border-radius: 0;
|
|
3312
|
+
box-shadow: none;
|
|
3313
|
+
background: var(--dg-surface-header);
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
.kanuni-datagrid-edit-form-header {
|
|
3317
|
+
padding: 10px 14px;
|
|
3318
|
+
border-bottom: 1px solid var(--dg-border);
|
|
3319
|
+
background: var(--dg-surface-header);
|
|
3320
|
+
border-radius: var(--dg-radius) var(--dg-radius) 0 0;
|
|
3321
|
+
}
|
|
3322
|
+
|
|
3323
|
+
.kanuni-datagrid-edit-form-fields {
|
|
3324
|
+
flex: 1;
|
|
3325
|
+
overflow: auto;
|
|
3326
|
+
display: grid;
|
|
3327
|
+
/* Two columns on a wide grid, one on a narrow one — without a media query,
|
|
3328
|
+
which would key off the VIEWPORT when what matters is the grid's width. */
|
|
3329
|
+
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
|
3330
|
+
gap: 10px 16px;
|
|
3331
|
+
padding: 14px;
|
|
3332
|
+
}
|
|
3333
|
+
|
|
3334
|
+
.kanuni-datagrid-edit-form-field {
|
|
3335
|
+
display: flex;
|
|
3336
|
+
flex-direction: column;
|
|
3337
|
+
gap: 3px;
|
|
3338
|
+
min-width: 0;
|
|
3339
|
+
}
|
|
3340
|
+
|
|
3341
|
+
.kanuni-datagrid-edit-form-label {
|
|
3342
|
+
font-size: 11px;
|
|
3343
|
+
font-weight: 600;
|
|
3344
|
+
opacity: 0.75;
|
|
3345
|
+
}
|
|
3346
|
+
|
|
3347
|
+
.kanuni-datagrid-edit-form-input {
|
|
3348
|
+
width: 100%;
|
|
3349
|
+
min-width: 0;
|
|
3350
|
+
padding: 4px 6px;
|
|
3351
|
+
border: 1px solid var(--dg-border-strong);
|
|
3352
|
+
border-radius: var(--dg-radius-control);
|
|
3353
|
+
background: var(--dg-surface);
|
|
3354
|
+
color: inherit;
|
|
3355
|
+
font: inherit;
|
|
3356
|
+
font-size: var(--dg-font-size);
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
input[type='checkbox'].kanuni-datagrid-edit-form-input {
|
|
3360
|
+
width: auto;
|
|
3361
|
+
accent-color: var(--dg-primary);
|
|
3362
|
+
}
|
|
3363
|
+
|
|
3364
|
+
.kanuni-datagrid-edit-form-input:focus {
|
|
3365
|
+
outline: 2px solid var(--dg-primary);
|
|
3366
|
+
outline-offset: -1px;
|
|
3367
|
+
}
|
|
3368
|
+
|
|
3369
|
+
.kanuni-datagrid-edit-form-field[data-invalid] .kanuni-datagrid-edit-form-input {
|
|
3370
|
+
border-color: var(--dg-danger);
|
|
3371
|
+
}
|
|
3372
|
+
|
|
3373
|
+
.kanuni-datagrid-edit-form-message {
|
|
3374
|
+
color: var(--dg-danger-text);
|
|
3375
|
+
font-size: 11px;
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
/* A rejected save, above the fields — where the eye already is after pressing
|
|
3379
|
+
Save, rather than beside the button that is about to be pressed again. */
|
|
3380
|
+
.kanuni-datagrid-edit-form-error {
|
|
3381
|
+
margin: 10px 14px 0;
|
|
3382
|
+
padding: 6px 10px;
|
|
3383
|
+
border-radius: var(--dg-radius-control);
|
|
3384
|
+
background: color-mix(in srgb, var(--dg-danger) 12%, transparent);
|
|
3385
|
+
color: var(--dg-danger-text);
|
|
3386
|
+
font-size: var(--dg-chrome-font-size);
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3389
|
+
.kanuni-datagrid-edit-form-footer {
|
|
3390
|
+
display: flex;
|
|
3391
|
+
align-items: center;
|
|
3392
|
+
gap: 8px;
|
|
3393
|
+
padding: 10px 14px;
|
|
3394
|
+
border-top: 1px solid var(--dg-border);
|
|
3395
|
+
background: var(--dg-surface-header);
|
|
3396
|
+
border-radius: 0 0 var(--dg-radius) var(--dg-radius);
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
.kanuni-datagrid-edit-form-hint {
|
|
3400
|
+
margin-inline-end: auto;
|
|
3401
|
+
font-size: 11px;
|
|
3402
|
+
opacity: 0.65;
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
.kanuni-datagrid-edit-form-footer button {
|
|
3406
|
+
padding: 4px 12px;
|
|
3407
|
+
border: 1px solid var(--dg-border-strong);
|
|
3408
|
+
border-radius: var(--dg-radius-control);
|
|
3409
|
+
background: var(--dg-surface);
|
|
3410
|
+
color: inherit;
|
|
3411
|
+
font: inherit;
|
|
3412
|
+
font-size: var(--dg-chrome-font-size);
|
|
3413
|
+
cursor: pointer;
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
.kanuni-datagrid-edit-form-footer button:disabled {
|
|
3417
|
+
opacity: 0.55;
|
|
3418
|
+
cursor: default;
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
|
+
.kanuni-datagrid-edit-form-save {
|
|
3422
|
+
border-color: var(--dg-primary) !important;
|
|
3423
|
+
background: var(--dg-primary) !important;
|
|
3424
|
+
color: var(--dg-on-primary) !important;
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3427
|
+
/* ── Popup mode ───────────────────────────────────────────── */
|
|
3428
|
+
.kanuni-datagrid-edit-popup {
|
|
3429
|
+
position: fixed;
|
|
3430
|
+
inset: 0;
|
|
3431
|
+
z-index: 1000;
|
|
3432
|
+
display: flex;
|
|
3433
|
+
align-items: center;
|
|
3434
|
+
justify-content: center;
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3437
|
+
.kanuni-datagrid-edit-popup-overlay {
|
|
3438
|
+
position: absolute;
|
|
3439
|
+
inset: 0;
|
|
3440
|
+
/* Opaque enough to read the form against a dense grid — the see-through
|
|
3441
|
+
overlay was a real bug in PivotGrid's drill-down modal. */
|
|
3442
|
+
background: var(--dg-overlay);
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
.kanuni-datagrid-edit-popup > .kanuni-datagrid-edit-form {
|
|
3446
|
+
position: relative;
|
|
3447
|
+
width: min(720px, 94vw);
|
|
3448
|
+
max-height: 86vh;
|
|
3449
|
+
margin-bottom: 0;
|
|
3450
|
+
box-shadow: var(--dg-shadow-dialog);
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
/* While a row/form/popup session owns the record, the grid behind it must not
|
|
3454
|
+
accept edits: a click that lands on a cell would change a value the user
|
|
3455
|
+
cannot see is changing, in a record they believe is open in the dialog. */
|
|
3456
|
+
/* A modal covers the grid, so nothing under it should react at all. */
|
|
3457
|
+
.kanuni-datagrid-enterprise[data-row-session='popup'] .kanuni-datagrid-scroller,
|
|
3458
|
+
.kanuni-datagrid-root[data-row-session='popup'] .kanuni-datagrid-scroller {
|
|
3459
|
+
pointer-events: none;
|
|
3460
|
+
}
|
|
3461
|
+
|
|
3462
|
+
/* The in-grid form is INSIDE the scroller, so the lock is per row rather than
|
|
3463
|
+
over the whole scroll area. Locking the scroller would take the form's own
|
|
3464
|
+
fields and buttons with it — and the wheel, leaving a form taller than the
|
|
3465
|
+
viewport with a Save nobody could scroll to. */
|
|
3466
|
+
.kanuni-datagrid-enterprise[data-row-session='form']
|
|
3467
|
+
.kanuni-datagrid-row:not(.kanuni-datagrid-editform-row),
|
|
3468
|
+
.kanuni-datagrid-root[data-row-session='form']
|
|
3469
|
+
.kanuni-datagrid-row:not(.kanuni-datagrid-editform-row) {
|
|
3470
|
+
pointer-events: none;
|
|
3471
|
+
}
|
|
3472
|
+
|
|
3473
|
+
/* ─────────────────────────────────────────────────────────────
|
|
3474
|
+
Row save status (`rowStatus`, Community, 2026-10-16).
|
|
3475
|
+
─────────────────────────────────────────────────────────────
|
|
3476
|
+
A customer whose grid saves every edit at once asked to see each row's
|
|
3477
|
+
save: unsaved, in flight, saved, refused. Both renderers put
|
|
3478
|
+
`data-row-status` and `kanuni-datagrid-row--status-<status>` on the ROW
|
|
3479
|
+
element — one element per row, pinned cells included — so the marker is
|
|
3480
|
+
drawn once per row and cannot repeat per pinned block.
|
|
3481
|
+
|
|
3482
|
+
The marker is the row's own `::before`: a sticky flex item at the inline
|
|
3483
|
+
start that gives its width back with a negative margin. Sticky, because
|
|
3484
|
+
the row is as wide as all its columns and scrolls sideways — a plain left
|
|
3485
|
+
border or inset shadow on the row would scroll out of view with the first
|
|
3486
|
+
column, and under a pinned-left column it would be painted over. It sits
|
|
3487
|
+
above pinned cells (z-index) and moves no cell content. `inset-inline-start`
|
|
3488
|
+
puts it on the right edge under `dir="rtl"`. The focused row keeps its own
|
|
3489
|
+
inset bar; at the leading edge the status marker covers it, which is the
|
|
3490
|
+
more urgent of the two. */
|
|
3491
|
+
.kanuni-datagrid-root,
|
|
3492
|
+
.kanuni-datagrid-enterprise,
|
|
3493
|
+
.kanuni-datagrid-detached {
|
|
3494
|
+
--dg-row-status-width: 3px;
|
|
3495
|
+
--dg-row-status-changed: var(--dg-warning);
|
|
3496
|
+
--dg-row-status-saving: var(--dg-primary);
|
|
3497
|
+
/* The success fill: every palette and scheme sets it, dark ones included. */
|
|
3498
|
+
--dg-row-status-saved: var(--dg-success);
|
|
3499
|
+
--dg-row-status-error: var(--dg-danger);
|
|
3500
|
+
/* How strongly `tint: true` washes the row. */
|
|
3501
|
+
--dg-row-status-tint: 8%;
|
|
3502
|
+
}
|
|
3503
|
+
|
|
3504
|
+
.kanuni-datagrid-row--status-changed {
|
|
3505
|
+
--dg-row-status-color: var(--dg-row-status-changed);
|
|
3506
|
+
}
|
|
3507
|
+
|
|
3508
|
+
.kanuni-datagrid-row--status-saving {
|
|
3509
|
+
--dg-row-status-color: var(--dg-row-status-saving);
|
|
3510
|
+
}
|
|
3511
|
+
|
|
3512
|
+
.kanuni-datagrid-row--status-saved {
|
|
3513
|
+
--dg-row-status-color: var(--dg-row-status-saved);
|
|
3514
|
+
}
|
|
3515
|
+
|
|
3516
|
+
.kanuni-datagrid-row--status-error {
|
|
3517
|
+
--dg-row-status-color: var(--dg-row-status-error);
|
|
3518
|
+
}
|
|
3519
|
+
|
|
3520
|
+
.kanuni-datagrid-row[data-row-status]::before {
|
|
3521
|
+
content: '';
|
|
3522
|
+
position: sticky;
|
|
3523
|
+
inset-inline-start: 0;
|
|
3524
|
+
/* Above pinned cells (2), below the row being edited (4): at 6 the next
|
|
3525
|
+
row's marker cut through the editor's error bubble, which hangs one row
|
|
3526
|
+
down (pre-release review, 2026-10-16). */
|
|
3527
|
+
z-index: 3;
|
|
3528
|
+
flex: none;
|
|
3529
|
+
align-self: stretch;
|
|
3530
|
+
width: var(--dg-row-status-width);
|
|
3531
|
+
margin-inline-end: calc(-1 * var(--dg-row-status-width));
|
|
3532
|
+
background: var(--dg-row-status-color);
|
|
3533
|
+
pointer-events: none;
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
/* The tint is a translucent IMAGE over whatever colour the row already has —
|
|
3537
|
+
stripe, hover, selection or focus — so those still read through it. Pinned
|
|
3538
|
+
cells inherit the row's background but the hover rule resets theirs, so
|
|
3539
|
+
they are named here too (three classes + an attribute: above the hover and
|
|
3540
|
+
selection rules, which are two classes). */
|
|
3541
|
+
.kanuni-datagrid-row.kanuni-datagrid-row--status-tint[data-row-status],
|
|
3542
|
+
.kanuni-datagrid-row.kanuni-datagrid-row--status-tint[data-row-status] .kanuni-datagrid-cell--pinned {
|
|
3543
|
+
background-image: linear-gradient(
|
|
3544
|
+
color-mix(in srgb, var(--dg-row-status-color) var(--dg-row-status-tint), transparent),
|
|
3545
|
+
color-mix(in srgb, var(--dg-row-status-color) var(--dg-row-status-tint), transparent)
|
|
3546
|
+
);
|
|
3547
|
+
}
|
|
3548
|
+
|
|
3549
|
+
/* High contrast drops background colours; the marker is the whole signal,
|
|
3550
|
+
so it keeps its own. */
|
|
3551
|
+
@media (forced-colors: active) {
|
|
3552
|
+
.kanuni-datagrid-row[data-row-status]::before {
|
|
3553
|
+
forced-color-adjust: none;
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
/* ── Message rows (`rowStatus.messages`, 2026-10-16) ─────────
|
|
3558
|
+
A refused save's reason in a row under it, with Retry and Delete row. The
|
|
3559
|
+
in-grid edit form's shape: sticky to the scroller's inline start and as wide
|
|
3560
|
+
as the VIEWPORT, so it stays in view while the columns scroll. The ground
|
|
3561
|
+
stays the surface — the text is the danger TEXT colour, measured at 4.5:1
|
|
3562
|
+
on it — and the row's own marker colour runs down its leading edge. */
|
|
3563
|
+
.kanuni-datagrid-message-row {
|
|
3564
|
+
background: var(--dg-surface);
|
|
3565
|
+
border-bottom: 1px solid var(--dg-border);
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
.kanuni-datagrid-message-cell {
|
|
3569
|
+
position: sticky;
|
|
3570
|
+
inset-inline-start: 0;
|
|
3571
|
+
box-sizing: border-box;
|
|
3572
|
+
width: var(--dg-viewport-width, 100%);
|
|
3573
|
+
height: 100%;
|
|
3574
|
+
border-inline-start: var(--dg-row-status-width) solid var(--dg-row-status-error);
|
|
3575
|
+
user-select: text;
|
|
3576
|
+
}
|
|
3577
|
+
|
|
3578
|
+
.kanuni-datagrid-row-message {
|
|
3579
|
+
display: flex;
|
|
3580
|
+
align-items: center;
|
|
3581
|
+
gap: 8px;
|
|
3582
|
+
height: 100%;
|
|
3583
|
+
padding: 0 var(--dg-cell-padding-x);
|
|
3584
|
+
color: var(--dg-danger-text);
|
|
3585
|
+
font-size: var(--dg-chrome-font-size);
|
|
3586
|
+
}
|
|
3587
|
+
|
|
3588
|
+
.kanuni-datagrid-row-message-icon {
|
|
3589
|
+
flex: none;
|
|
3590
|
+
}
|
|
3591
|
+
|
|
3592
|
+
.kanuni-datagrid-row-message-text {
|
|
3593
|
+
flex: 1 1 auto;
|
|
3594
|
+
min-width: 0;
|
|
3595
|
+
overflow: hidden;
|
|
3596
|
+
text-overflow: ellipsis;
|
|
3597
|
+
white-space: nowrap;
|
|
3598
|
+
}
|
|
3599
|
+
|
|
3600
|
+
.kanuni-datagrid-root .kanuni-datagrid-row-message-button {
|
|
3601
|
+
flex: none;
|
|
3602
|
+
height: min(var(--dg-control-height), calc(100% - 6px));
|
|
3603
|
+
padding: 0 8px;
|
|
3604
|
+
border: 1px solid var(--dg-border-strong);
|
|
3605
|
+
border-radius: var(--dg-radius-control);
|
|
3606
|
+
background: var(--dg-surface);
|
|
3607
|
+
color: var(--dg-text);
|
|
3608
|
+
font: inherit;
|
|
3609
|
+
cursor: pointer;
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3612
|
+
.kanuni-datagrid-root .kanuni-datagrid-row-message-button:hover {
|
|
3613
|
+
background: var(--dg-surface-hover);
|
|
3614
|
+
}
|
|
3615
|
+
|
|
3616
|
+
.kanuni-datagrid-root .kanuni-datagrid-row-message-button:focus-visible {
|
|
3617
|
+
outline: 2px solid var(--dg-focus-ring);
|
|
3618
|
+
outline-offset: 1px;
|
|
3619
|
+
}
|
|
3620
|
+
|
|
3621
|
+
/* ── Status column (`rowStatus.icons`, 2026-10-16) ───────────
|
|
3622
|
+
A glyph per status so it does not rest on colour alone: a dot while
|
|
3623
|
+
changed, a turning ring while saving, a tick when saved, a triangle when
|
|
3624
|
+
refused. Drawn as a MASK filled with the status colour, so a palette or a
|
|
3625
|
+
scheme recolours it like the marker. The cell exists on every row (an empty
|
|
3626
|
+
one where there is no status) so the columns beside it never step. */
|
|
3627
|
+
.kanuni-datagrid-status-cell {
|
|
3628
|
+
display: flex;
|
|
3629
|
+
align-items: center;
|
|
3630
|
+
justify-content: center;
|
|
3631
|
+
padding: 0;
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3634
|
+
.kanuni-datagrid-status-icon {
|
|
3635
|
+
display: none;
|
|
3636
|
+
width: 12px;
|
|
3637
|
+
height: 12px;
|
|
3638
|
+
background: var(--dg-row-status-color);
|
|
3639
|
+
-webkit-mask: var(--dg-row-status-glyph) center / contain no-repeat;
|
|
3640
|
+
mask: var(--dg-row-status-glyph) center / contain no-repeat;
|
|
3641
|
+
}
|
|
3642
|
+
|
|
3643
|
+
.kanuni-datagrid-row[data-row-status] .kanuni-datagrid-status-icon {
|
|
3644
|
+
display: block;
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
.kanuni-datagrid-row--status-changed {
|
|
3648
|
+
--dg-row-status-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3.5'/%3E%3C/svg%3E");
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
.kanuni-datagrid-row--status-saving {
|
|
3652
|
+
--dg-row-status-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2a6 6 0 1 1-6 6' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round'/%3E%3C/svg%3E");
|
|
3653
|
+
}
|
|
3654
|
+
|
|
3655
|
+
.kanuni-datagrid-row--status-saved {
|
|
3656
|
+
--dg-row-status-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5 6.5 12.5 13.5 3.5' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3659
|
+
.kanuni-datagrid-row--status-error {
|
|
3660
|
+
--dg-row-status-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1 15.5 14.5H.5z M7 6v4.5h2V6z M7 11.5v2h2v-2z' fill-rule='evenodd'/%3E%3C/svg%3E");
|
|
3661
|
+
}
|
|
3662
|
+
|
|
3663
|
+
.kanuni-datagrid-row--status-saving .kanuni-datagrid-status-icon {
|
|
3664
|
+
animation: kanuni-datagrid-status-spin 0.9s linear infinite;
|
|
3665
|
+
}
|
|
3666
|
+
|
|
3667
|
+
@keyframes kanuni-datagrid-status-spin {
|
|
3668
|
+
to {
|
|
3669
|
+
transform: rotate(360deg);
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3674
|
+
.kanuni-datagrid-row--status-saving .kanuni-datagrid-status-icon {
|
|
3675
|
+
animation: none;
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
|
|
3679
|
+
@media (forced-colors: active) {
|
|
3680
|
+
.kanuni-datagrid-status-icon {
|
|
3681
|
+
background: CanvasText;
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3184
3685
|
/* ─────────────────────────────────────────────────────────────
|
|
3185
3686
|
KANUNILABS DataGrid — packaged themes
|
|
3186
3687
|
─────────────────────────────────────────────────────────────
|
|
@@ -3647,6 +4148,9 @@
|
|
|
3647
4148
|
--dg-danger: #f87171;
|
|
3648
4149
|
--dg-danger-text: #fca5a5;
|
|
3649
4150
|
--dg-on-danger: #450a0a;
|
|
4151
|
+
--dg-success: #4ade80;
|
|
4152
|
+
--dg-success-text: #86efac;
|
|
4153
|
+
--dg-on-success: #0d2817;
|
|
3650
4154
|
--dg-warning: #fbbf24;
|
|
3651
4155
|
--dg-overlay: rgba(12, 10, 9, 0.72);
|
|
3652
4156
|
|
|
@@ -3995,6 +4499,9 @@
|
|
|
3995
4499
|
--dg-danger: #a2515a; /* Aurora nord11, deepened for white text */
|
|
3996
4500
|
--dg-danger-text: #8f4149;
|
|
3997
4501
|
--dg-on-danger: #ffffff;
|
|
4502
|
+
--dg-success: #687a5a;
|
|
4503
|
+
--dg-success-text: #5d6c50;
|
|
4504
|
+
--dg-on-success: #ffffff;
|
|
3998
4505
|
--dg-warning: #8a6220; /* nord13 family */
|
|
3999
4506
|
}
|
|
4000
4507
|
|
|
@@ -4023,6 +4530,9 @@
|
|
|
4023
4530
|
/* nord11 is a muted red, so the label on it has to go further down than the
|
|
4024
4531
|
usual near-black: #2b1113 measured 4.31:1 and this is 5.17:1. */
|
|
4025
4532
|
--dg-on-danger: #170709;
|
|
4533
|
+
--dg-success: #a3be8c;
|
|
4534
|
+
--dg-success-text: #adc599;
|
|
4535
|
+
--dg-on-success: #1d2219;
|
|
4026
4536
|
--dg-warning: #ebcb8b; /* nord13 */
|
|
4027
4537
|
--dg-overlay: rgba(24, 28, 36, 0.72);
|
|
4028
4538
|
}
|
|
@@ -4056,6 +4566,9 @@
|
|
|
4056
4566
|
--dg-danger: #b03a5b; /* Pink #ff79c6 / Red #ff5555 family */
|
|
4057
4567
|
--dg-danger-text: #98304d;
|
|
4058
4568
|
--dg-on-danger: #ffffff;
|
|
4569
|
+
--dg-success: #2a8441;
|
|
4570
|
+
--dg-success-text: #257339;
|
|
4571
|
+
--dg-on-success: #ffffff;
|
|
4059
4572
|
--dg-warning: #8a5a1c;
|
|
4060
4573
|
}
|
|
4061
4574
|
|
|
@@ -4082,6 +4595,9 @@
|
|
|
4082
4595
|
--dg-danger: #ff5555; /* Red */
|
|
4083
4596
|
--dg-danger-text: #ff8a8a;
|
|
4084
4597
|
--dg-on-danger: #3b0000;
|
|
4598
|
+
--dg-success: #50fa7b;
|
|
4599
|
+
--dg-success-text: #50fa7b;
|
|
4600
|
+
--dg-on-success: #0e2d16;
|
|
4085
4601
|
--dg-warning: #f1fa8c; /* Yellow */
|
|
4086
4602
|
--dg-overlay: rgba(18, 19, 26, 0.74);
|
|
4087
4603
|
}
|
|
@@ -4115,6 +4631,9 @@
|
|
|
4115
4631
|
--dg-danger: #b3372c; /* red #dc322f, deepened */
|
|
4116
4632
|
--dg-danger-text: #9c2f25;
|
|
4117
4633
|
--dg-on-danger: #ffffff;
|
|
4634
|
+
--dg-success: #6c7c00;
|
|
4635
|
+
--dg-success-text: #5a6800;
|
|
4636
|
+
--dg-on-success: #ffffff;
|
|
4118
4637
|
--dg-warning: #8a5a00; /* yellow #b58900, deepened */
|
|
4119
4638
|
}
|
|
4120
4639
|
|
|
@@ -4141,6 +4660,9 @@
|
|
|
4141
4660
|
--dg-danger: #e07a72;
|
|
4142
4661
|
--dg-danger-text: #f0a49e;
|
|
4143
4662
|
--dg-on-danger: #34110d;
|
|
4663
|
+
--dg-success: #859900;
|
|
4664
|
+
--dg-success-text: #a4b240;
|
|
4665
|
+
--dg-on-success: #181c00;
|
|
4144
4666
|
--dg-warning: #d5a63b;
|
|
4145
4667
|
--dg-overlay: rgba(0, 20, 26, 0.74);
|
|
4146
4668
|
}
|
|
@@ -4173,6 +4695,9 @@
|
|
|
4173
4695
|
--dg-danger: #9d0006; /* light red */
|
|
4174
4696
|
--dg-danger-text: #9d0006;
|
|
4175
4697
|
--dg-on-danger: #ffffff;
|
|
4698
|
+
--dg-success: #79740e;
|
|
4699
|
+
--dg-success-text: #605c0b;
|
|
4700
|
+
--dg-on-success: #ffffff;
|
|
4176
4701
|
/* The scheme's light yellow (#b57614) is 3.33:1 on this cream ground — the
|
|
4177
4702
|
warmth that makes Gruvbox work is also what makes its yellow weak here.
|
|
4178
4703
|
Same hue, two steps down, 4.72:1. */
|
|
@@ -4202,6 +4727,9 @@
|
|
|
4202
4727
|
--dg-danger: #fb4934; /* dark red */
|
|
4203
4728
|
--dg-danger-text: #fb8b7f;
|
|
4204
4729
|
--dg-on-danger: #2c0500;
|
|
4730
|
+
--dg-success: #b8bb26;
|
|
4731
|
+
--dg-success-text: #bfc23c;
|
|
4732
|
+
--dg-on-success: #212207;
|
|
4205
4733
|
--dg-warning: #fabd2f; /* dark yellow */
|
|
4206
4734
|
--dg-overlay: rgba(20, 20, 20, 0.74);
|
|
4207
4735
|
}
|
|
@@ -4235,6 +4763,9 @@
|
|
|
4235
4763
|
--dg-danger: #c4304a; /* red #d20f39, deepened for white text */
|
|
4236
4764
|
--dg-danger-text: #b02540;
|
|
4237
4765
|
--dg-on-danger: #ffffff;
|
|
4766
|
+
--dg-success: #358524;
|
|
4767
|
+
--dg-success-text: #2d701e;
|
|
4768
|
+
--dg-on-success: #ffffff;
|
|
4238
4769
|
--dg-warning: #995f14; /* peach, deepened */
|
|
4239
4770
|
}
|
|
4240
4771
|
|
|
@@ -4261,6 +4792,9 @@
|
|
|
4261
4792
|
--dg-danger: #f38ba8; /* red */
|
|
4262
4793
|
--dg-danger-text: #f5a3ba;
|
|
4263
4794
|
--dg-on-danger: #3d0b1a;
|
|
4795
|
+
--dg-success: #a6e3a1;
|
|
4796
|
+
--dg-success-text: #a6e3a1;
|
|
4797
|
+
--dg-on-success: #1e291d;
|
|
4264
4798
|
--dg-warning: #fab387; /* peach */
|
|
4265
4799
|
--dg-overlay: rgba(14, 14, 22, 0.74);
|
|
4266
4800
|
}
|
|
@@ -4297,6 +4831,9 @@
|
|
|
4297
4831
|
--dg-danger: #b1364a;
|
|
4298
4832
|
--dg-danger-text: #9d2c3f;
|
|
4299
4833
|
--dg-on-danger: #ffffff;
|
|
4834
|
+
--dg-success: #587539;
|
|
4835
|
+
--dg-success-text: #455b2c;
|
|
4836
|
+
--dg-on-success: #ffffff;
|
|
4300
4837
|
--dg-warning: #8a5a12;
|
|
4301
4838
|
}
|
|
4302
4839
|
|
|
@@ -4323,6 +4860,9 @@
|
|
|
4323
4860
|
--dg-danger: #f7768e; /* red */
|
|
4324
4861
|
--dg-danger-text: #f993a6;
|
|
4325
4862
|
--dg-on-danger: #3a0713;
|
|
4863
|
+
--dg-success: #9ece6a;
|
|
4864
|
+
--dg-success-text: #9ece6a;
|
|
4865
|
+
--dg-on-success: #1c2513;
|
|
4326
4866
|
--dg-warning: #e0af68; /* yellow */
|
|
4327
4867
|
--dg-overlay: rgba(10, 11, 18, 0.76);
|
|
4328
4868
|
}
|