@perspective-dev/viewer-datagrid 4.3.0 → 4.4.1
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/cdn/perspective-viewer-datagrid.js +4 -22
- package/dist/cdn/perspective-viewer-datagrid.js.map +4 -4
- package/dist/css/perspective-viewer-datagrid-toolbar.css +1 -1
- package/dist/css/perspective-viewer-datagrid.css +1 -1
- package/dist/esm/color_utils.d.ts +22 -0
- package/dist/esm/custom_elements/datagrid.d.ts +5 -5
- package/dist/esm/data_listener/format_cell.d.ts +1 -1
- package/dist/esm/data_listener/formatter_cache.d.ts +1 -1
- package/dist/esm/data_listener/index.d.ts +3 -2
- package/dist/esm/event_handlers/click/edit_click.d.ts +3 -2
- package/dist/esm/event_handlers/click.d.ts +4 -6
- package/dist/esm/event_handlers/dispatch_click.d.ts +3 -2
- package/dist/esm/event_handlers/expand_collapse.d.ts +1 -1
- package/dist/esm/event_handlers/focus.d.ts +4 -5
- package/dist/esm/event_handlers/header_click.d.ts +5 -3
- package/dist/esm/event_handlers/keydown/edit_keydown.d.ts +3 -4
- package/dist/esm/event_handlers/select_region.d.ts +3 -1
- package/dist/esm/event_handlers/sort.d.ts +8 -7
- package/dist/esm/model/create.d.ts +1 -1
- package/dist/esm/perspective-viewer-datagrid.js +3 -3
- package/dist/esm/perspective-viewer-datagrid.js.map +4 -4
- package/dist/esm/plugin/activate.d.ts +1 -1
- package/dist/esm/plugin/column_style_controls.d.ts +1 -1
- package/dist/esm/style_handlers/body.d.ts +3 -3
- package/dist/esm/style_handlers/column_header.d.ts +4 -3
- package/dist/esm/style_handlers/consolidated.d.ts +3 -47
- package/dist/esm/style_handlers/editable.d.ts +3 -2
- package/dist/esm/style_handlers/focus.d.ts +4 -4
- package/dist/esm/style_handlers/group_header.d.ts +1 -1
- package/dist/esm/style_handlers/table_cell/boolean.d.ts +1 -1
- package/dist/esm/style_handlers/table_cell/cell_flash.d.ts +1 -1
- package/dist/esm/style_handlers/table_cell/datetime.d.ts +6 -2
- package/dist/esm/style_handlers/table_cell/numeric.d.ts +1 -1
- package/dist/esm/style_handlers/table_cell/row_header.d.ts +1 -1
- package/dist/esm/style_handlers/table_cell/string.d.ts +1 -1
- package/dist/esm/style_handlers/types.d.ts +0 -4
- package/dist/esm/types.d.ts +10 -17
- package/package.json +3 -5
- package/src/css/mitered-headers.css +64 -0
- package/src/css/perspective-viewer-datagrid.css +6 -0
- package/src/{less/pro.less → css/pro.css} +32 -31
- package/src/css/regular_table.css +589 -0
- package/src/{less/row-hover.less → css/row-hover.css} +48 -29
- package/src/{less/scrollbar.less → css/scrollbar.css} +16 -15
- package/src/{less/sub-cell-scroll.less → css/sub-cell-scroll.css} +14 -13
- package/src/{less/toolbar.less → css/toolbar.css} +57 -39
- package/src/ts/color_utils.ts +144 -16
- package/src/ts/custom_elements/datagrid.ts +11 -12
- package/src/ts/custom_elements/toolbar.ts +4 -5
- package/src/ts/data_listener/format_cell.ts +28 -9
- package/src/ts/data_listener/formatter_cache.ts +1 -1
- package/src/ts/data_listener/index.ts +4 -8
- package/src/ts/event_handlers/click/edit_click.ts +7 -6
- package/src/ts/event_handlers/click.ts +39 -68
- package/src/ts/event_handlers/dispatch_click.ts +24 -25
- package/src/ts/event_handlers/expand_collapse.ts +7 -7
- package/src/ts/event_handlers/focus.ts +38 -35
- package/src/ts/event_handlers/header_click.ts +101 -62
- package/src/ts/event_handlers/keydown/edit_keydown.ts +49 -52
- package/src/ts/event_handlers/select_region.ts +144 -133
- package/src/ts/event_handlers/sort.ts +16 -24
- package/src/ts/model/column_overrides.ts +13 -4
- package/src/ts/model/create.ts +55 -59
- package/src/ts/model/toolbar.ts +23 -7
- package/src/ts/plugin/activate.ts +120 -92
- package/src/ts/plugin/column_style_controls.ts +1 -1
- package/src/ts/plugin/save.ts +1 -0
- package/src/ts/style_handlers/body.ts +56 -61
- package/src/ts/style_handlers/column_header.ts +16 -19
- package/src/ts/style_handlers/consolidated.ts +22 -123
- package/src/ts/style_handlers/editable.ts +10 -8
- package/src/ts/style_handlers/focus.ts +5 -5
- package/src/ts/style_handlers/group_header.ts +3 -2
- package/src/ts/style_handlers/table_cell/boolean.ts +3 -3
- package/src/ts/style_handlers/table_cell/cell_flash.ts +11 -11
- package/src/ts/style_handlers/table_cell/datetime.ts +14 -11
- package/src/ts/style_handlers/table_cell/numeric.ts +24 -25
- package/src/ts/style_handlers/table_cell/row_header.ts +2 -2
- package/src/ts/style_handlers/table_cell/string.ts +20 -18
- package/src/ts/style_handlers/types.ts +0 -10
- package/src/ts/types.ts +28 -20
- package/dist/esm/event_handlers/deselect_all.d.ts +0 -5
- package/dist/esm/event_handlers/row_select_click.d.ts +0 -4
- package/src/less/mitered-headers.less +0 -65
- package/src/less/regular_table.less +0 -526
- package/src/ts/event_handlers/deselect_all.ts +0 -28
- package/src/ts/event_handlers/row_select_click.ts +0 -92
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
* ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
* ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
* ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
* ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
* ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
* ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
* ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
* ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
* ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
* ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
*/
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
/* Scrollbar styling */
|
|
14
15
|
regular-table {
|
|
15
16
|
outline: none;
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
/* webkit (chrome, safari, etc) scrollbar styling */
|
|
18
19
|
&::-webkit-scrollbar,
|
|
19
20
|
&::-webkit-scrollbar-corner {
|
|
20
21
|
background-color: transparent;
|
|
@@ -24,8 +25,8 @@ regular-table {
|
|
|
24
25
|
|
|
25
26
|
&::-webkit-scrollbar-thumb {
|
|
26
27
|
background-clip: content-box;
|
|
27
|
-
background: var(--
|
|
28
|
-
border: 5.5px solid var(--
|
|
28
|
+
background: var(--psp--color);
|
|
29
|
+
border: 5.5px solid var(--psp--background-color);
|
|
29
30
|
max-height: 50%;
|
|
30
31
|
max-width: 50%;
|
|
31
32
|
min-width: 10%;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
* ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
* ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
* ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
* ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
* ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
* ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
* ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
* ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
* ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
* ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
*/
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
/* Handles sub-cell scrolling via CSS transform offset by variables set during */
|
|
15
|
+
/* rendering. */
|
|
15
16
|
perspective-viewer-datagrid:not(.sub-cell-scroll-disabled) regular-table table,
|
|
16
17
|
:host(:not(.sub-cell-scroll-disabled)) regular-table table {
|
|
17
18
|
tbody td,
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
/* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
* ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
* ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
* ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
* ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
* ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
* ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
* ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
* ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
* ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
* ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
*/
|
|
12
13
|
|
|
13
14
|
:host {
|
|
14
15
|
position: relative;
|
|
@@ -42,9 +43,9 @@
|
|
|
42
43
|
|
|
43
44
|
&:hover {
|
|
44
45
|
box-shadow:
|
|
45
|
-
-4px 0 0 var(--
|
|
46
|
-
4px 0 0 var(--
|
|
47
|
-
background-color: var(--
|
|
46
|
+
-4px 0 0 var(--psp--color),
|
|
47
|
+
4px 0 0 var(--psp--color);
|
|
48
|
+
background-color: var(--psp--color);
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -54,11 +55,11 @@
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
#scroll_lock.lock-scroll:before {
|
|
57
|
-
-webkit-mask-image: var(--toolbar-scroll-lock-active--content);
|
|
58
|
+
-webkit-mask-image: var(--psp-toolbar-scroll-lock-active--content);
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
#scroll_lock:before {
|
|
61
|
-
-webkit-mask-image: var(--toolbar-scroll-lock--content);
|
|
62
|
+
-webkit-mask-image: var(--psp-toolbar-scroll-lock--content);
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
#select_mode:before {
|
|
@@ -70,69 +71,86 @@
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
#edit_mode[data-edit-mode="READ_ONLY"]:before {
|
|
73
|
-
-webkit-mask-image: var(--toolbar-edit-mode
|
|
74
|
+
-webkit-mask-image: var(--psp-toolbar-edit-mode-read-only--content);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
#edit_mode[data-edit-mode="EDIT"]:before {
|
|
77
|
-
-webkit-mask-image: var(--toolbar-edit-mode
|
|
78
|
+
-webkit-mask-image: var(--psp-toolbar-edit-mode-edit--content);
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
:host(.aggregated) #toolbar #edit_mode[data-edit-mode="EDIT"]:before {
|
|
81
|
-
-webkit-mask-image: var(--toolbar-edit-mode
|
|
82
|
+
-webkit-mask-image: var(--psp-toolbar-edit-mode-read-only--content);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
#edit_mode[data-edit-mode="SELECT_ROW"]:before {
|
|
85
|
-
-webkit-mask-image: var(--toolbar-edit-mode
|
|
86
|
+
-webkit-mask-image: var(--psp-toolbar-edit-mode-select-row--content);
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
#edit_mode[data-edit-mode="SELECT_COLUMN"]:before {
|
|
89
|
-
-webkit-mask-image: var(--toolbar-edit-mode
|
|
90
|
+
-webkit-mask-image: var(--psp-toolbar-edit-mode-select-column--content);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
#edit_mode[data-edit-mode="SELECT_REGION"]:before {
|
|
93
|
-
-webkit-mask-image: var(--toolbar-edit-mode
|
|
94
|
+
-webkit-mask-image: var(--psp-toolbar-edit-mode-select-region--content);
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
#edit_mode[data-edit-mode="SELECT_ROW_TREE"]:before {
|
|
98
|
+
-webkit-mask-image: var(--psp-toolbar-edit-mode-select-row-tree--content);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* #edit_mode span:before { */
|
|
102
|
+
/* content: var(--edit-mode-toggle--content, "N/A"); */
|
|
103
|
+
/* } */
|
|
99
104
|
|
|
100
105
|
#edit_mode[data-edit-mode="READ_ONLY"] span:before {
|
|
101
|
-
content: var(--edit-mode
|
|
106
|
+
content: var(--psp-label--edit-mode-read-only--content, "Read Only");
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
#edit_mode[data-edit-mode="EDIT"] span:before {
|
|
105
|
-
content: var(--edit-mode
|
|
110
|
+
content: var(--psp-label--edit-mode-edit--content, "Editable");
|
|
106
111
|
}
|
|
107
112
|
|
|
108
113
|
#edit_mode[data-edit-mode="SELECT_ROW"] span:before {
|
|
109
|
-
content: var(--edit-mode
|
|
114
|
+
content: var(--psp-label--edit-mode-select-row--content, "Row Select");
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
#edit_mode[data-edit-mode="SELECT_COLUMN"] span:before {
|
|
113
|
-
content: var(
|
|
118
|
+
content: var(
|
|
119
|
+
--psp-label--edit-mode-select-column--content,
|
|
120
|
+
"Column Select"
|
|
121
|
+
);
|
|
114
122
|
}
|
|
115
123
|
|
|
116
124
|
#edit_mode[data-edit-mode="SELECT_REGION"] span:before {
|
|
117
|
-
content: var(
|
|
125
|
+
content: var(
|
|
126
|
+
--psp-label--edit-mode-select-region--content,
|
|
127
|
+
"Region Select"
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#edit_mode[data-edit-mode="SELECT_ROW_TREE"] span:before {
|
|
132
|
+
content: var(
|
|
133
|
+
--psp-label--edit-mode-select-row-tree--content,
|
|
134
|
+
"Tree Select"
|
|
135
|
+
);
|
|
118
136
|
}
|
|
119
137
|
|
|
120
138
|
#scroll_lock span:before {
|
|
121
|
-
content: var(--scroll-lock-toggle--content, "Free Scroll");
|
|
139
|
+
content: var(--psp-label--scroll-lock-toggle--content, "Free Scroll");
|
|
122
140
|
}
|
|
123
141
|
|
|
124
142
|
#scroll_lock.lock-scroll span:before {
|
|
125
|
-
content: var(--scroll-lock-alt-toggle--content, "Align Scroll");
|
|
143
|
+
content: var(--psp-label--scroll-lock-alt-toggle--content, "Align Scroll");
|
|
126
144
|
}
|
|
127
145
|
|
|
128
|
-
|
|
146
|
+
/* The icon. */
|
|
129
147
|
.button:before {
|
|
130
148
|
width: 21px;
|
|
131
149
|
height: 21px;
|
|
132
150
|
content: "";
|
|
133
151
|
-webkit-mask-size: cover;
|
|
134
152
|
mask-size: cover;
|
|
135
|
-
background-color: var(--
|
|
153
|
+
background-color: var(--psp--color);
|
|
136
154
|
}
|
|
137
155
|
|
|
138
156
|
.button.editable:before,
|
|
@@ -167,8 +185,8 @@
|
|
|
167
185
|
.hover-target:focus-within .button,
|
|
168
186
|
.hover-target:hover .button {
|
|
169
187
|
position: relative;
|
|
170
|
-
background-color: var(--
|
|
171
|
-
color: var(--
|
|
188
|
+
background-color: var(--psp--color);
|
|
189
|
+
color: var(--psp--background-color);
|
|
172
190
|
opacity: 1;
|
|
173
191
|
display: flex;
|
|
174
192
|
align-items: center;
|
|
@@ -177,10 +195,10 @@
|
|
|
177
195
|
|
|
178
196
|
.hover-target:focus-within .button:before,
|
|
179
197
|
.hover-target:hover .button:before {
|
|
180
|
-
background-color: var(--
|
|
198
|
+
background-color: var(--psp--background-color);
|
|
181
199
|
}
|
|
182
200
|
|
|
183
|
-
|
|
201
|
+
/* The label. */
|
|
184
202
|
.hover-target:focus-within .button > span,
|
|
185
203
|
.hover-target:hover .button > span {
|
|
186
204
|
display: block;
|
|
@@ -194,7 +212,7 @@
|
|
|
194
212
|
white-space: pre-wrap;
|
|
195
213
|
line-height: 1;
|
|
196
214
|
font-size: 9px;
|
|
197
|
-
background-color: var(--
|
|
215
|
+
background-color: var(--psp--color);
|
|
198
216
|
width: 35px;
|
|
199
217
|
text-align: center;
|
|
200
218
|
border-radius: 0 0 3px 3px;
|
package/src/ts/color_utils.ts
CHANGED
|
@@ -10,15 +10,145 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
import chroma from "chroma-js";
|
|
14
13
|
import type { ColorRecord } from "./types.js";
|
|
15
14
|
|
|
15
|
+
/** 8-bit sRGB color as `[r, g, b]` with each channel in `[0, 255]`. */
|
|
16
|
+
export type RGB = [number, number, number];
|
|
17
|
+
|
|
18
|
+
/** HSL color as `[h, s, l]` with `h` in degrees `[0, 360)` and `s`, `l` in `[0, 1]`. */
|
|
19
|
+
export type HSL = [number, number, number];
|
|
20
|
+
|
|
21
|
+
const parse_cache = new Map<string, RGB>();
|
|
22
|
+
let parse_ctx: CanvasRenderingContext2D | null = null;
|
|
23
|
+
|
|
24
|
+
/** Parse a CSS hex color (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`). Returns `null` if `input` is not a hex literal. Alpha is ignored. */
|
|
25
|
+
function parse_hex(input: string): RGB | null {
|
|
26
|
+
const s = input.startsWith("#") ? input.slice(1) : input;
|
|
27
|
+
if (s.length === 3 || s.length === 4) {
|
|
28
|
+
const r = parseInt(s[0] + s[0], 16);
|
|
29
|
+
const g = parseInt(s[1] + s[1], 16);
|
|
30
|
+
const b = parseInt(s[2] + s[2], 16);
|
|
31
|
+
if (!isNaN(r) && !isNaN(g) && !isNaN(b)) return [r, g, b];
|
|
32
|
+
} else if (s.length === 6 || s.length === 8) {
|
|
33
|
+
const r = parseInt(s.slice(0, 2), 16);
|
|
34
|
+
const g = parseInt(s.slice(2, 4), 16);
|
|
35
|
+
const b = parseInt(s.slice(4, 6), 16);
|
|
36
|
+
if (!isNaN(r) && !isNaN(g) && !isNaN(b)) return [r, g, b];
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Parse a CSS `rgb()` or `rgba()` functional color. Returns `null` if `input` does not match. Alpha is ignored. */
|
|
42
|
+
function parse_rgb_fn(input: string): RGB | null {
|
|
43
|
+
const m = input.match(
|
|
44
|
+
/^rgba?\(\s*([\d.]+)\s*[, ]\s*([\d.]+)\s*[, ]\s*([\d.]+)/i,
|
|
45
|
+
);
|
|
46
|
+
if (!m) return null;
|
|
47
|
+
return [
|
|
48
|
+
Math.round(parseFloat(m[1])),
|
|
49
|
+
Math.round(parseFloat(m[2])),
|
|
50
|
+
Math.round(parseFloat(m[3])),
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Fallback parser that defers to the browser by assigning `input` to a 2D canvas `fillStyle` and re-reading the normalized value. Handles named colors, `hsl()`, etc. Returns `[0, 0, 0]` if the value is invalid or no canvas context is available. */
|
|
55
|
+
function parse_via_canvas(input: string): RGB {
|
|
56
|
+
if (!parse_ctx) {
|
|
57
|
+
const canvas = document.createElement("canvas");
|
|
58
|
+
canvas.width = canvas.height = 1;
|
|
59
|
+
parse_ctx = canvas.getContext("2d");
|
|
60
|
+
}
|
|
61
|
+
if (!parse_ctx) return [0, 0, 0];
|
|
62
|
+
parse_ctx.fillStyle = "#000";
|
|
63
|
+
parse_ctx.fillStyle = input;
|
|
64
|
+
const normalized = parse_ctx.fillStyle as string;
|
|
65
|
+
return parse_hex(normalized) ?? parse_rgb_fn(normalized) ?? [0, 0, 0];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Parse any CSS color string into an `RGB` triple. Tries hex and `rgb()` fast paths, then falls back to a canvas-based parser for named colors, `hsl()`, etc. Results are memoized per input. */
|
|
69
|
+
export function parseColor(input: string): RGB {
|
|
70
|
+
const key = input.trim();
|
|
71
|
+
const cached = parse_cache.get(key);
|
|
72
|
+
if (cached) return cached;
|
|
73
|
+
const rgb = parse_hex(key) ?? parse_rgb_fn(key) ?? parse_via_canvas(key);
|
|
74
|
+
parse_cache.set(key, rgb);
|
|
75
|
+
return rgb;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Format a single channel as a clamped, zero-padded two-digit hex byte. */
|
|
79
|
+
function toHex(c: number): string {
|
|
80
|
+
const v = Math.max(0, Math.min(255, Math.round(c)));
|
|
81
|
+
return v.toString(16).padStart(2, "0");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Format an `RGB` triple as a `#rrggbb` hex string. Channels are clamped to `[0, 255]`. */
|
|
85
|
+
export function rgbToHex([r, g, b]: RGB): string {
|
|
86
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Convert sRGB to HSL. Output `h` is in degrees `[0, 360)`; `s` and `l` are in `[0, 1]`. */
|
|
90
|
+
export function rgbToHsl([r, g, b]: RGB): HSL {
|
|
91
|
+
const rn = r / 255,
|
|
92
|
+
gn = g / 255,
|
|
93
|
+
bn = b / 255;
|
|
94
|
+
const max = Math.max(rn, gn, bn);
|
|
95
|
+
const min = Math.min(rn, gn, bn);
|
|
96
|
+
const l = (max + min) / 2;
|
|
97
|
+
const d = max - min;
|
|
98
|
+
let h = 0;
|
|
99
|
+
let s = 0;
|
|
100
|
+
if (d !== 0) {
|
|
101
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
102
|
+
if (max === rn) h = ((gn - bn) / d + (gn < bn ? 6 : 0)) * 60;
|
|
103
|
+
else if (max === gn) h = ((bn - rn) / d + 2) * 60;
|
|
104
|
+
else h = ((rn - gn) / d + 4) * 60;
|
|
105
|
+
}
|
|
106
|
+
return [h, s, l];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Convert HSL to sRGB. `h` is wrapped into `[0, 360)`; `s` and `l` are expected in `[0, 1]`. Output channels are rounded to integers in `[0, 255]`. */
|
|
110
|
+
export function hslToRgb([h, s, l]: HSL): RGB {
|
|
111
|
+
const hn = (((h % 360) + 360) % 360) / 360;
|
|
112
|
+
if (s === 0) {
|
|
113
|
+
const v = Math.round(l * 255);
|
|
114
|
+
return [v, v, v];
|
|
115
|
+
}
|
|
116
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
117
|
+
const p = 2 * l - q;
|
|
118
|
+
const f = (t: number): number => {
|
|
119
|
+
if (t < 0) t += 1;
|
|
120
|
+
if (t > 1) t -= 1;
|
|
121
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
122
|
+
if (t < 1 / 2) return q;
|
|
123
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
124
|
+
return p;
|
|
125
|
+
};
|
|
126
|
+
return [
|
|
127
|
+
Math.round(f(hn + 1 / 3) * 255),
|
|
128
|
+
Math.round(f(hn) * 255),
|
|
129
|
+
Math.round(f(hn - 1 / 3) * 255),
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Blend two `RGB` colors using LRGB (gamma-naive linear) interpolation,
|
|
135
|
+
* matching chroma-js's default `mix` mode. `f` is the weight of `b` in `[0, 1]`
|
|
136
|
+
* (0 returns `a`, 1 returns `b`).
|
|
137
|
+
*/
|
|
138
|
+
export function mixRgb(a: RGB, b: RGB, f = 0.5): RGB {
|
|
139
|
+
return [
|
|
140
|
+
Math.round(Math.sqrt(a[0] * a[0] * (1 - f) + b[0] * b[0] * f)),
|
|
141
|
+
Math.round(Math.sqrt(a[1] * a[1] * (1 - f) + b[1] * b[1] * f)),
|
|
142
|
+
Math.round(Math.sqrt(a[2] * a[2] * (1 - f) + b[2] * b[2] * f)),
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** 50/50 LRGB blend of CSS color `a` with `RGB`-ish triple `b`, returned as `#rrggbb`. */
|
|
16
147
|
export function blend(a: string, b: number[]): string {
|
|
17
|
-
return
|
|
148
|
+
return rgbToHex(mixRgb(parseColor(a), [b[0], b[1], b[2]], 0.5));
|
|
18
149
|
}
|
|
19
150
|
|
|
20
|
-
|
|
21
|
-
// the color of a heatmap cell over the background.
|
|
151
|
+
/** Composite a premultiplied-style `RGBA` cell color over `source` (default white) and return the resulting opaque `RGB`. Used to flatten heatmap cells against the background. */
|
|
22
152
|
export function rgbaToRgb(
|
|
23
153
|
[r, g, b, a]: [number, number, number, number],
|
|
24
154
|
source: [number, number, number] = [255, 255, 255],
|
|
@@ -30,7 +160,7 @@ export function rgbaToRgb(
|
|
|
30
160
|
return [f(0, r), f(1, g), f(2, b)];
|
|
31
161
|
}
|
|
32
162
|
|
|
33
|
-
|
|
163
|
+
/** Pick a readable foreground (`#161616` or `#ffffff`) for the given background using a perceptual luminance threshold. */
|
|
34
164
|
export function infer_foreground_from_background([r, g, b]: [
|
|
35
165
|
number,
|
|
36
166
|
number,
|
|
@@ -42,21 +172,19 @@ export function infer_foreground_from_background([r, g, b]: [
|
|
|
42
172
|
: "#ffffff";
|
|
43
173
|
}
|
|
44
174
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const [
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const [r2, g2, b2] =
|
|
51
|
-
.set("hsl.h", (chromahex.get("hsl.h") + 15) % 360)
|
|
52
|
-
.rgb();
|
|
175
|
+
/** Build a CSS `linear-gradient` that fans `rgb` ±15° in hue, used as the negative-value swatch in column color pickers. */
|
|
176
|
+
function make_gradient(rgb: RGB): string {
|
|
177
|
+
const [h, s, l] = rgbToHsl(rgb);
|
|
178
|
+
const [r, g, b] = rgb;
|
|
179
|
+
const [r1, g1, b1] = hslToRgb([h - 15, s, l]);
|
|
180
|
+
const [r2, g2, b2] = hslToRgb([h + 15, s, l]);
|
|
53
181
|
return `linear-gradient(to right top,rgb(${r1},${g1},${b1}),rgb(${r},${g},${b}) 50%,rgb(${r2},${g2},${b2}))`;
|
|
54
182
|
}
|
|
55
183
|
|
|
184
|
+
/** Precompute the tuple of derived color strings (RGB channels, gradient, opaque/transparent rgba) cached on the model for a configured plugin color. */
|
|
56
185
|
export function make_color_record(color: string): ColorRecord {
|
|
57
|
-
const
|
|
58
|
-
const _neg_grad = make_gradient(
|
|
59
|
-
const rgb = chroma_neg.rgb();
|
|
186
|
+
const rgb = parseColor(color);
|
|
187
|
+
const _neg_grad = make_gradient(rgb);
|
|
60
188
|
return [
|
|
61
189
|
color,
|
|
62
190
|
rgb[0],
|
|
@@ -22,12 +22,14 @@ import datagridStyles from "../../../dist/css/perspective-viewer-datagrid.css";
|
|
|
22
22
|
import { format_raw } from "../data_listener/format_cell.js";
|
|
23
23
|
|
|
24
24
|
import type { View, ViewWindow } from "@perspective-dev/client";
|
|
25
|
-
import type {
|
|
25
|
+
import type {
|
|
26
|
+
HTMLPerspectiveViewerElement,
|
|
27
|
+
IPerspectiveViewerPlugin,
|
|
28
|
+
} from "@perspective-dev/viewer";
|
|
26
29
|
import type {
|
|
27
30
|
DatagridModel,
|
|
28
31
|
DatagridToolbarElement,
|
|
29
32
|
EditMode,
|
|
30
|
-
PerspectiveViewerElement,
|
|
31
33
|
DatagridPluginConfig,
|
|
32
34
|
ColumnsConfig,
|
|
33
35
|
} from "../types.js";
|
|
@@ -171,7 +173,7 @@ export class HTMLPerspectiveViewerDatagridPluginElement
|
|
|
171
173
|
}
|
|
172
174
|
|
|
173
175
|
async render(viewport?: ViewWindow): Promise<string> {
|
|
174
|
-
const viewer = this.parentElement as
|
|
176
|
+
const viewer = this.parentElement as HTMLPerspectiveViewerElement;
|
|
175
177
|
const view = await viewer.getView();
|
|
176
178
|
const json = await view.to_columns(viewport as any);
|
|
177
179
|
const cols = await view.column_paths(viewport as any);
|
|
@@ -210,7 +212,7 @@ export class HTMLPerspectiveViewerDatagridPluginElement
|
|
|
210
212
|
return out.trim();
|
|
211
213
|
}
|
|
212
214
|
|
|
213
|
-
async resize(): Promise<void> {
|
|
215
|
+
async resize(_view: View): Promise<void> {
|
|
214
216
|
if (!this.isConnected || this.offsetParent == null) {
|
|
215
217
|
return;
|
|
216
218
|
}
|
|
@@ -225,25 +227,22 @@ export class HTMLPerspectiveViewerDatagridPluginElement
|
|
|
225
227
|
this.regular_table.clear();
|
|
226
228
|
}
|
|
227
229
|
|
|
228
|
-
|
|
230
|
+
save(): any {
|
|
229
231
|
return save.call(this);
|
|
230
232
|
}
|
|
231
233
|
|
|
232
|
-
|
|
233
|
-
token: DatagridPluginConfig,
|
|
234
|
-
columns_config?: ColumnsConfig,
|
|
235
|
-
): Promise<any> {
|
|
234
|
+
restore(token: DatagridPluginConfig, columns_config?: ColumnsConfig): void {
|
|
236
235
|
return restore.call(this, token, columns_config ?? {});
|
|
237
236
|
}
|
|
238
237
|
|
|
239
|
-
async restyle(): Promise<void> {
|
|
238
|
+
async restyle(view: View): Promise<void> {
|
|
240
239
|
// Get view from model if available, otherwise no-op
|
|
241
240
|
if (this.model?._view) {
|
|
242
|
-
await this.draw(
|
|
241
|
+
await this.draw(view);
|
|
243
242
|
}
|
|
244
243
|
}
|
|
245
244
|
|
|
246
|
-
|
|
245
|
+
delete(): void {
|
|
247
246
|
this.disconnectedCallback();
|
|
248
247
|
this._toolbar = undefined;
|
|
249
248
|
if ((this.regular_table as any).table_model) {
|
|
@@ -10,12 +10,10 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
+
import type { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
|
|
13
14
|
import TOOLBAR_STYLE from "../../../dist/css/perspective-viewer-datagrid-toolbar.css";
|
|
14
15
|
import { toggle_edit_mode, toggle_scroll_lock } from "../model/toolbar.js";
|
|
15
|
-
import type {
|
|
16
|
-
DatagridPluginElement,
|
|
17
|
-
PerspectiveViewerElement,
|
|
18
|
-
} from "../types.js";
|
|
16
|
+
import type { DatagridPluginElement } from "../types.js";
|
|
19
17
|
|
|
20
18
|
const stylesheet = new CSSStyleSheet();
|
|
21
19
|
stylesheet.replaceSync(TOOLBAR_STYLE);
|
|
@@ -53,7 +51,7 @@ export class HTMLPerspectiveViewerDatagridToolbarElement extends HTMLElement {
|
|
|
53
51
|
</div>
|
|
54
52
|
`;
|
|
55
53
|
|
|
56
|
-
const viewer = this.parentElement as
|
|
54
|
+
const viewer = this.parentElement as HTMLPerspectiveViewerElement;
|
|
57
55
|
const plugin = this.previousElementSibling as DatagridPluginElement;
|
|
58
56
|
|
|
59
57
|
plugin._scroll_lock = this.shadowRoot!.querySelector(
|
|
@@ -66,6 +64,7 @@ export class HTMLPerspectiveViewerDatagridToolbarElement extends HTMLElement {
|
|
|
66
64
|
plugin._edit_button = this.shadowRoot!.querySelector(
|
|
67
65
|
"#edit_mode",
|
|
68
66
|
) as HTMLElement;
|
|
67
|
+
|
|
69
68
|
plugin._edit_button.addEventListener("click", () => {
|
|
70
69
|
toggle_edit_mode.call(plugin);
|
|
71
70
|
plugin.regular_table.draw();
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { FormatterCache, Formatter } from "./formatter_cache.js";
|
|
14
14
|
import type { DatagridModel, ColumnsConfig, ColumnConfig } from "../types.js";
|
|
15
|
-
import { ColumnType } from "@perspective-dev/client";
|
|
15
|
+
import type { ColumnType } from "@perspective-dev/client";
|
|
16
16
|
|
|
17
17
|
const FORMAT_CACHE = new FormatterCache();
|
|
18
18
|
const MAX_BAR_WIDTH_PCT = 1;
|
|
@@ -44,7 +44,11 @@ export function format_cell(
|
|
|
44
44
|
const plugin: ColumnConfig = plugins[title] || {};
|
|
45
45
|
const is_numeric = type === "integer" || type === "float";
|
|
46
46
|
|
|
47
|
-
if (
|
|
47
|
+
if (
|
|
48
|
+
is_numeric &&
|
|
49
|
+
(plugin?.number_fg_mode === "bar" ||
|
|
50
|
+
plugin?.number_fg_mode === "label-bar")
|
|
51
|
+
) {
|
|
48
52
|
const a = Math.max(
|
|
49
53
|
0,
|
|
50
54
|
Math.min(
|
|
@@ -54,15 +58,30 @@ export function format_cell(
|
|
|
54
58
|
),
|
|
55
59
|
);
|
|
56
60
|
|
|
57
|
-
const
|
|
58
|
-
const anchor = (val as number) >= 0 ? "left" : "right";
|
|
61
|
+
const anchor = (val as number) >= 0 ? "" : "justify-self:flex-end;";
|
|
59
62
|
const pct = (a * 100).toFixed(2);
|
|
60
|
-
div.setAttribute(
|
|
61
|
-
"style",
|
|
62
|
-
`width:calc(${pct}% - 4px);position:absolute;${anchor}:2px;height:80%;top:10%;pointer-events:none;`,
|
|
63
|
-
);
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
if (plugin.number_fg_mode === "bar") {
|
|
65
|
+
const div = this._div_factory.get();
|
|
66
|
+
div.className = "psp-bar";
|
|
67
|
+
div.setAttribute(
|
|
68
|
+
"style",
|
|
69
|
+
`${anchor}width:${pct}%;height:80%;top:10%;pointer-events:none;background:var(--psp-label-bar-color)`,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return div;
|
|
73
|
+
} else {
|
|
74
|
+
const formatter = FORMAT_CACHE.get(type, plugin);
|
|
75
|
+
const label = formatter ? formatter.format(val) : (val as string);
|
|
76
|
+
|
|
77
|
+
const div = this._div_factory.get();
|
|
78
|
+
div.className = "psp-bar";
|
|
79
|
+
div.setAttribute(
|
|
80
|
+
"style",
|
|
81
|
+
`--label:"${label}";${anchor}width:${pct}%;height:80%;top:10%;pointer-events:none;background:var(--psp-label-bar-color)`,
|
|
82
|
+
);
|
|
83
|
+
return div;
|
|
84
|
+
}
|
|
66
85
|
} else if (plugin?.format === "link" && type === "string") {
|
|
67
86
|
const anchor = document.createElement("a");
|
|
68
87
|
anchor.setAttribute("href", val as string);
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
import { ColumnType } from "@perspective-dev/client";
|
|
13
|
+
import type { ColumnType } from "@perspective-dev/client";
|
|
14
14
|
import type { ColumnConfig } from "../types.js";
|
|
15
15
|
|
|
16
16
|
export interface Formatter {
|