@perspective-dev/viewer 4.5.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/dist/cdn/perspective-viewer.js +20 -1
  2. package/dist/cdn/perspective-viewer.js.map +4 -4
  3. package/dist/css/botanical.css +1 -1
  4. package/dist/css/dracula.css +1 -1
  5. package/dist/css/gruvbox-dark.css +1 -1
  6. package/dist/css/gruvbox.css +1 -1
  7. package/dist/css/icons.css +1 -1
  8. package/dist/css/monokai.css +1 -1
  9. package/dist/css/phosphor.css +1 -1
  10. package/dist/css/pro-dark.css +1 -1
  11. package/dist/css/pro.css +1 -1
  12. package/dist/css/solarized-dark.css +1 -1
  13. package/dist/css/solarized.css +1 -1
  14. package/dist/css/themes.css +1 -1
  15. package/dist/css/vaporwave.css +1 -1
  16. package/dist/esm/extensions.d.ts +22 -3
  17. package/dist/esm/perspective-viewer.d.ts +9 -0
  18. package/dist/esm/perspective-viewer.inline.js +20 -1
  19. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  20. package/dist/esm/perspective-viewer.js +20 -1
  21. package/dist/esm/perspective-viewer.js.map +4 -4
  22. package/dist/esm/plugin.d.ts +71 -5
  23. package/dist/esm/ts-rs/ClientOptions.d.ts +7 -0
  24. package/dist/esm/ts-rs/ExportMethod.d.ts +1 -0
  25. package/dist/esm/ts-rs/ExportOptions.d.ts +9 -0
  26. package/dist/esm/ts-rs/GetClientOptions.d.ts +8 -0
  27. package/dist/esm/ts-rs/GetTableOptions.d.ts +8 -0
  28. package/dist/esm/ts-rs/Layout.d.ts +11 -0
  29. package/dist/esm/ts-rs/Orientation.d.ts +4 -0
  30. package/dist/esm/ts-rs/PanelOptions.d.ts +7 -0
  31. package/dist/esm/ts-rs/PanelViewerConfig.d.ts +39 -0
  32. package/dist/esm/ts-rs/SplitLayout.d.ts +7 -0
  33. package/dist/esm/ts-rs/TabLayout.d.ts +10 -0
  34. package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -2
  35. package/dist/esm/ts-rs/WorkspaceConfig.d.ts +40 -0
  36. package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +28 -0
  37. package/dist/wasm/perspective-viewer.d.ts +211 -77
  38. package/dist/wasm/perspective-viewer.js +528 -180
  39. package/dist/wasm/perspective-viewer.wasm +0 -0
  40. package/dist/wasm/perspective-viewer.wasm.d.ts +34 -26
  41. package/dist/wasm/snippets/perspective-viewer-daeef4ceb066e6c7/inline0.js +6 -0
  42. package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline3.js → perspective-viewer-daeef4ceb066e6c7/inline4.js} +5 -0
  43. package/package.json +3 -2
  44. package/src/css/_context_menu.css +14 -0
  45. package/src/css/column-settings-panel.css +1 -1
  46. package/src/css/containers/context-menu.css +101 -0
  47. package/src/css/panel-tab.css +193 -0
  48. package/src/css/plugin-selector.css +7 -10
  49. package/src/css/status-bar.css +75 -81
  50. package/src/css/viewer.css +180 -70
  51. package/src/rust/components/column_dropdown.rs +40 -30
  52. package/src/rust/components/column_selector/active_column.rs +7 -18
  53. package/src/rust/components/column_selector/aggregate_selector.rs +4 -7
  54. package/src/rust/components/column_selector/config_selector.rs +33 -81
  55. package/src/rust/components/column_selector/filter_column.rs +5 -15
  56. package/src/rust/components/column_selector/inactive_column.rs +3 -8
  57. package/src/rust/components/column_selector/sort_column.rs +3 -6
  58. package/src/rust/components/column_selector.rs +5 -11
  59. package/src/rust/components/containers/split_panel.rs +175 -62
  60. package/src/rust/components/context_menu.rs +130 -0
  61. package/src/rust/components/form/debug.rs +3 -0
  62. package/src/rust/components/global_filter_bar.rs +76 -0
  63. package/src/rust/components/main_panel/frame_theme.rs +186 -0
  64. package/src/rust/components/main_panel/msg.rs +62 -0
  65. package/src/rust/components/main_panel/presize.rs +220 -0
  66. package/src/rust/components/main_panel/reconcile.rs +224 -0
  67. package/src/rust/components/main_panel/render.rs +385 -0
  68. package/src/rust/components/main_panel/update.rs +184 -0
  69. package/src/rust/components/main_panel.rs +311 -71
  70. package/src/rust/components/mod.rs +4 -0
  71. package/src/rust/components/panel_menu.rs +486 -0
  72. package/src/rust/components/panel_tab.rs +505 -0
  73. package/src/rust/components/plugin_tab.rs +1 -1
  74. package/src/rust/components/settings_panel.rs +13 -5
  75. package/src/rust/components/status_bar.rs +110 -178
  76. package/src/rust/components/status_indicator.rs +6 -9
  77. package/src/rust/components/style/mod.rs +5 -0
  78. package/src/rust/components/style/style_provider.rs +2 -0
  79. package/src/rust/components/viewer/filters.rs +133 -0
  80. package/src/rust/components/viewer/msg.rs +180 -0
  81. package/src/rust/components/viewer/panels.rs +326 -0
  82. package/src/rust/components/viewer/render.rs +243 -0
  83. package/src/rust/components/viewer/settings.rs +402 -0
  84. package/src/rust/components/viewer/snapshots.rs +134 -0
  85. package/src/rust/components/viewer/wiring.rs +505 -0
  86. package/src/rust/components/viewer.rs +243 -756
  87. package/src/rust/config/export_method.rs +1 -1
  88. package/src/rust/config/mod.rs +4 -0
  89. package/src/rust/config/options.rs +71 -0
  90. package/src/rust/config/viewer_config.rs +24 -2
  91. package/src/rust/config/workspace_config.rs +92 -0
  92. package/src/rust/custom_elements/copy_dropdown.rs +3 -1
  93. package/src/rust/custom_elements/debug_plugin.rs +20 -1
  94. package/src/rust/custom_elements/export_dropdown.rs +3 -1
  95. package/src/rust/custom_elements/viewer.rs +1015 -286
  96. package/src/rust/custom_events.rs +212 -61
  97. package/src/rust/js/mod.rs +2 -0
  98. package/src/rust/js/plugin.rs +297 -10
  99. package/src/rust/js/regular_layout.rs +258 -0
  100. package/src/rust/lib.rs +20 -1
  101. package/src/rust/presentation.rs +66 -33
  102. package/src/rust/queries/get_viewer_config.rs +29 -11
  103. package/src/rust/queries/plugin_column_styles.rs +2 -2
  104. package/src/rust/renderer/activate.rs +41 -14
  105. package/src/rust/renderer/dispatch.rs +436 -0
  106. package/src/rust/renderer/plugin_config.rs +495 -0
  107. package/src/rust/renderer/registry.rs +18 -6
  108. package/src/rust/renderer/render_timer.rs +29 -10
  109. package/src/rust/renderer.rs +350 -837
  110. package/src/rust/session/column_defaults_update.rs +26 -8
  111. package/src/rust/session/view_subscription.rs +30 -15
  112. package/src/rust/session.rs +753 -264
  113. package/src/rust/tasks/apply_global_filters.rs +89 -0
  114. package/src/rust/tasks/auto_pause.rs +171 -0
  115. package/src/rust/tasks/copy_export.rs +29 -19
  116. package/src/rust/tasks/create_panel.rs +243 -0
  117. package/src/rust/tasks/dismiss_render_warning.rs +3 -1
  118. package/src/rust/tasks/edit_expression.rs +4 -4
  119. package/src/rust/tasks/eject.rs +64 -23
  120. package/src/rust/tasks/mod.rs +28 -4
  121. package/src/rust/tasks/pipeline.rs +411 -0
  122. package/src/rust/tasks/presize_panels.rs +324 -0
  123. package/src/rust/tasks/reset_all.rs +22 -12
  124. package/src/rust/tasks/resize_observer.rs +124 -87
  125. package/src/rust/tasks/restore_and_render.rs +80 -86
  126. package/src/rust/tasks/restore_panel.rs +145 -0
  127. package/src/rust/tasks/send_column_config.rs +5 -2
  128. package/src/rust/tasks/send_plugin_config.rs +5 -2
  129. package/src/rust/tasks/set_edit_mode.rs +59 -0
  130. package/src/rust/tasks/sync_update_panels.rs +152 -0
  131. package/src/rust/tasks/table_lifecycle.rs +158 -0
  132. package/src/rust/tasks/update_theme.rs +56 -12
  133. package/src/rust/utils/completion.rs +56 -0
  134. package/src/rust/utils/custom_element.rs +5 -0
  135. package/src/rust/utils/debounce.rs +130 -7
  136. package/src/rust/utils/mod.rs +6 -0
  137. package/src/rust/utils/pending_effects.rs +62 -0
  138. package/src/rust/utils/spawn.rs +33 -0
  139. package/src/rust/utils/weak_scope.rs +0 -10
  140. package/src/rust/workspace.rs +846 -0
  141. package/src/svg/active-indicator.svg +3 -0
  142. package/src/themes/botanical.css +5 -2
  143. package/src/themes/defaults.css +54 -2
  144. package/src/themes/dracula.css +6 -3
  145. package/src/themes/gruvbox-dark.css +5 -2
  146. package/src/themes/gruvbox.css +5 -2
  147. package/src/themes/icons.css +4 -2
  148. package/src/themes/monokai.css +5 -2
  149. package/src/themes/phosphor.css +5 -2
  150. package/src/themes/pro-dark.css +5 -2
  151. package/src/themes/pro.css +2 -1
  152. package/src/themes/solarized-dark.css +5 -2
  153. package/src/themes/solarized.css +5 -2
  154. package/src/themes/vaporwave.css +5 -2
  155. package/src/ts/bootstrap.ts +8 -7
  156. package/src/ts/extensions.ts +30 -2
  157. package/src/ts/perspective-viewer.ts +10 -0
  158. package/src/ts/plugin.ts +72 -5
  159. package/src/ts/ts-rs/ClientOptions.ts +7 -0
  160. package/src/ts/ts-rs/ExportMethod.ts +3 -0
  161. package/src/ts/ts-rs/ExportOptions.ts +8 -0
  162. package/src/ts/ts-rs/GetClientOptions.ts +7 -0
  163. package/src/ts/ts-rs/GetTableOptions.ts +7 -0
  164. package/src/ts/ts-rs/Layout.ts +9 -0
  165. package/src/ts/ts-rs/Orientation.ts +6 -0
  166. package/src/ts/ts-rs/PanelOptions.ts +7 -0
  167. package/src/ts/ts-rs/PanelViewerConfig.ts +15 -0
  168. package/src/ts/ts-rs/SplitLayout.ts +5 -0
  169. package/src/ts/ts-rs/TabLayout.ts +11 -0
  170. package/src/ts/ts-rs/ViewerConfig.ts +6 -2
  171. package/src/ts/ts-rs/WorkspaceConfig.ts +36 -0
  172. package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +24 -0
  173. package/src/rust/tasks/intersection_observer.rs +0 -98
  174. package/src/rust/tasks/update_and_render.rs +0 -110
  175. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline0.js → perspective-viewer-daeef4ceb066e6c7/inline1.js} +0 -0
  176. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline1.js → perspective-viewer-daeef4ceb066e6c7/inline2.js} +0 -0
  177. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline2.js → perspective-viewer-daeef4ceb066e6c7/inline3.js} +0 -0
  178. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline4.js → perspective-viewer-daeef4ceb066e6c7/inline5.js} +0 -0
