@keenmate/web-grid 1.1.0 → 1.2.0-rc02
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 +20 -15
- package/ai/fill-handle.txt +1 -1
- package/ai/frozen-columns.txt +2 -2
- package/ai/row-locking.txt +1 -1
- package/ai/styling-theming.txt +13 -12
- package/component-variables.manifest.json +8 -7
- package/dist/grid.d.ts +98 -11
- package/dist/logger.d.ts +1 -0
- package/dist/modules/click-events/index.d.ts +5 -1
- package/dist/modules/contextmenu/index.d.ts +10 -1
- package/dist/modules/datepicker/datepicker.d.ts +2 -0
- package/dist/modules/rendering/tree-render.d.ts +8 -0
- package/dist/perf.d.ts +15 -0
- package/dist/types.d.ts +15 -4
- package/dist/web-component.d.ts +31 -3
- package/dist/web-grid.js +3009 -2411
- package/dist/web-grid.umd.js +109 -114
- package/package.json +9 -3
- package/src/css/animations.css +14 -0
- package/src/css/{_cells.css → cells.css} +1 -1
- package/src/css/controls.css +3 -0
- package/src/css/dark-mode.css +67 -0
- package/src/css/{_dialogs.css → dialogs.css} +9 -68
- package/src/css/{_dirty-indicator.css → dirty-indicator.css} +37 -37
- package/src/css/{_dropdown.css → dropdown.css} +1 -1
- package/src/css/{_editors.css → editors.css} +14 -8
- package/src/css/floating.css +71 -0
- package/src/css/{_freeze.css → freeze.css} +5 -5
- package/src/css/{_header.css → header.css} +1 -1
- package/src/css/main.css +53 -48
- package/src/css/{_navigation.css → navigation.css} +10 -5
- package/src/css/{_resize.css → resize.css} +1 -1
- package/src/css/{_selection.css → selection.css} +1 -1
- package/src/css/{_shortcuts.css → shortcuts.css} +4 -4
- package/src/css/{_modifiers.css → states.css} +8 -2
- package/src/css/tree.css +71 -0
- package/src/css/{_variables.css → variables.css} +55 -42
- package/src/css/_dark-mode.css +0 -93
- package/src/css/_tree.css +0 -73
- /package/src/css/{_cell-selection.css → cell-selection.css} +0 -0
- /package/src/css/{_fill-handle.css → fill-handle.css} +0 -0
- /package/src/css/{_pagination.css → pagination.css} +0 -0
- /package/src/css/{_reorder.css → reorder.css} +0 -0
- /package/src/css/{_row-locking.css → row-locking.css} +0 -0
- /package/src/css/{_table.css → table.css} +0 -0
- /package/src/css/{_toolbar.css → toolbar.css} +0 -0
- /package/src/css/{_virtual-scroll.css → virtual-scroll.css} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keenmate/web-grid",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0-rc02",
|
|
4
4
|
"description": "Framework-agnostic data grid web component with sorting, filtering, inline editing, and keyboard navigation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/web-grid.umd.js",
|
|
@@ -36,7 +36,10 @@
|
|
|
36
36
|
"build:types": "tsc",
|
|
37
37
|
"preview": "vite preview",
|
|
38
38
|
"clean": "rimraf dist --glob \"*.tgz\"",
|
|
39
|
-
"clean:dist": "rimraf dist"
|
|
39
|
+
"clean:dist": "rimraf dist",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"test:watch": "vitest",
|
|
42
|
+
"test:ui": "vitest --ui"
|
|
40
43
|
},
|
|
41
44
|
"keywords": [
|
|
42
45
|
"grid",
|
|
@@ -69,9 +72,12 @@
|
|
|
69
72
|
},
|
|
70
73
|
"homepage": "https://github.com/KeenMate/web-grid#readme",
|
|
71
74
|
"devDependencies": {
|
|
75
|
+
"@vitest/ui": "^2.1.0",
|
|
76
|
+
"happy-dom": "^15.0.0",
|
|
72
77
|
"rimraf": "^5.0.5",
|
|
73
78
|
"typescript": "^5.3.3",
|
|
74
|
-
"vite": "^5.0.8"
|
|
79
|
+
"vite": "^5.0.8",
|
|
80
|
+
"vitest": "^2.1.0"
|
|
75
81
|
},
|
|
76
82
|
"dependencies": {
|
|
77
83
|
"@floating-ui/dom": "^1.7.4"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* ==============================================================================
|
|
2
|
+
ANIMATIONS — Tier-2 canonical concern
|
|
3
|
+
==============================================================================
|
|
4
|
+
@keyframes declarations only. Inline transition: rules live next to the
|
|
5
|
+
property they animate (tree chevron rotation in tree.css, tooltip fade in
|
|
6
|
+
floating.css).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* Loading indicator pulse — used on autocomplete/combobox editors while
|
|
10
|
+
options are being fetched. */
|
|
11
|
+
@keyframes wg-pulse {
|
|
12
|
+
0%, 100% { opacity: 1; }
|
|
13
|
+
50% { opacity: 0.4; }
|
|
14
|
+
}
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
============================================================================== */
|
|
74
74
|
.wg__cell--editing {
|
|
75
75
|
position: relative;
|
|
76
|
-
background: var(--wg-
|
|
76
|
+
background: var(--wg-main-bg);
|
|
77
77
|
outline: 2px solid var(--wg-accent-color);
|
|
78
78
|
outline-offset: -2px;
|
|
79
79
|
z-index: var(--wg-z-cell-highlight); /* Paint above neighboring cells so outline isn't hidden */
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/* ==============================================================================
|
|
2
|
+
DARK MODE — framework class + per-instance signal handling
|
|
3
|
+
==============================================================================
|
|
4
|
+
Sets `color-scheme` on the host when the consumer signals dark/light via a
|
|
5
|
+
framework class (signal #4) or a per-instance attribute (signal #5). Every
|
|
6
|
+
`--wg-*` color in variables.css resolves through `light-dark(<light>, <dark>)`,
|
|
7
|
+
so flipping `color-scheme` on the host picks the correct branch without us
|
|
8
|
+
touching any `--base-*` value.
|
|
9
|
+
|
|
10
|
+
Why we don't override `--base-*` or `--wg-*` here:
|
|
11
|
+
Setting e.g. `--wg-main-bg: #1f1f1f` on `:host` would shadow the consumer's
|
|
12
|
+
`:root { --base-main-bg: ... }` for resolution inside the shadow root, so
|
|
13
|
+
their themed value (e.g. pure-admin's dark theme) would be silently replaced
|
|
14
|
+
by our hardcoded default. Setting `color-scheme` instead leaves the
|
|
15
|
+
consumer's `--base-*` chain intact — they remain the source of truth, and
|
|
16
|
+
we only pick the dark branch of our own `light-dark()` fallbacks.
|
|
17
|
+
|
|
18
|
+
Why `color-scheme` on `:host` is fine *here* (but not in variables.css):
|
|
19
|
+
variables.css avoids it because an unconditional declaration would override
|
|
20
|
+
whatever the consumer's <html>/<body>/ancestor set. Here we declare it only
|
|
21
|
+
when the consumer's own signal matches, so we're amplifying their intent
|
|
22
|
+
rather than fighting it. Frameworks that already set `color-scheme`
|
|
23
|
+
alongside their class (Bootstrap 5.3+) get a redundant no-op; frameworks
|
|
24
|
+
that don't (Tailwind `.dark`, hand-rolled toggles) get filled in.
|
|
25
|
+
|
|
26
|
+
OS preference (signal #1) is intentionally not handled here. To opt into
|
|
27
|
+
"follow OS", the consumer sets `color-scheme: light dark` on <html> (or any
|
|
28
|
+
ancestor) — inheritance propagates into the shadow root and `light-dark()`
|
|
29
|
+
resolves automatically. Forcing an `@media (prefers-color-scheme: dark)`
|
|
30
|
+
block here would override consumers that explicitly want their app pinned
|
|
31
|
+
to one mode.
|
|
32
|
+
|
|
33
|
+
Signals handled:
|
|
34
|
+
#4 Framework theme class on an ancestor — `:host-context([data-theme="dark"])`,
|
|
35
|
+
`:host-context([data-bs-theme="dark"])`, `:host-context(.dark)`.
|
|
36
|
+
#5 Per-instance attribute on the host — `:host([data-theme="dark"])`,
|
|
37
|
+
`:host([data-theme="light"])`. Highest specificity, wins over any
|
|
38
|
+
framework class on an ancestor.
|
|
39
|
+
|
|
40
|
+
See BlissFramework/guidelines/web-components/color-scheme.md for the full pattern. */
|
|
41
|
+
|
|
42
|
+
/* DARK — framework class on ancestor (signal #4) */
|
|
43
|
+
:host-context([data-theme="dark"]),
|
|
44
|
+
:host-context([data-bs-theme="dark"]),
|
|
45
|
+
:host-context(.dark) {
|
|
46
|
+
color-scheme: dark;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* LIGHT — framework class on ancestor (signal #4, safety net for
|
|
50
|
+
"force one section back to light on a dark page"). */
|
|
51
|
+
:host-context([data-theme="light"]),
|
|
52
|
+
:host-context([data-bs-theme="light"]),
|
|
53
|
+
:host-context(.light) {
|
|
54
|
+
color-scheme: light;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* DARK — per-instance attribute on the host (signal #5). */
|
|
58
|
+
:host([data-theme="dark"]),
|
|
59
|
+
:host([data-bs-theme="dark"]) {
|
|
60
|
+
color-scheme: dark;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* LIGHT — per-instance attribute on the host (signal #5). */
|
|
64
|
+
:host([data-theme="light"]),
|
|
65
|
+
:host([data-bs-theme="light"]) {
|
|
66
|
+
color-scheme: light;
|
|
67
|
+
}
|
|
@@ -1,70 +1,11 @@
|
|
|
1
|
-
/* ==============================================================================
|
|
2
|
-
TOOLTIP (Floating UI positioned)
|
|
3
|
-
============================================================================== */
|
|
4
|
-
.wg__tooltip {
|
|
5
|
-
position: absolute;
|
|
6
|
-
z-index: var(--wg-z-tooltip);
|
|
7
|
-
max-width: var(--wg-tooltip-max-width);
|
|
8
|
-
padding: var(--wg-tooltip-padding);
|
|
9
|
-
background: var(--wg-tooltip-bg);
|
|
10
|
-
color: var(--wg-tooltip-color);
|
|
11
|
-
font-size: var(--wg-font-size-sm);
|
|
12
|
-
line-height: 1.4;
|
|
13
|
-
border-radius: var(--wg-border-radius-sm);
|
|
14
|
-
box-shadow: var(--wg-tooltip-shadow);
|
|
15
|
-
pointer-events: none;
|
|
16
|
-
opacity: 0;
|
|
17
|
-
transition: opacity var(--wg-transition-fast);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.wg__tooltip--visible {
|
|
21
|
-
opacity: 1;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.wg__tooltip-arrow {
|
|
25
|
-
position: absolute;
|
|
26
|
-
width: var(--wg-tooltip-arrow-size);
|
|
27
|
-
height: var(--wg-tooltip-arrow-size);
|
|
28
|
-
background: var(--wg-tooltip-bg);
|
|
29
|
-
transform: rotate(45deg);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/* Arrow positioning based on tooltip placement */
|
|
33
|
-
.wg__tooltip[data-placement^="top"] .wg__tooltip-arrow {
|
|
34
|
-
bottom: calc(-0.5 * var(--wg-tooltip-arrow-size));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.wg__tooltip[data-placement^="bottom"] .wg__tooltip-arrow {
|
|
38
|
-
top: calc(-0.5 * var(--wg-tooltip-arrow-size));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.wg__tooltip[data-placement^="left"] .wg__tooltip-arrow {
|
|
42
|
-
right: calc(-0.5 * var(--wg-tooltip-arrow-size));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.wg__tooltip[data-placement^="right"] .wg__tooltip-arrow {
|
|
46
|
-
left: calc(-0.5 * var(--wg-tooltip-arrow-size));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/* Rich tooltip content */
|
|
50
|
-
.wg__tooltip-title {
|
|
51
|
-
font-weight: 600;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.wg__tooltip-desc {
|
|
55
|
-
opacity: 0.85;
|
|
56
|
-
margin-top: 2px;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.wg__tooltip-shortcut {
|
|
60
|
-
margin-top: 4px;
|
|
61
|
-
opacity: 0.7;
|
|
62
|
-
font-size: 0.9em;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
1
|
/* ==============================================================================
|
|
66
2
|
GO TO ROW DIALOG (Ctrl+G)
|
|
67
|
-
==============================================================================
|
|
3
|
+
==============================================================================
|
|
4
|
+
Modal dialog for jumping to a specific row by number. Triggered by Ctrl+G
|
|
5
|
+
keyboard shortcut. Tooltip styling moved to floating.css; this file owns
|
|
6
|
+
the go-to dialog only.
|
|
7
|
+
*/
|
|
8
|
+
|
|
68
9
|
.wg__goto-overlay {
|
|
69
10
|
position: fixed;
|
|
70
11
|
inset: 0;
|
|
@@ -76,7 +17,7 @@
|
|
|
76
17
|
}
|
|
77
18
|
|
|
78
19
|
.wg__goto-dialog {
|
|
79
|
-
background: var(--wg-
|
|
20
|
+
background: var(--wg-main-bg);
|
|
80
21
|
border-radius: var(--wg-border-radius-md);
|
|
81
22
|
padding: var(--wg-spacing-lg);
|
|
82
23
|
box-shadow: var(--wg-dialog-shadow);
|
|
@@ -120,12 +61,12 @@
|
|
|
120
61
|
font-family: inherit; /* Form elements don't inherit font by default */
|
|
121
62
|
font-size: var(--wg-font-size-sm);
|
|
122
63
|
cursor: pointer;
|
|
123
|
-
background: var(--wg-
|
|
64
|
+
background: var(--wg-main-bg);
|
|
124
65
|
color: var(--wg-text-color-1);
|
|
125
66
|
}
|
|
126
67
|
|
|
127
68
|
.wg__goto-btn:hover {
|
|
128
|
-
background: var(--wg-
|
|
69
|
+
background: var(--wg-elevated-bg);
|
|
129
70
|
}
|
|
130
71
|
|
|
131
72
|
.wg__goto-btn--go {
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
/* ==============================================================================
|
|
2
|
-
DIRTY INDICATOR (Unsaved Changes)
|
|
3
|
-
==============================================================================
|
|
4
|
-
Shows a small triangle in the top-left corner of cells that have been edited
|
|
5
|
-
but not yet saved/committed to the original data.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/* Dirty cell - subtle background tint */
|
|
9
|
-
.wg__cell--dirty {
|
|
10
|
-
background: var(--wg-dirty-cell-bg) !important;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/* Dirty cell - small corner triangle via ::before */
|
|
14
|
-
.wg__cell--dirty::before {
|
|
15
|
-
content: "";
|
|
16
|
-
position: absolute;
|
|
17
|
-
top: 0;
|
|
18
|
-
left: 0;
|
|
19
|
-
width: 0;
|
|
20
|
-
height: 0;
|
|
21
|
-
border-style: solid;
|
|
22
|
-
border-width: var(--wg-dirty-indicator-size) var(--wg-dirty-indicator-size) 0 0;
|
|
23
|
-
border-color: var(--wg-dirty-indicator-color) transparent transparent transparent;
|
|
24
|
-
pointer-events: none;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/* Don't show dirty indicator when cell is being actively edited */
|
|
28
|
-
.wg__cell--dirty.wg__cell--editing::before {
|
|
29
|
-
display: none;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/* Row number dirty indicator - left border accent */
|
|
33
|
-
.wg__row-number--dirty {
|
|
34
|
-
box-shadow:
|
|
35
|
-
inset 3px 0 0 var(--wg-dirty-row-number-border-color),
|
|
36
|
-
inset calc(-1 * var(--wg-cell-splitter-width)) 0 0 var(--wg-cell-splitter-color);
|
|
37
|
-
}
|
|
1
|
+
/* ==============================================================================
|
|
2
|
+
DIRTY INDICATOR (Unsaved Changes)
|
|
3
|
+
==============================================================================
|
|
4
|
+
Shows a small triangle in the top-left corner of cells that have been edited
|
|
5
|
+
but not yet saved/committed to the original data.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/* Dirty cell - subtle background tint */
|
|
9
|
+
.wg__cell--dirty {
|
|
10
|
+
background: var(--wg-dirty-cell-bg) !important;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Dirty cell - small corner triangle via ::before */
|
|
14
|
+
.wg__cell--dirty::before {
|
|
15
|
+
content: "";
|
|
16
|
+
position: absolute;
|
|
17
|
+
top: 0;
|
|
18
|
+
left: 0;
|
|
19
|
+
width: 0;
|
|
20
|
+
height: 0;
|
|
21
|
+
border-style: solid;
|
|
22
|
+
border-width: var(--wg-dirty-indicator-size) var(--wg-dirty-indicator-size) 0 0;
|
|
23
|
+
border-color: var(--wg-dirty-indicator-color) transparent transparent transparent;
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Don't show dirty indicator when cell is being actively edited */
|
|
28
|
+
.wg__cell--dirty.wg__cell--editing::before {
|
|
29
|
+
display: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Row number dirty indicator - left border accent */
|
|
33
|
+
.wg__row-number--dirty {
|
|
34
|
+
box-shadow:
|
|
35
|
+
inset 3px 0 0 var(--wg-dirty-row-number-border-color),
|
|
36
|
+
inset calc(-1 * var(--wg-cell-splitter-width)) 0 0 var(--wg-cell-splitter-color);
|
|
37
|
+
}
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
DROPDOWN MENU
|
|
126
126
|
============================================================================== */
|
|
127
127
|
.wg__dropdown {
|
|
128
|
-
background: var(--wg-
|
|
128
|
+
background: var(--wg-dropdown-bg);
|
|
129
129
|
border: 1px solid var(--wg-border-color);
|
|
130
130
|
border-radius: var(--wg-border-radius-sm);
|
|
131
131
|
box-shadow: var(--wg-toolbar-shadow);
|
|
@@ -26,6 +26,10 @@
|
|
|
26
26
|
box-shadow: none;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/* ==============================================================================
|
|
30
|
+
TEXT / NUMBER EDITORS
|
|
31
|
+
============================================================================== */
|
|
32
|
+
|
|
29
33
|
/* Text Editor */
|
|
30
34
|
.wg__editor--text {
|
|
31
35
|
text-align: inherit;
|
|
@@ -52,7 +56,9 @@
|
|
|
52
56
|
bottom: 0;
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
/*
|
|
59
|
+
/* ==============================================================================
|
|
60
|
+
DATE EDITOR
|
|
61
|
+
============================================================================== */
|
|
56
62
|
.wg__editor--date {
|
|
57
63
|
position: absolute;
|
|
58
64
|
inset: 0;
|
|
@@ -94,7 +100,9 @@
|
|
|
94
100
|
background: var(--wg-hover-bg);
|
|
95
101
|
}
|
|
96
102
|
|
|
97
|
-
/*
|
|
103
|
+
/* ==============================================================================
|
|
104
|
+
CHECKBOX EDITOR
|
|
105
|
+
============================================================================== */
|
|
98
106
|
.wg__editor--checkbox {
|
|
99
107
|
position: absolute;
|
|
100
108
|
top: 50%;
|
|
@@ -127,7 +135,9 @@
|
|
|
127
135
|
opacity: 0.5;
|
|
128
136
|
}
|
|
129
137
|
|
|
130
|
-
/*
|
|
138
|
+
/* ==============================================================================
|
|
139
|
+
CUSTOM EDITOR
|
|
140
|
+
============================================================================== */
|
|
131
141
|
.wg__editor--custom {
|
|
132
142
|
position: absolute;
|
|
133
143
|
inset: 0;
|
|
@@ -220,9 +230,5 @@
|
|
|
220
230
|
transform: translateY(-50%);
|
|
221
231
|
font-size: var(--wg-font-size-sm);
|
|
222
232
|
animation: wg-pulse 1s infinite;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
@keyframes wg-pulse {
|
|
226
|
-
0%, 100% { opacity: 1; }
|
|
227
|
-
50% { opacity: 0.4; }
|
|
233
|
+
/* @keyframes wg-pulse defined in animations.css */
|
|
228
234
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/* ==============================================================================
|
|
2
|
+
FLOATING UI — Tier-2 canonical concern
|
|
3
|
+
==============================================================================
|
|
4
|
+
Anchored panels positioned by Floating UI. Generic floating chrome only —
|
|
5
|
+
feature-specific floating panels (dropdown editor menu, row toolbar,
|
|
6
|
+
context menu, datepicker) live in their feature files.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* ==============================================================================
|
|
10
|
+
TOOLTIP (Floating UI positioned)
|
|
11
|
+
============================================================================== */
|
|
12
|
+
.wg__tooltip {
|
|
13
|
+
position: absolute;
|
|
14
|
+
z-index: var(--wg-z-tooltip);
|
|
15
|
+
max-width: var(--wg-tooltip-max-width);
|
|
16
|
+
padding: var(--wg-tooltip-padding);
|
|
17
|
+
background: var(--wg-tooltip-bg);
|
|
18
|
+
color: var(--wg-tooltip-color);
|
|
19
|
+
font-size: var(--wg-font-size-sm);
|
|
20
|
+
line-height: 1.4;
|
|
21
|
+
border-radius: var(--wg-border-radius-sm);
|
|
22
|
+
box-shadow: var(--wg-tooltip-shadow);
|
|
23
|
+
pointer-events: none;
|
|
24
|
+
opacity: 0;
|
|
25
|
+
transition: opacity var(--wg-transition-fast);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.wg__tooltip--visible {
|
|
29
|
+
opacity: 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.wg__tooltip-arrow {
|
|
33
|
+
position: absolute;
|
|
34
|
+
width: var(--wg-tooltip-arrow-size);
|
|
35
|
+
height: var(--wg-tooltip-arrow-size);
|
|
36
|
+
background: var(--wg-tooltip-bg);
|
|
37
|
+
transform: rotate(45deg);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Arrow positioning based on tooltip placement */
|
|
41
|
+
.wg__tooltip[data-placement^="top"] .wg__tooltip-arrow {
|
|
42
|
+
bottom: calc(-0.5 * var(--wg-tooltip-arrow-size));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.wg__tooltip[data-placement^="bottom"] .wg__tooltip-arrow {
|
|
46
|
+
top: calc(-0.5 * var(--wg-tooltip-arrow-size));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.wg__tooltip[data-placement^="left"] .wg__tooltip-arrow {
|
|
50
|
+
right: calc(-0.5 * var(--wg-tooltip-arrow-size));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.wg__tooltip[data-placement^="right"] .wg__tooltip-arrow {
|
|
54
|
+
left: calc(-0.5 * var(--wg-tooltip-arrow-size));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Rich tooltip content */
|
|
58
|
+
.wg__tooltip-title {
|
|
59
|
+
font-weight: 600;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.wg__tooltip-desc {
|
|
63
|
+
opacity: 0.85;
|
|
64
|
+
margin-top: 2px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.wg__tooltip-shortcut {
|
|
68
|
+
margin-top: 4px;
|
|
69
|
+
opacity: 0.7;
|
|
70
|
+
font-size: 0.9em;
|
|
71
|
+
}
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
========================================================================== */
|
|
31
31
|
|
|
32
32
|
.wg__cell--frozen {
|
|
33
|
-
background: var(--wg-frozen-column-bg, var(--wg-
|
|
33
|
+
background: var(--wg-frozen-column-bg, var(--wg-main-bg));
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/* Only the last frozen cell gets the separator border */
|
|
@@ -74,12 +74,12 @@
|
|
|
74
74
|
non-frozen content show through when it scrolls behind sticky columns.
|
|
75
75
|
Mix against the opaque frozen column base instead. */
|
|
76
76
|
.wg__row--focused > .wg__cell--frozen {
|
|
77
|
-
background: color-mix(in srgb, var(--wg-accent-color) 10%, var(--wg-frozen-column-bg, var(--wg-
|
|
77
|
+
background: color-mix(in srgb, var(--wg-accent-color) 10%, var(--wg-frozen-column-bg, var(--wg-main-bg))) !important;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/* Row selection on frozen cells */
|
|
81
81
|
.wg__row--selected > .wg__cell--frozen {
|
|
82
|
-
background: color-mix(in srgb, var(--wg-accent-color) 15%, var(--wg-frozen-column-bg, var(--wg-
|
|
82
|
+
background: color-mix(in srgb, var(--wg-accent-color) 15%, var(--wg-frozen-column-bg, var(--wg-main-bg))) !important;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/* Row number cells in selected rows - accent color (override above rule) */
|
|
@@ -90,12 +90,12 @@
|
|
|
90
90
|
|
|
91
91
|
/* Column selection on frozen cells */
|
|
92
92
|
.wg__cell--frozen.wg__cell--column-selected {
|
|
93
|
-
background: color-mix(in srgb, var(--wg-accent-color) 15%, var(--wg-frozen-column-bg, var(--wg-
|
|
93
|
+
background: color-mix(in srgb, var(--wg-accent-color) 15%, var(--wg-frozen-column-bg, var(--wg-main-bg))) !important;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/* Cell range selection on frozen cells */
|
|
97
97
|
.wg__cell--frozen.wg__cell--in-range {
|
|
98
|
-
background: color-mix(in srgb, var(--wg-accent-color) 10%, var(--wg-frozen-column-bg, var(--wg-
|
|
98
|
+
background: color-mix(in srgb, var(--wg-accent-color) 10%, var(--wg-frozen-column-bg, var(--wg-main-bg))) !important;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/* ==========================================================================
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
padding: var(--wg-filter-input-padding);
|
|
155
155
|
border: var(--wg-filter-input-border);
|
|
156
156
|
border-radius: var(--wg-filter-input-border-radius);
|
|
157
|
-
background: var(--wg-
|
|
157
|
+
background: var(--wg-main-bg);
|
|
158
158
|
color: var(--wg-text-color-1);
|
|
159
159
|
font-family: inherit; /* Form elements don't inherit font by default */
|
|
160
160
|
font-size: var(--wg-filter-input-font-size);
|
package/src/css/main.css
CHANGED
|
@@ -1,52 +1,57 @@
|
|
|
1
1
|
/* ==============================================================================
|
|
2
|
-
|
|
2
|
+
@keenmate/web-grid — MAIN ENTRY POINT
|
|
3
3
|
==============================================================================
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- _cells.css : Cells, editable states, editing, validation
|
|
17
|
-
- _editors.css : All editor types (text, number, date, combobox, etc)
|
|
18
|
-
- _dropdown.css : Dropdown menus, select triggers
|
|
19
|
-
- _navigation.css : Keyboard navigation, focus states
|
|
20
|
-
- _pagination.css : Pagination controls, summary, footer
|
|
21
|
-
- _toolbar.css : Row toolbar styles
|
|
22
|
-
- _shortcuts.css : Keyboard shortcuts help icon and overlay
|
|
23
|
-
- _modifiers.css : Striped rows, hover effects, empty state
|
|
24
|
-
- _dialogs.css : Tooltips, go-to dialog
|
|
25
|
-
- _virtual-scroll.css : Virtual scroll support
|
|
26
|
-
- _dark-mode.css : Dark mode overrides
|
|
4
|
+
Cascade layer order (later = higher priority):
|
|
5
|
+
variables — :host { --wg-* } declarations
|
|
6
|
+
component — base + feature rules
|
|
7
|
+
overrides — dark mode, framework themes, per-instance overrides
|
|
8
|
+
|
|
9
|
+
Consumer override contract:
|
|
10
|
+
- Any unlayered consumer rule beats every rule below.
|
|
11
|
+
- Any :root --base-* declaration beats the variables layer.
|
|
12
|
+
|
|
13
|
+
BEM convention used throughout:
|
|
14
|
+
.wg__<element> — element
|
|
15
|
+
.wg__<element>--<modifier> — state modifier
|
|
27
16
|
*/
|
|
28
17
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@import '
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@import '
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@import '
|
|
39
|
-
@import '
|
|
40
|
-
@import '
|
|
41
|
-
@import '
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@import '
|
|
48
|
-
@import '
|
|
49
|
-
@import '
|
|
50
|
-
@import '
|
|
51
|
-
@import '
|
|
52
|
-
@import '
|
|
18
|
+
@layer variables, component, overrides;
|
|
19
|
+
|
|
20
|
+
/* === VARIABLES === */
|
|
21
|
+
@import './variables.css' layer(variables);
|
|
22
|
+
|
|
23
|
+
/* === BASE === */
|
|
24
|
+
@import './table.css' layer(component);
|
|
25
|
+
|
|
26
|
+
/* === CANONICAL CONCERNS (Tier 2) === */
|
|
27
|
+
@import './controls.css' layer(component);
|
|
28
|
+
@import './floating.css' layer(component);
|
|
29
|
+
@import './states.css' layer(component);
|
|
30
|
+
@import './animations.css' layer(component);
|
|
31
|
+
|
|
32
|
+
/* === COMPONENT-SPECIFIC FEATURES (Tier 3) ===
|
|
33
|
+
Ordered by dependency: header before resize/reorder (positioning); cells
|
|
34
|
+
before navigation (navigate-mode rules need to beat read-only cell rules);
|
|
35
|
+
editors/dropdown after cells (edit-state styling overrides). */
|
|
36
|
+
@import './header.css' layer(component);
|
|
37
|
+
@import './resize.css' layer(component);
|
|
38
|
+
@import './reorder.css' layer(component);
|
|
39
|
+
@import './fill-handle.css' layer(component);
|
|
40
|
+
@import './selection.css' layer(component);
|
|
41
|
+
@import './cell-selection.css' layer(component);
|
|
42
|
+
@import './freeze.css' layer(component);
|
|
43
|
+
@import './cells.css' layer(component);
|
|
44
|
+
@import './row-locking.css' layer(component);
|
|
45
|
+
@import './dirty-indicator.css' layer(component);
|
|
46
|
+
@import './editors.css' layer(component);
|
|
47
|
+
@import './dropdown.css' layer(component);
|
|
48
|
+
@import './navigation.css' layer(component);
|
|
49
|
+
@import './pagination.css' layer(component);
|
|
50
|
+
@import './toolbar.css' layer(component);
|
|
51
|
+
@import './shortcuts.css' layer(component);
|
|
52
|
+
@import './dialogs.css' layer(component);
|
|
53
|
+
@import './virtual-scroll.css' layer(component);
|
|
54
|
+
@import './tree.css' layer(component);
|
|
55
|
+
|
|
56
|
+
/* === OVERRIDES === */
|
|
57
|
+
@import './dark-mode.css' layer(overrides);
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
/* Replace browser default focus outline with box-shadow on all cells.
|
|
12
12
|
Outline ignores z-index stacking and bleeds over frozen columns.
|
|
13
13
|
Box-shadow respects stacking contexts so frozen columns properly cover it.
|
|
14
|
-
Combines with the cell splitter shadow (from
|
|
14
|
+
Combines with the cell splitter shadow (from cells.css) to keep the right-edge separator. */
|
|
15
15
|
.wg__cell:focus {
|
|
16
16
|
outline: none;
|
|
17
17
|
box-shadow:
|
|
@@ -19,8 +19,13 @@
|
|
|
19
19
|
inset calc(-1 * var(--wg-cell-splitter-width)) 0 0 var(--wg-cell-splitter-color);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/* Focused cell styling
|
|
23
|
-
|
|
22
|
+
/* Focused cell styling (.wg__cell--focused class).
|
|
23
|
+
Applies whenever focusedCell state is set, in any grid mode. Read-only grids
|
|
24
|
+
(default editTrigger, isEditable: false) still set focusedCell on click via
|
|
25
|
+
the cell-selection module; the indicator needs to be visible there too,
|
|
26
|
+
otherwise tree-shortcut Ctrl+Arrows look like they're losing focus after a
|
|
27
|
+
re-render destroys/rebuilds the tbody. */
|
|
28
|
+
.wg__cell.wg__cell--focused {
|
|
24
29
|
box-shadow:
|
|
25
30
|
inset 0 0 0 var(--wg-focus-border-width) var(--wg-focus-border-color),
|
|
26
31
|
inset calc(-1 * var(--wg-cell-splitter-width)) 0 0 var(--wg-cell-splitter-color);
|
|
@@ -43,7 +48,7 @@
|
|
|
43
48
|
/* ==============================================================================
|
|
44
49
|
ROW FOCUS (master/detail patterns)
|
|
45
50
|
==============================================================================
|
|
46
|
-
Must be in this file (after
|
|
51
|
+
Must be in this file (after cells.css) so source order beats the
|
|
47
52
|
.wg--editable.wg--navigate-mode .wg__cell:not(.wg__cell--editable) readonly rule.
|
|
48
53
|
*/
|
|
49
54
|
.wg__row--focused > .wg__cell {
|
|
@@ -54,7 +59,7 @@
|
|
|
54
59
|
background: var(--wg-row-focus-row-number-bg);
|
|
55
60
|
}
|
|
56
61
|
|
|
57
|
-
/* Navigate mode: override read-only cell background (needs higher specificity than
|
|
62
|
+
/* Navigate mode: override read-only cell background (needs higher specificity than cells.css rule) */
|
|
58
63
|
.wg--editable.wg--navigate-mode .wg__row--focused > .wg__cell {
|
|
59
64
|
background: var(--wg-row-focus-bg);
|
|
60
65
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Resize handles for column width adjustment
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
/* Note: .wg__header has position: sticky in
|
|
7
|
+
/* Note: .wg__header has position: sticky in header.css, which also
|
|
8
8
|
creates a containing block for absolutely positioned children.
|
|
9
9
|
Do NOT add position: relative here - it would break sticky headers! */
|
|
10
10
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/* Selected row number cell - accent colored
|
|
12
|
-
Needs .wg--editable prefix to beat the readonly rule in
|
|
12
|
+
Needs .wg--editable prefix to beat the readonly rule in cells.css
|
|
13
13
|
(.wg--editable.wg--navigate-mode .wg__cell:not(.wg__cell--editable)) which has specificity 0,4,0 */
|
|
14
14
|
.wg__row--selected > .wg__cell.wg__row-number,
|
|
15
15
|
.wg--editable.wg--navigate-mode .wg__row--selected > .wg__cell.wg__row-number {
|