@@ -19,15 +19,8 @@
19
19
  }
20
20
 
21
21
  :host {
22
- /* When settings open ... */
23
- #main_column #status_bar,
24
- #main_column #status_bar.titled {
25
- input::placeholder {
26
- color: var(--psp-inactive--color);
27
- }
28
- }
29
-
30
22
  #status_bar.settings-closed {
23
+ box-shadow: none;
31
24
  padding-right: 10px;
32
25
  }
33
26
 
@@ -43,86 +36,25 @@
43
36
  height: auto;
44
37
  min-height: auto;
45
38
  max-height: none;
46
- gap: 6px;
47
- top: calc((var(--psp-status-bar--height, 48px) - 20px) / 2);
39
+ top: calc((var(--psp-status-bar--height, 38px) - 20px) / 2);
48
40
  right: calc(
49
- min(48px, (var(--psp-status-bar--height, 48px) - 20px) / 2)
41
+ min(48px, (var(--psp-status-bar--height, 38px) - 20px) / 2)
50
42
  );
51
43
  }
52
44
 
53
45
  #status_bar {
54
- box-shadow: 0 13px 0 -12px var(--psp-inactive--border-color);
55
- z-index: 3;
46
+ box-shadow: 0 1px 0 0px var(--psp-inactive--color);
47
+ z-index: 6;
56
48
  display: var(--psp-status-bar--display, flex);
57
- gap: 6px;
49
+ gap: 4px;
58
50
  align-items: center;
59
51
  background: var(--psp--background-color);
60
- padding: var(--psp-status-bar--padding, 0 31px 0 8px);
52
+ padding: var(--psp-status-bar--padding, 0 31px 0 4px);
61
53
  position: relative;
62
- height: var(--psp-status-bar--height, 48px);
63
- min-height: var(--psp-status-bar--height, 48px);
64
- max-height: var(--psp-status-bar--height, 48px);
54
+ height: var(--psp-status-bar--height, 38px);
55
+ min-height: var(--psp-status-bar--height, 38px);
56
+ max-height: var(--psp-status-bar--height, 38px);
65
57
  border-radius: var(--psp-status-bar--border-radius);
66
- #status-bar-placeholder {
67
- margin: 0px;
68
- margin-right: -5px;
69
- pointer-events: none;
70
- }
71
-
72
- input {
73
- font-size: 1em;
74
- }
75
-
76
- input:placeholder-shown + #status-bar-placeholder:before {
77
- content: var(--psp-label--untitled--content, "untitled");
78
- color: var(--psp-inactive--color);
79
- }
80
-
81
- .input-sizer {
82
- display: inline-block;
83
- align-items: center;
84
- position: relative;
85
- min-width: 65px;
86
- overflow: hidden;
87
- padding-top: 0.5px;
88
-
89
- &:after,
90
- input,
91
- textarea {
92
- width: auto;
93
- grid-area: 1 / 1;
94
- font-family: inherit;
95
- }
96
-
97
- input,
98
- textarea {
99
- position: absolute;
100
- left: 0;
101
- right: 0;
102
- text-overflow: ellipsis;
103
- padding: 0;
104
- border: none;
105
- background: transparent;
106
- color: inherit;
107
- height: 100%;
108
- }
109
-
110
- &:after {
111
- content: attr(data-value) " ";
112
- color: var(--psp-inactive--color, inherit);
113
- visibility: hidden;
114
- white-space: nowrap;
115
- padding-right: 12px;
116
- }
117
-
118
- &:focus-within {
119
- textarea:focus,
120
- input:focus {
121
- outline: none;
122
- }
123
- }
124
- }
125
-
126
58
  .section {
127
59
  display: flex;
128
60
  align-items: center;
@@ -143,7 +75,7 @@
143
75
  gap: 6px;
144
76
  flex: 0 1000 auto;
145
77
  overflow: hidden;
146
- margin: 0px 10px;
78
+ margin: 0px 0px;
147
79
  pointer-events: none;
148
80
  span {
149
81
  margin: 0 !important;
@@ -166,6 +98,68 @@
166
98
  align-self: stretch;
167
99
  }
168
100
 
101
+ /* Global-filter chips, rendered inline between the row stats and the
102
+ menu icons (was a dedicated strip above the panels). Shrinks/clips
103
+ rather than growing the fixed-height bar. */
104
+ #global_filter_bar {
105
+ display: flex;
106
+ align-items: center;
107
+ gap: 6px;
108
+ flex: 0 1 auto;
109
+ min-width: 0;
110
+ overflow: hidden;
111
+ font-size: 11px;
112
+
113
+ /* Beat the status bar's generic `span { margin: 0 14px }`. */
114
+ span {
115
+ margin: 0;
116
+ }
117
+
118
+ .global-filter-bar-label {
119
+ opacity: 0.6;
120
+ pointer-events: none;
121
+ }
122
+
123
+ .global-filter-bar-chips {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 4px;
127
+ min-width: 0;
128
+ overflow: hidden;
129
+ }
130
+
131
+ .global-filter-chip {
132
+ display: inline-flex;
133
+ align-items: center;
134
+ gap: 4px;
135
+ padding: 1px 4px 1px 6px;
136
+ background: var(--psp--background-color, #ffffff);
137
+ border: 1px solid var(--psp-inactive--color, #c8ccd0);
138
+ border-radius: 3px;
139
+ white-space: nowrap;
140
+ }
141
+
142
+ .global-filter-chip-remove {
143
+ cursor: pointer;
144
+ opacity: 0.5;
145
+ font-size: 13px;
146
+ line-height: 1;
147
+ }
148
+
149
+ .global-filter-chip-remove:hover {
150
+ opacity: 1;
151
+ }
152
+
153
+ .global-filter-bar-clear {
154
+ cursor: pointer;
155
+ opacity: 0.6;
156
+ }
157
+
158
+ .global-filter-bar-clear:hover {
159
+ opacity: 1;
160
+ }
161
+ }
162
+
169
163
  span {
170
164
  white-space: nowrap;
171
165
  margin: 0px 14px;
@@ -243,8 +237,8 @@
243
237
  align-items: center;
244
238
  display: flex;
245
239
  padding-right: 17px;
246
- height: var(--psp-status-bar--height, 48px);
247
- min-height: var(--psp-status-bar--height, 48px);
240
+ height: var(--psp-status-bar--height, 38px);
241
+ min-height: var(--psp-status-bar--height, 38px);
248
242
  }
249
243
 
250
244
  .error-dialog-stack {
@@ -16,10 +16,6 @@
16
16
  --psp--color: #ff0000;
17
17
  }
18
18
 
19
- /* Shift-key affordance: while the user holds Shift, any mask-image icon
20
- * tagged `.shift-alt-icon` recolors to advertise that a Shift-modified
21
- * action is available on the underlying control. `!important` is required
22
- * to beat per-icon ID-scoped `background-color` rules. */
23
19
  :host(.shift-active) .shift-alt-icon {
24
20
  background-color: var(
25
21
  --shift-active--color,
@@ -93,8 +89,44 @@
93
89
  pointer-events: var(--override-content-pointer-events);
94
90
  }
95
91
 
92
+ ::slotted(:not([slot^="statusbar-extra"]):not([slot^="tab-"])) {
93
+ position: absolute;
94
+ inset: 0;
95
+ background-color: var(--psp--background-color) !important;
96
+ box-shadow:
97
+ 2.25px 2.25px 0 2.25px var(--psp--background-color),
98
+ /* down-right */ -2.25px 2.25px 0 2.25px var(--psp--background-color),
99
+ /* down-left */ 2.75px 2.75px 0 2.75px var(--psp-inactive--color),
100
+ -1.75px 2.75px 0 2.75px var(--psp-inactive--color);
101
+ }
102
+
103
+ .overlay ::slotted(:not([slot^="statusbar-extra"]):not([slot^="tab-"])) {
104
+ box-shadow:
105
+ 2.25px 2.25px 0 2.25px var(--psp--background-color),
106
+ -2.25px 2.25px 0 2.25px var(--psp--background-color),
107
+ 2.75px 2.75px 0 2.75px var(--psp-inactive--color),
108
+ -2.75px 2.75px 0 2.75px var(--psp-inactive--color);
109
+ }
110
+
111
+ ::slotted([part="tab"].visible) {
112
+ box-shadow:
113
+ 2.25px -2.25px 0 2.25px var(--psp--background-color),
114
+ -2.25px -2.25px 0 2.25px var(--psp--background-color),
115
+ 3.5px -2.25px 0 2.25px var(--psp-inactive--color),
116
+ 0 12.5px 0 -11.5px var(--psp-inactive--border-color);
117
+ }
118
+
119
+ .overlay ::slotted([part="tab"].visible) {
120
+ box-shadow:
121
+ 2.25px -2.25px 0 2.25px var(--psp--background-color),
122
+ -2.25px -2.25px 0 2.25px var(--psp--background-color),
123
+ 2.75px -2.75px 0 2.75px var(--psp-inactive--color),
124
+ -2.75px -2.75px 0 2.75px var(--psp-inactive--color),
125
+ 0 12.5px 0 -11.5px var(--psp-inactive--border-color);
126
+ }
127
+
96
128
  :host input[type="number"]::-webkit-inner-spin-button {
97
- transform: scale(1.5) translateX(-5px); /* Makes the arrows 50% larger */
129
+ transform: scale(1.5) translateX(-5px);
98
130
  filter: var(--psp-input--filter);
99
131
  }
100
132
 
@@ -105,7 +137,7 @@
105
137
  (
106
138
  var(
107
139
  --psp-plugin-selector--height,
108
- var(--psp-status-bar--height, 48px)
140
+ var(--psp-status-bar--height, 38px)
109
141
  ) -
110
142
  20px
111
143
  ) /
@@ -115,7 +147,7 @@
115
147
  (
116
148
  var(
117
149
  --psp-plugin-selector--height,
118
- var(--psp-status-bar--height, 48px)
150
+ var(--psp-status-bar--height, 38px)
119
151
  ) -
120
152
  20px
121
153
  ) /
@@ -124,7 +156,7 @@
124
156
  z-index: 10000;
125
157
  height: var(
126
158
  --psp-plugin-selector--height,
127
- var(--psp-status-bar--height, 48px)
159
+ var(--psp-status-bar--height, 38px)
128
160
  );
129
161
 
130
162
  &:hover {
@@ -212,11 +244,6 @@
212
244
  #menu-bar {
213
245
  opacity: 1 !important;
214
246
  }
215
-
216
- #component_container #settings_button,
217
- #component_container #settings_button.titled {
218
- opacity: 1;
219
- }
220
247
  }
221
248
 
222
249
  :host {
@@ -241,6 +268,14 @@
241
268
  flex-direction: column;
242
269
  }
243
270
 
271
+ #layout_area {
272
+ flex: 1 1 auto;
273
+ position: relative;
274
+ min-height: 0;
275
+ display: flex;
276
+ overflow: hidden;
277
+ }
278
+
244
279
  #app_panel {
245
280
  position: absolute;
246
281
  bottom: 0px;
@@ -274,7 +309,7 @@
274
309
  }
275
310
 
276
311
  #status_bar {
277
- height: var(--psp-status-bar--height, 48px);
312
+ height: var(--psp-status-bar--height, 38px);
278
313
  }
279
314
 
280
315
  #main_column_container {
@@ -297,15 +332,142 @@
297
332
  }
298
333
 
299
334
  #main_panel_container {
335
+ z-index: 0;
300
336
  position: relative;
301
337
  height: 100%;
302
338
  box-shadow: var(--plugin--box-shadow, none);
339
+ overflow: hidden;
340
+ border: var(--psp-plugin--border, none);
303
341
  background: var(
304
342
  --psp-main-column--background,
305
343
  var(--psp--background-color, none)
306
344
  );
307
- overflow: hidden;
308
- border: var(--psp-plugin--border, none);
345
+
346
+ /* A STAGED panel's hidden staging wrapper (`MainPanel::render` +
347
+ `Workspace::stage_panel`): a freshly-created panel's plugin
348
+ completes its first draw here, laid out at predicted final size
349
+ but unpainted. `visibility` (not `display`) so the plugin keeps a
350
+ real box and a non-null `offsetParent` — draw guards, redraw
351
+ subscriptions and observers behave exactly as for a visible
352
+ panel. */
353
+ & > .psp-staging {
354
+ position: absolute;
355
+ top: 0;
356
+ left: 0;
357
+ overflow: hidden;
358
+ visibility: hidden;
359
+ pointer-events: none;
360
+ }
361
+
362
+ & > .psp-staging ::slotted(*) {
363
+ display: block;
364
+ width: 100%;
365
+ height: 100%;
366
+ }
367
+
368
+ /* The layout engine hosting this panel's plugin fills the container. */
369
+ & regular-layout {
370
+ position: absolute;
371
+ inset: -4px -4px -4px -4px;
372
+ box-sizing: border-box;
373
+ padding: 0px;
374
+ background: var(--psp--background-color, transparent);
375
+
376
+ & > .rl-panel {
377
+ position: relative;
378
+ box-sizing: border-box;
379
+ background: none;
380
+ border: 1px solid transparent;
381
+ margin: var(--psp-panel--margin, 4px);
382
+ }
383
+
384
+ & > .rl-panel::part(container) {
385
+ position: relative;
386
+ background: var(--psp--background-color);
387
+ /* box-shadow: 0 0 0 4.5px var(--psp--background-color); */
388
+ }
389
+
390
+ & > .rl-panel::part(titlebar-track) {
391
+ gap: 10px;
392
+ }
393
+
394
+ & > .rl-panel::part(titlebar) {
395
+ display: flex;
396
+ align-items: stretch;
397
+ height: var(--psp-panel-titlebar--height, 26px);
398
+ font-family: var(--button--font-family, inherit);
399
+ overflow: visible;
400
+ }
401
+
402
+ & > .rl-panel::part(tab) {
403
+ display: flex;
404
+ flex: 1 1 auto;
405
+ align-items: center;
406
+ min-width: 0;
407
+ padding: 0 8px;
408
+ cursor: pointer;
409
+ font-size: 11px;
410
+ white-space: nowrap;
411
+ color: var(--psp--color, inherit);
412
+ background: var(--psp--background-color, #ffffff);
413
+ }
414
+
415
+ & > .rl-panel::part(title) {
416
+ overflow: hidden;
417
+ text-overflow: ellipsis;
418
+ }
419
+
420
+ & > .rl-panel::part(close) {
421
+ flex: 0 0 auto;
422
+ align-self: center;
423
+ display: flex;
424
+ align-items: center;
425
+ justify-content: center;
426
+ width: 16px;
427
+ height: 16px;
428
+ margin: 0 4px;
429
+ border: none;
430
+ background: none;
431
+ cursor: pointer;
432
+ opacity: 0.6;
433
+ color: inherit;
434
+ }
435
+
436
+ & > .rl-panel::part(close):hover {
437
+ opacity: 1;
438
+ }
439
+
440
+ & > .rl-panel::part(close):before {
441
+ content: "×";
442
+ font-size: 14px;
443
+ line-height: 1;
444
+ }
445
+
446
+ & > .rl-panel.single::part(close) {
447
+ display: none;
448
+ }
449
+
450
+ &:has(.overlay) > * {
451
+ opacity: 0.7;
452
+ }
453
+
454
+ &:has(.overlay) > .overlay {
455
+ opacity: 1;
456
+ }
457
+
458
+ & > .overlay {
459
+ /* background: var(
460
+ --psp-panel-overlay--background,
461
+ rgba(26, 125, 161, 0.15)
462
+ ); */
463
+
464
+ transition:
465
+ top 0.1s ease-in-out,
466
+ left 0.1s ease-in-out,
467
+ width 0.1s ease-in-out,
468
+ height 0.1s ease-in-out;
469
+ }
470
+ }
309
471
  }
310
472
 
311
473
  #settings_panel {
@@ -367,15 +529,6 @@
367
529
  border-right-width: 0px;
368
530
  }
369
531
 
370
- #component_container > #settings_button {
371
- opacity: 0;
372
- position: absolute;
373
- top: 0;
374
- right: 0;
375
- margin: var(--settings-button--margin, 10px 36px 0 0);
376
- padding: 0;
377
- }
378
-
379
532
  #close_button {
380
533
  background-color: var(--psp--background-color);
381
534
  padding: 0px;
@@ -388,7 +541,6 @@
388
541
  border-radius: 5px;
389
542
  font-size: 10px;
390
543
  font-weight: normal;
391
-
392
544
  &:hover {
393
545
  color: var(--psp--background-color, inherit);
394
546
  background-color: var(--psp--color);
@@ -415,49 +567,6 @@
415
567
  }
416
568
  }
417
569
 
418
- #settings_button {
419
- background-color: var(--psp--background-color);
420
- padding: 0;
421
- overflow: hidden;
422
- display: flex;
423
- align-items: center;
424
- justify-content: center;
425
- z-index: 3;
426
- border: 1px solid var(--psp-inactive--color);
427
- border-radius: 5px;
428
- font-size: 10px;
429
- font-weight: normal;
430
-
431
- &:hover {
432
- color: var(--psp--background-color, inherit);
433
- background-color: var(--psp--color);
434
- cursor: pointer;
435
- }
436
-
437
- &:hover .icon {
438
- background-color: var(--psp--background-color);
439
- }
440
-
441
- .icon {
442
- display: inline-flex;
443
- mask-size: cover;
444
- -webkit-mask-size: cover;
445
- background-repeat: no-repeat;
446
- background-color: var(--psp--color);
447
- mask-image: var(--psp-icon--drawer-tab-inverted--mask-image);
448
- -webkit-mask-image: var(
449
- --psp-icon--drawer-tab-inverted--mask-image
450
- );
451
-
452
- &:before {
453
- line-height: 0;
454
- display: inline-flex;
455
- content: var(--psp-icon--drawer-tab-inverted--mask-image);
456
- visibility: hidden;
457
- }
458
- }
459
- }
460
-
461
570
  .settings_tab_bar_scroll_offset {
462
571
  margin-left: -8px;
463
572
  }
@@ -506,10 +615,11 @@
506
615
  min-height: calc(
507
616
  var(
508
617
  --psp-plugin-selector--height,
509
- var(--psp-status-bar--height, 48px)
618
+ var(--psp-status-bar--height, 38px)
510
619
  ) +
511
620
  1px
512
621
  );
622
+ z-index: 7;
513
623
  overflow: hidden;
514
624
  display: flex;
515
625
  flex-direction: column;
@@ -70,50 +70,60 @@ impl ColumnDropDownElement {
70
70
  callback: Callback<InPlaceColumn>,
71
71
  ) -> Option<()> {
72
72
  let input = target.value();
73
- let metadata = self.session.metadata();
74
- let mut values: Vec<InPlaceColumn> = vec![];
75
73
  let small_input = input.to_lowercase();
76
- for col in metadata.get_table_columns()? {
77
- if !exclude.contains(col) && col.to_lowercase().contains(&small_input) {
78
- values.push(InPlaceColumn::Column(col.to_owned()));
74
+ let mut values: Vec<InPlaceColumn> = vec![];
75
+ {
76
+ let metadata = self.session.metadata();
77
+ for col in metadata.get_table_columns()? {
78
+ if !exclude.contains(col) && col.to_lowercase().contains(&small_input) {
79
+ values.push(InPlaceColumn::Column(col.to_owned()));
80
+ }
79
81
  }
80
- }
81
82
 
82
- for col in self.session.metadata().get_expression_columns() {
83
- if !exclude.contains(col) && col.to_lowercase().contains(&small_input) {
84
- values.push(InPlaceColumn::Column(col.to_owned()));
83
+ for col in metadata.get_expression_columns() {
84
+ if !exclude.contains(col) && col.to_lowercase().contains(&small_input) {
85
+ values.push(InPlaceColumn::Column(col.to_owned()));
86
+ }
85
87
  }
86
88
  }
87
89
 
88
- clone!(self.state, self.session, self.notify);
89
- let target_elem: HtmlElement = target.clone().into();
90
90
  let width = target.get_bounding_client_rect().width();
91
- ApiFuture::spawn(async move {
92
- if !exclude.contains(&input) {
91
+ let target_elem: HtmlElement = target.clone().into();
92
+
93
+ // Publish the synchronous matches immediately, *before* any async
94
+ // work, so the dropdown and `item_select` always reflect the latest
95
+ // keystroke rather than whichever async continuation happens to
96
+ // resolve last.
97
+ {
98
+ let mut s = self.state.borrow_mut();
99
+ s.values = values;
100
+ s.selected = 0;
101
+ s.width = width;
102
+ s.on_select = Some(callback);
103
+ s.target = Some(target_elem);
104
+ s.no_results = s.values.is_empty();
105
+ }
106
+ self.notify.emit(());
107
+
108
+ if !exclude.contains(&input) {
109
+ clone!(self.state, self.session, self.notify);
110
+ ApiFuture::spawn(async move {
93
111
  let is_expr = crate::queries::validate_expr(&session, &input)
94
112
  .await?
95
113
  .is_none();
96
- if is_expr {
97
- values.push(InPlaceColumn::Expression(Expression::new(
114
+ if is_expr && target.value() == input {
115
+ let mut s = state.borrow_mut();
116
+ s.values.push(InPlaceColumn::Expression(Expression::new(
98
117
  None,
99
118
  input.into(),
100
119
  )));
120
+ s.no_results = false;
121
+ drop(s);
122
+ notify.emit(());
101
123
  }
102
- }
103
-
104
- let no_results = values.is_empty();
105
- {
106
- let mut s = state.borrow_mut();
107
- s.values = values;
108
- s.selected = 0;
109
- s.width = width;
110
- s.on_select = Some(callback);
111
- s.target = Some(target_elem);
112
- s.no_results = no_results;
113
- }
114
- notify.emit(());
115
- Ok(())
116
- });
124
+ Ok(())
125
+ });
126
+ }
117
127
 
118
128
  Some(())
119
129
  }
@@ -13,7 +13,6 @@
13
13
  use std::collections::HashSet;
14
14
 
15
15
  use perspective_client::config::*;
16
- use perspective_js::utils::ApiFuture;
17
16
  use web_sys::*;
18
17
  use yew::prelude::*;
19
18
 
@@ -28,6 +27,7 @@ use crate::presentation::{ColumnLocator, Presentation};
28
27
  use crate::queries::*;
29
28
  use crate::renderer::*;
30
29
  use crate::session::*;
30
+ use crate::tasks::apply_and_render;
31
31
  use crate::utils::*;
32
32
 
33
33
  #[derive(Clone, Properties)]
@@ -162,11 +162,8 @@ impl Component for ActiveColumn {
162
162
  {
163
163
  let session = ctx.props().session.clone();
164
164
  let renderer = ctx.props().renderer.clone();
165
- if session.update_view_config(update).is_ok() {
166
- ApiFuture::spawn(async move {
167
- renderer.apply_pending_plugin()?;
168
- renderer.draw(session.validate().await?.create_view()).await
169
- });
165
+ if let Ok(task) = apply_and_render(&session, &renderer, update) {
166
+ spawn_owned("active-column", task);
170
167
  }
171
168
  }
172
169
 
@@ -190,11 +187,8 @@ impl Component for ActiveColumn {
190
187
  {
191
188
  let session = ctx.props().session.clone();
192
189
  let renderer = ctx.props().renderer.clone();
193
- if session.update_view_config(update).is_ok() {
194
- ApiFuture::spawn(async move {
195
- renderer.apply_pending_plugin()?;
196
- renderer.draw(session.validate().await?.create_view()).await
197
- });
190
+ if let Ok(task) = apply_and_render(&session, &renderer, update) {
191
+ spawn_owned("active-column", task);
198
192
  }
199
193
  }
200
194
 
@@ -477,13 +471,8 @@ impl ActiveColumnProps {
477
471
  ..ViewConfigUpdate::default()
478
472
  };
479
473
 
480
- if self.session.update_view_config(config).is_ok() {
481
- let session = self.session.clone();
482
- let renderer = self.renderer.clone();
483
- ApiFuture::spawn(async move {
484
- renderer.apply_pending_plugin()?;
485
- renderer.draw(session.validate().await?.create_view()).await
486
- });
474
+ if let Ok(task) = apply_and_render(&self.session, &self.renderer, config) {
475
+ spawn_owned("active-column", task);
487
476
  }
488
477
  }
489
478
  }