@perspective-dev/viewer 4.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 (394) hide show
  1. package/LICENSE.md +193 -0
  2. package/README.md +4 -0
  3. package/dist/cdn/perspective-viewer.js +3 -0
  4. package/dist/cdn/perspective-viewer.js.map +7 -0
  5. package/dist/css/dracula.css +1 -0
  6. package/dist/css/gruvbox-dark.css +1 -0
  7. package/dist/css/gruvbox.css +1 -0
  8. package/dist/css/icons.css +1 -0
  9. package/dist/css/intl/de.css +1 -0
  10. package/dist/css/intl/es.css +1 -0
  11. package/dist/css/intl/fr.css +1 -0
  12. package/dist/css/intl/ja.css +1 -0
  13. package/dist/css/intl/pt.css +1 -0
  14. package/dist/css/intl/zh.css +1 -0
  15. package/dist/css/intl.css +1 -0
  16. package/dist/css/monokai.css +1 -0
  17. package/dist/css/pro-dark.css +1 -0
  18. package/dist/css/pro.css +1 -0
  19. package/dist/css/solarized-dark.css +1 -0
  20. package/dist/css/solarized.css +1 -0
  21. package/dist/css/themes.css +1 -0
  22. package/dist/css/vaporwave.css +1 -0
  23. package/dist/css/variables.css +0 -0
  24. package/dist/esm/bootstrap.d.ts +1 -0
  25. package/dist/esm/extensions.d.ts +70 -0
  26. package/dist/esm/perspective-viewer.d.ts +39 -0
  27. package/dist/esm/perspective-viewer.inline.js +3 -0
  28. package/dist/esm/perspective-viewer.inline.js.map +7 -0
  29. package/dist/esm/perspective-viewer.js +3 -0
  30. package/dist/esm/perspective-viewer.js.map +7 -0
  31. package/dist/esm/plugin.d.ts +195 -0
  32. package/dist/esm/ts-rs/Aggregate.d.ts +1 -0
  33. package/dist/esm/ts-rs/ColumnConfigValues.d.ts +31 -0
  34. package/dist/esm/ts-rs/CustomDatetimeFormat.d.ts +1 -0
  35. package/dist/esm/ts-rs/CustomDatetimeStyleConfig.d.ts +15 -0
  36. package/dist/esm/ts-rs/CustomNumberFormatConfig.d.ts +18 -0
  37. package/dist/esm/ts-rs/DatetimeColorMode.d.ts +1 -0
  38. package/dist/esm/ts-rs/DatetimeFormatType.d.ts +6 -0
  39. package/dist/esm/ts-rs/Expressions.d.ts +3 -0
  40. package/dist/esm/ts-rs/Filter.d.ts +2 -0
  41. package/dist/esm/ts-rs/FilterReducer.d.ts +1 -0
  42. package/dist/esm/ts-rs/FilterTerm.d.ts +2 -0
  43. package/dist/esm/ts-rs/FormatMode.d.ts +1 -0
  44. package/dist/esm/ts-rs/FormatUnit.d.ts +1 -0
  45. package/dist/esm/ts-rs/NumberBackgroundMode.d.ts +1 -0
  46. package/dist/esm/ts-rs/NumberForegroundMode.d.ts +1 -0
  47. package/dist/esm/ts-rs/OptionalUpdate.d.ts +1 -0
  48. package/dist/esm/ts-rs/PluginConfig.d.ts +2 -0
  49. package/dist/esm/ts-rs/RoundingMode.d.ts +1 -0
  50. package/dist/esm/ts-rs/RoundingPriority.d.ts +1 -0
  51. package/dist/esm/ts-rs/Scalar.d.ts +5 -0
  52. package/dist/esm/ts-rs/SignDisplay.d.ts +1 -0
  53. package/dist/esm/ts-rs/SimpleDatetimeFormat.d.ts +1 -0
  54. package/dist/esm/ts-rs/SimpleDatetimeStyleConfig.d.ts +6 -0
  55. package/dist/esm/ts-rs/Sort.d.ts +2 -0
  56. package/dist/esm/ts-rs/SortDir.d.ts +1 -0
  57. package/dist/esm/ts-rs/StringColorMode.d.ts +1 -0
  58. package/dist/esm/ts-rs/TrailingZeroDisplay.d.ts +1 -0
  59. package/dist/esm/ts-rs/UseGrouping.d.ts +1 -0
  60. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +102 -0
  61. package/dist/esm/ts-rs/serde_json/JsonValue.d.ts +3 -0
  62. package/dist/wasm/perspective-viewer.d.ts +1291 -0
  63. package/dist/wasm/perspective-viewer.js +3883 -0
  64. package/dist/wasm/perspective-viewer.wasm +0 -0
  65. package/dist/wasm/perspective-viewer.wasm.d.ts +142 -0
  66. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline0.js +1 -0
  67. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline1.js +1 -0
  68. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline2.js +1 -0
  69. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline3.js +44 -0
  70. package/dist/wasm/snippets/perspective-viewer-c69283f6f62a5f14/inline4.js +1 -0
  71. package/package.json +55 -0
  72. package/src/less/aggregate-selector.less +72 -0
  73. package/src/less/column-dropdown.less +95 -0
  74. package/src/less/column-selector.less +551 -0
  75. package/src/less/column-settings-panel.less +255 -0
  76. package/src/less/column-style.less +319 -0
  77. package/src/less/column-symbol-attributes.less +73 -0
  78. package/src/less/config-selector.less +363 -0
  79. package/src/less/containers/dropdown-menu.less +94 -0
  80. package/src/less/containers/pairs-list.less +46 -0
  81. package/src/less/containers/radio-list.less +29 -0
  82. package/src/less/containers/scroll-panel.less +27 -0
  83. package/src/less/containers/split-panel.less +80 -0
  84. package/src/less/containers/tabs.less +90 -0
  85. package/src/less/dom/checkbox.less +100 -0
  86. package/src/less/dom/scrollbar.less +35 -0
  87. package/src/less/dom/select.less +63 -0
  88. package/src/less/empty-column.less +72 -0
  89. package/src/less/expression-editor.less +152 -0
  90. package/src/less/filter-dropdown.less +53 -0
  91. package/src/less/filter-item.less +126 -0
  92. package/src/less/form/code-editor.less +137 -0
  93. package/src/less/form/debug.less +88 -0
  94. package/src/less/function-dropdown.less +45 -0
  95. package/src/less/plugin-selector.less +173 -0
  96. package/src/less/render-warning.less +81 -0
  97. package/src/less/status-bar.less +551 -0
  98. package/src/less/type-icon.less +68 -0
  99. package/src/less/viewer.less +368 -0
  100. package/src/rust/components/column_dropdown.rs +162 -0
  101. package/src/rust/components/column_selector/active_column.rs +462 -0
  102. package/src/rust/components/column_selector/add_expression_button.rs +59 -0
  103. package/src/rust/components/column_selector/aggregate_selector.rs +186 -0
  104. package/src/rust/components/column_selector/config_selector.rs +674 -0
  105. package/src/rust/components/column_selector/empty_column.rs +134 -0
  106. package/src/rust/components/column_selector/expression_toolbar.rs +45 -0
  107. package/src/rust/components/column_selector/filter_column.rs +530 -0
  108. package/src/rust/components/column_selector/inactive_column.rs +221 -0
  109. package/src/rust/components/column_selector/invalid_column.rs +37 -0
  110. package/src/rust/components/column_selector/pivot_column.rs +93 -0
  111. package/src/rust/components/column_selector/sort_column.rs +135 -0
  112. package/src/rust/components/column_selector.rs +426 -0
  113. package/src/rust/components/column_settings_sidebar/attributes_tab.rs +34 -0
  114. package/src/rust/components/column_settings_sidebar/mod.rs +17 -0
  115. package/src/rust/components/column_settings_sidebar/save_settings.rs +68 -0
  116. package/src/rust/components/column_settings_sidebar/sidebar.rs +396 -0
  117. package/src/rust/components/column_settings_sidebar/style_tab/column_style.rs +177 -0
  118. package/src/rust/components/column_settings_sidebar/style_tab/stub.rs +34 -0
  119. package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +101 -0
  120. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_config.rs +24 -0
  121. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +185 -0
  122. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_selector.rs +55 -0
  123. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +131 -0
  124. package/src/rust/components/column_settings_sidebar/style_tab.rs +231 -0
  125. package/src/rust/components/containers/dragdrop_list.rs +325 -0
  126. package/src/rust/components/containers/dropdown_menu.rs +104 -0
  127. package/src/rust/components/containers/kvpair.rs +47 -0
  128. package/src/rust/components/containers/mod.rs +28 -0
  129. package/src/rust/components/containers/scroll_panel.rs +311 -0
  130. package/src/rust/components/containers/scroll_panel_item.rs +111 -0
  131. package/src/rust/components/containers/select.rs +269 -0
  132. package/src/rust/components/containers/sidebar.rs +89 -0
  133. package/src/rust/components/containers/split_panel.rs +483 -0
  134. package/src/rust/components/containers/tab_list.rs +104 -0
  135. package/src/rust/components/containers/tests/mod.rs +11 -0
  136. package/src/rust/components/containers/tests/split_panel.rs +91 -0
  137. package/src/rust/components/containers/trap_door_panel.rs +50 -0
  138. package/src/rust/components/copy_dropdown.rs +136 -0
  139. package/src/rust/components/datetime_column_style/custom.rs +222 -0
  140. package/src/rust/components/datetime_column_style/simple.rs +122 -0
  141. package/src/rust/components/datetime_column_style.rs +284 -0
  142. package/src/rust/components/editable_header.rs +183 -0
  143. package/src/rust/components/empty_row.rs +169 -0
  144. package/src/rust/components/error_message.rs +56 -0
  145. package/src/rust/components/export_dropdown.rs +153 -0
  146. package/src/rust/components/expression_editor.rs +153 -0
  147. package/src/rust/components/filter_dropdown.rs +144 -0
  148. package/src/rust/components/font_loader.rs +254 -0
  149. package/src/rust/components/form/code_editor.rs +286 -0
  150. package/src/rust/components/form/color_range_selector.rs +115 -0
  151. package/src/rust/components/form/color_selector.rs +54 -0
  152. package/src/rust/components/form/debug.rs +253 -0
  153. package/src/rust/components/form/highlight.rs +50 -0
  154. package/src/rust/components/form/mod.rs +29 -0
  155. package/src/rust/components/form/number_field.rs +72 -0
  156. package/src/rust/components/form/number_input.rs +45 -0
  157. package/src/rust/components/form/number_range_field.rs +77 -0
  158. package/src/rust/components/form/optional_field.rs +53 -0
  159. package/src/rust/components/form/select_field.rs +104 -0
  160. package/src/rust/components/function_dropdown.rs +151 -0
  161. package/src/rust/components/mod.rs +45 -0
  162. package/src/rust/components/modal.rs +171 -0
  163. package/src/rust/components/number_column_style.rs +522 -0
  164. package/src/rust/components/plugin_selector.rs +196 -0
  165. package/src/rust/components/render_warning.rs +178 -0
  166. package/src/rust/components/status_bar.rs +315 -0
  167. package/src/rust/components/status_bar_counter.rs +229 -0
  168. package/src/rust/components/status_indicator.rs +164 -0
  169. package/src/rust/components/string_column_style.rs +186 -0
  170. package/src/rust/components/style/local_style.rs +35 -0
  171. package/src/rust/components/style/mod.rs +52 -0
  172. package/src/rust/components/style/style_cache.rs +132 -0
  173. package/src/rust/components/style/style_provider.rs +65 -0
  174. package/src/rust/components/style_controls/number_string_format/digits_section.rs +140 -0
  175. package/src/rust/components/style_controls/number_string_format/misc_section.rs +56 -0
  176. package/src/rust/components/style_controls/number_string_format/style_section.rs +69 -0
  177. package/src/rust/components/style_controls/number_string_format/types.rs +31 -0
  178. package/src/rust/components/style_controls/number_string_format.rs +259 -0
  179. package/src/rust/components/style_controls.rs +15 -0
  180. package/src/rust/components/type_icon.rs +53 -0
  181. package/src/rust/components/viewer.rs +668 -0
  182. package/src/rust/config/columns_config.rs +132 -0
  183. package/src/rust/config/datetime_column_style/color_mode.rs +62 -0
  184. package/src/rust/config/datetime_column_style/custom.rs +121 -0
  185. package/src/rust/config/datetime_column_style/custom_format.rs +90 -0
  186. package/src/rust/config/datetime_column_style/simple.rs +55 -0
  187. package/src/rust/config/datetime_column_style/simple_format.rs +86 -0
  188. package/src/rust/config/datetime_column_style.rs +104 -0
  189. package/src/rust/config/mod.rs +30 -0
  190. package/src/rust/config/number_column_style.rs +138 -0
  191. package/src/rust/config/number_string_format/enums.rs +298 -0
  192. package/src/rust/config/number_string_format.rs +269 -0
  193. package/src/rust/config/string_column_style.rs +140 -0
  194. package/src/rust/config/view_config.rs +24 -0
  195. package/src/rust/config/viewer_config.rs +337 -0
  196. package/src/rust/custom_elements/column_dropdown.rs +123 -0
  197. package/src/rust/custom_elements/copy_dropdown.rs +112 -0
  198. package/src/rust/custom_elements/debug_plugin.rs +114 -0
  199. package/src/rust/custom_elements/export_dropdown.rs +112 -0
  200. package/src/rust/custom_elements/filter_dropdown.rs +179 -0
  201. package/src/rust/custom_elements/function_dropdown.rs +115 -0
  202. package/src/rust/custom_elements/mod.rs +24 -0
  203. package/src/rust/custom_elements/modal.rs +395 -0
  204. package/src/rust/custom_elements/viewer.rs +880 -0
  205. package/src/rust/custom_events.rs +214 -0
  206. package/src/rust/dragdrop.rs +362 -0
  207. package/src/rust/exprtk/cursor.rs +81 -0
  208. package/src/rust/exprtk/mod.rs +17 -0
  209. package/src/rust/exprtk/tokenize/comment.rs +21 -0
  210. package/src/rust/exprtk/tokenize/number.rs +44 -0
  211. package/src/rust/exprtk/tokenize/string.rs +98 -0
  212. package/src/rust/exprtk/tokenize/symbol.rs +26 -0
  213. package/src/rust/exprtk/tokenize.rs +190 -0
  214. package/src/rust/js/clipboard.rs +77 -0
  215. package/src/rust/js/clipboard_item.rs +21 -0
  216. package/src/rust/js/intersection_observer.rs +32 -0
  217. package/src/rust/js/mimetype.rs +42 -0
  218. package/src/rust/js/mod.rs +29 -0
  219. package/src/rust/js/plugin.rs +167 -0
  220. package/src/rust/js/resize_observer.rs +37 -0
  221. package/src/rust/js/testing.rs +149 -0
  222. package/src/rust/lib.rs +116 -0
  223. package/src/rust/model/columns_iter_set.rs +340 -0
  224. package/src/rust/model/copy_export.rs +157 -0
  225. package/src/rust/model/create_col.rs +59 -0
  226. package/src/rust/model/edit_expression.rs +95 -0
  227. package/src/rust/model/export_app.rs +58 -0
  228. package/src/rust/model/export_method.rs +151 -0
  229. package/src/rust/model/get_viewer_config.rs +85 -0
  230. package/src/rust/model/intersection_observer.rs +81 -0
  231. package/src/rust/model/is_invalid_drop.rs +36 -0
  232. package/src/rust/model/mod.rs +93 -0
  233. package/src/rust/model/plugin_column_styles.rs +106 -0
  234. package/src/rust/model/resize_observer.rs +98 -0
  235. package/src/rust/model/restore_and_render.rs +113 -0
  236. package/src/rust/model/structural.rs +73 -0
  237. package/src/rust/model/update_and_render.rs +74 -0
  238. package/src/rust/presentation.rs +370 -0
  239. package/src/rust/renderer/activate.rs +49 -0
  240. package/src/rust/renderer/limits.rs +200 -0
  241. package/src/rust/renderer/plugin_store.rs +45 -0
  242. package/src/rust/renderer/registry.rs +135 -0
  243. package/src/rust/renderer/render_timer.rs +185 -0
  244. package/src/rust/renderer.rs +463 -0
  245. package/src/rust/session/column_defaults_update.rs +141 -0
  246. package/src/rust/session/drag_drop_update.rs +179 -0
  247. package/src/rust/session/metadata.rs +308 -0
  248. package/src/rust/session/replace_expression_update.rs +131 -0
  249. package/src/rust/session/view_subscription.rs +189 -0
  250. package/src/rust/session.rs +794 -0
  251. package/src/rust/utils/browser/blob.rs +49 -0
  252. package/src/rust/utils/browser/download.rs +26 -0
  253. package/src/rust/utils/browser/mod.rs +24 -0
  254. package/src/rust/utils/browser/request_animation_frame.rs +76 -0
  255. package/src/rust/utils/browser/selection.rs +79 -0
  256. package/src/rust/utils/browser/tests/debounce.rs +114 -0
  257. package/src/rust/utils/browser/tests/mod.rs +13 -0
  258. package/src/rust/utils/custom_element.rs +85 -0
  259. package/src/rust/utils/datetime.rs +49 -0
  260. package/src/rust/utils/debounce.rs +54 -0
  261. package/src/rust/utils/hooks/mod.rs +15 -0
  262. package/src/rust/utils/hooks/use_async_callback.rs +53 -0
  263. package/src/rust/utils/mod.rs +114 -0
  264. package/src/rust/utils/number_format.rs +48 -0
  265. package/src/rust/utils/pubsub.rs +222 -0
  266. package/src/rust/utils/scope.rs +54 -0
  267. package/src/rust/utils/tee.rs +88 -0
  268. package/src/rust/utils/tests/mod.rs +14 -0
  269. package/src/rust/utils/tests/pubsub.rs +95 -0
  270. package/src/rust/utils/tests/request_animation_frame.rs +42 -0
  271. package/src/rust/utils/wasm_abi.rs +61 -0
  272. package/src/rust/utils/weak_scope.rs +39 -0
  273. package/src/svg/align-scroll-icon.svg +7 -0
  274. package/src/svg/bg-pattern.png +0 -0
  275. package/src/svg/boolean-type.svg +3 -0
  276. package/src/svg/checkbox-checked-icon.svg +7 -0
  277. package/src/svg/checkbox-hover.svg +4 -0
  278. package/src/svg/checkbox-off.svg +4 -0
  279. package/src/svg/checkbox-on.svg +4 -0
  280. package/src/svg/checkbox-unchecked-icon.svg +3 -0
  281. package/src/svg/close-icon.svg +6 -0
  282. package/src/svg/column-settings-icon.svg +6 -0
  283. package/src/svg/datagrid-select-column.svg +15 -0
  284. package/src/svg/datagrid-select-region.svg +15 -0
  285. package/src/svg/datagrid-select-row.svg +13 -0
  286. package/src/svg/datagrid.svg +13 -0
  287. package/src/svg/date-type.svg +23 -0
  288. package/src/svg/downloading.gif +0 -0
  289. package/src/svg/drag-handle.svg +10 -0
  290. package/src/svg/drawer-bg-pattern-hidpi.png +0 -0
  291. package/src/svg/drawer-tab-hover.svg +8 -0
  292. package/src/svg/drawer-tab-invert-hover.svg +9 -0
  293. package/src/svg/drawer-tab-invert.svg +8 -0
  294. package/src/svg/drawer-tab.svg +7 -0
  295. package/src/svg/dropdown-selector-light.svg +3 -0
  296. package/src/svg/dropdown-selector.svg +3 -0
  297. package/src/svg/duplicate-icon.svg +4 -0
  298. package/src/svg/editable-icon.svg +5 -0
  299. package/src/svg/export-icon.svg +4 -0
  300. package/src/svg/expression.svg +10 -0
  301. package/src/svg/free-scroll-icon.svg +5 -0
  302. package/src/svg/inactive-mouseover.svg +4 -0
  303. package/src/svg/mega-menu-icons-candlestick.svg +38 -0
  304. package/src/svg/mega-menu-icons-datagrid.svg +38 -0
  305. package/src/svg/mega-menu-icons-heatmap.svg +60 -0
  306. package/src/svg/mega-menu-icons-map-scatter.svg +43 -0
  307. package/src/svg/mega-menu-icons-ohlc.svg +40 -0
  308. package/src/svg/mega-menu-icons-sunburst.svg +39 -0
  309. package/src/svg/mega-menu-icons-treemap.svg +44 -0
  310. package/src/svg/mega-menu-icons-x-bar.svg +36 -0
  311. package/src/svg/mega-menu-icons-x-y-line.svg +38 -0
  312. package/src/svg/mega-menu-icons-x-y-scatter.svg +72 -0
  313. package/src/svg/mega-menu-icons-y-area.svg +73 -0
  314. package/src/svg/mega-menu-icons-y-bar.svg +36 -0
  315. package/src/svg/mega-menu-icons-y-line.svg +36 -0
  316. package/src/svg/mega-menu-icons-y-scatter.svg +72 -0
  317. package/src/svg/number-type.svg +4 -0
  318. package/src/svg/radio-hover.svg +4 -0
  319. package/src/svg/radio-off.svg +3 -0
  320. package/src/svg/radio-on.svg +4 -0
  321. package/src/svg/read-only-icon.svg +6 -0
  322. package/src/svg/revert-icon.svg +4 -0
  323. package/src/svg/sort-abs-asc-icon.svg +3 -0
  324. package/src/svg/sort-abs-col-asc-icon.svg +3 -0
  325. package/src/svg/sort-abs-col-desc-icon.svg +3 -0
  326. package/src/svg/sort-abs-desc-icon.svg +3 -0
  327. package/src/svg/sort-asc-icon.svg +4 -0
  328. package/src/svg/sort-col-asc-icon.svg +4 -0
  329. package/src/svg/sort-col-desc-icon.svg +4 -0
  330. package/src/svg/sort-desc-icon.svg +4 -0
  331. package/src/svg/sort-none-icon.svg +3 -0
  332. package/src/svg/status_error.svg +70 -0
  333. package/src/svg/status_ok.svg +26 -0
  334. package/src/svg/string-type.svg +8 -0
  335. package/src/svg/theme-icon.svg +5 -0
  336. package/src/svg/updating.gif +0 -0
  337. package/src/themes/dracula.less +101 -0
  338. package/src/themes/gruvbox-dark.less +116 -0
  339. package/src/themes/gruvbox.less +152 -0
  340. package/src/themes/icons.less +130 -0
  341. package/src/themes/intl/de.less +102 -0
  342. package/src/themes/intl/es.less +102 -0
  343. package/src/themes/intl/fr.less +102 -0
  344. package/src/themes/intl/ja.less +102 -0
  345. package/src/themes/intl/pt.less +102 -0
  346. package/src/themes/intl/zh.less +102 -0
  347. package/src/themes/intl.less +102 -0
  348. package/src/themes/monokai.less +107 -0
  349. package/src/themes/pro-dark.less +147 -0
  350. package/src/themes/pro.less +186 -0
  351. package/src/themes/solarized-dark.less +78 -0
  352. package/src/themes/solarized.less +102 -0
  353. package/src/themes/themes.less +21 -0
  354. package/src/themes/vaporwave.less +145 -0
  355. package/src/themes/variables.less +24 -0
  356. package/src/ts/bootstrap.ts +26 -0
  357. package/src/ts/extensions.ts +124 -0
  358. package/src/ts/perspective-viewer.cdn.ts +19 -0
  359. package/src/ts/perspective-viewer.inline.ts +23 -0
  360. package/src/ts/perspective-viewer.ts +59 -0
  361. package/src/ts/plugin.ts +279 -0
  362. package/src/ts/ts-rs/Aggregate.ts +3 -0
  363. package/src/ts/ts-rs/ColumnConfigValues.ts +14 -0
  364. package/src/ts/ts-rs/CustomDatetimeFormat.ts +3 -0
  365. package/src/ts/ts-rs/CustomDatetimeStyleConfig.ts +5 -0
  366. package/src/ts/ts-rs/CustomNumberFormatConfig.ts +8 -0
  367. package/src/ts/ts-rs/DatetimeColorMode.ts +3 -0
  368. package/src/ts/ts-rs/DatetimeFormatType.ts +8 -0
  369. package/src/ts/ts-rs/Expressions.ts +3 -0
  370. package/src/ts/ts-rs/Filter.ts +4 -0
  371. package/src/ts/ts-rs/FilterReducer.ts +3 -0
  372. package/src/ts/ts-rs/FilterTerm.ts +4 -0
  373. package/src/ts/ts-rs/FormatMode.ts +3 -0
  374. package/src/ts/ts-rs/FormatUnit.ts +3 -0
  375. package/src/ts/ts-rs/NumberBackgroundMode.ts +3 -0
  376. package/src/ts/ts-rs/NumberForegroundMode.ts +3 -0
  377. package/src/ts/ts-rs/OnUpdateData.ts +8 -0
  378. package/src/ts/ts-rs/OptionalUpdate.ts +3 -0
  379. package/src/ts/ts-rs/PluginConfig.ts +4 -0
  380. package/src/ts/ts-rs/RoundingMode.ts +3 -0
  381. package/src/ts/ts-rs/RoundingPriority.ts +3 -0
  382. package/src/ts/ts-rs/Scalar.ts +7 -0
  383. package/src/ts/ts-rs/SignDisplay.ts +3 -0
  384. package/src/ts/ts-rs/SimpleDatetimeFormat.ts +3 -0
  385. package/src/ts/ts-rs/SimpleDatetimeStyleConfig.ts +4 -0
  386. package/src/ts/ts-rs/Sort.ts +4 -0
  387. package/src/ts/ts-rs/SortDir.ts +3 -0
  388. package/src/ts/ts-rs/StringColorMode.ts +3 -0
  389. package/src/ts/ts-rs/TrailingZeroDisplay.ts +3 -0
  390. package/src/ts/ts-rs/UseGrouping.ts +3 -0
  391. package/src/ts/ts-rs/ViewOnUpdateResp.ts +3 -0
  392. package/src/ts/ts-rs/ViewerConfigUpdate.ts +90 -0
  393. package/src/ts/ts-rs/serde_json/JsonValue.ts +3 -0
  394. package/tsconfig.json +15 -0
@@ -0,0 +1,880 @@
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
+
13
+ #![allow(non_snake_case)]
14
+
15
+ use std::cell::RefCell;
16
+ use std::rc::Rc;
17
+ use std::str::FromStr;
18
+
19
+ use ::perspective_js::{Table, View};
20
+ use futures::future::join;
21
+ use js_sys::*;
22
+ use perspective_client::config::ViewConfigUpdate;
23
+ use perspective_js::{JsViewWindow, apierror};
24
+ use wasm_bindgen::JsCast;
25
+ use wasm_bindgen::prelude::*;
26
+ use wasm_bindgen_futures::JsFuture;
27
+ use web_sys::*;
28
+ use yew::prelude::*;
29
+
30
+ use crate::components::viewer::{PerspectiveViewer, PerspectiveViewerMsg, PerspectiveViewerProps};
31
+ use crate::config::*;
32
+ use crate::custom_events::*;
33
+ use crate::dragdrop::*;
34
+ use crate::js::*;
35
+ use crate::model::*;
36
+ use crate::presentation::*;
37
+ use crate::renderer::*;
38
+ use crate::session::Session;
39
+ use crate::utils::*;
40
+ use crate::*;
41
+
42
+ /// The `<perspective-viewer>` custom element.
43
+ ///
44
+ /// # JavaScript Examples
45
+ ///
46
+ /// Create a new `<perspective-viewer>`:
47
+ ///
48
+ /// ```javascript
49
+ /// const viewer = document.createElement("perspective-viewer");
50
+ /// window.body.appendChild(viewer);
51
+ /// ```
52
+ #[derive(Clone)]
53
+ #[wasm_bindgen]
54
+ pub struct PerspectiveViewerElement {
55
+ elem: HtmlElement,
56
+ root: Rc<RefCell<Option<AppHandle<PerspectiveViewer>>>>,
57
+ resize_handle: Rc<RefCell<Option<ResizeObserverHandle>>>,
58
+ intersection_handle: Rc<RefCell<Option<IntersectionObserverHandle>>>,
59
+ session: Session,
60
+ renderer: Renderer,
61
+ presentation: Presentation,
62
+ events: CustomEvents,
63
+ _subscriptions: Rc<Subscription>,
64
+ }
65
+
66
+ derive_model!( Renderer, Session, Presentation for PerspectiveViewerElement);
67
+
68
+ impl CustomElementMetadata for PerspectiveViewerElement {
69
+ const CUSTOM_ELEMENT_NAME: &'static str = "perspective-viewer";
70
+ const STATICS: &'static [&'static str] = ["registerPlugin", "getExprTKCommands"].as_slice();
71
+ }
72
+
73
+ #[wasm_bindgen]
74
+ impl PerspectiveViewerElement {
75
+ #[doc(hidden)]
76
+ #[wasm_bindgen(constructor)]
77
+ pub fn new(elem: web_sys::HtmlElement) -> Self {
78
+ let init = web_sys::ShadowRootInit::new(web_sys::ShadowRootMode::Open);
79
+ let shadow_root = elem
80
+ .attach_shadow(&init)
81
+ .unwrap()
82
+ .unchecked_into::<web_sys::Element>();
83
+
84
+ Self::new_from_shadow(elem, shadow_root)
85
+ }
86
+
87
+ fn new_from_shadow(elem: web_sys::HtmlElement, shadow_root: web_sys::Element) -> Self {
88
+ // Application State
89
+ let session = Session::default();
90
+ let renderer = Renderer::new(&elem);
91
+ let presentation = Presentation::new(&elem);
92
+ let events = CustomEvents::new(&elem, &session, &renderer, &presentation);
93
+
94
+ // Create Yew App
95
+ let props = yew::props!(PerspectiveViewerProps {
96
+ elem: elem.clone(),
97
+ session: session.clone(),
98
+ renderer: renderer.clone(),
99
+ presentation: presentation.clone(),
100
+ dragdrop: DragDrop::default(),
101
+ custom_events: events.clone(),
102
+ weak_link: WeakScope::default(),
103
+ });
104
+
105
+ let root = yew::Renderer::with_root_and_props(shadow_root, props).render();
106
+
107
+ // Create callbacks
108
+ let update_sub = session.table_updated.add_listener({
109
+ clone!(renderer, session);
110
+ move |_| {
111
+ clone!(renderer, session);
112
+ ApiFuture::spawn(async move { renderer.update(&session).await })
113
+ }
114
+ });
115
+
116
+ let resize_handle = ResizeObserverHandle::new(&elem, &renderer, &root);
117
+ Self {
118
+ elem,
119
+ root: Rc::new(RefCell::new(Some(root))),
120
+ session,
121
+ renderer,
122
+ presentation,
123
+ resize_handle: Rc::new(RefCell::new(Some(resize_handle))),
124
+ intersection_handle: Rc::new(RefCell::new(None)),
125
+ events,
126
+ _subscriptions: Rc::new(update_sub),
127
+ }
128
+ }
129
+
130
+ #[doc(hidden)]
131
+ #[wasm_bindgen(js_name = "connectedCallback")]
132
+ pub fn connected_callback(&self) {
133
+ tracing::debug!("Connected <perspective-viewer>");
134
+ }
135
+
136
+ /// Loads a [`Table`] (or rather, a Javascript `Promise` which returns a
137
+ /// [`Table`]) in this viewer.
138
+ ///
139
+ /// When [`PerspectiveViewerElement::load`] resolves, the first frame of the
140
+ /// UI + visualization is guaranteed to have been drawn. Awaiting the result
141
+ /// of this method in a `try`/`catch` block will capture any errors
142
+ /// thrown during the loading process, or from the [`Table`] `Promise`
143
+ /// itself.
144
+ ///
145
+ /// A [`Table`] can be created using the
146
+ /// [`@perspective-dev/client`](https://www.npmjs.com/package/@perspective-dev/client)
147
+ /// library from NPM (see [`perspective_js`] documentation for details).
148
+ ///
149
+ /// # JavaScript Examples
150
+ ///
151
+ /// ```javascript
152
+ /// import perspective from "@perspective-dev/client";
153
+ ///
154
+ /// const worker = await perspective.worker();
155
+ /// viewer.load(worker.table("x,y\n1,2"));
156
+ /// ```
157
+ pub fn load(&self, table: JsValue) -> ApiFuture<()> {
158
+ tracing::info!("Loading Table");
159
+ self.session.invalidate();
160
+ let promise = table
161
+ .clone()
162
+ .dyn_into::<js_sys::Promise>()
163
+ .unwrap_or_else(|_| js_sys::Promise::resolve(&table));
164
+
165
+ self.session.reset_stats();
166
+ let delete_task = self.session.reset(true);
167
+ let mut config = ViewConfigUpdate {
168
+ columns: Some(self.session.get_view_config().columns.clone()),
169
+ ..ViewConfigUpdate::default()
170
+ };
171
+
172
+ self.session
173
+ .set_update_column_defaults(&mut config, &self.renderer.metadata());
174
+
175
+ let update_task = self.session.update_view_config(config);
176
+ clone!(self.renderer, self.session);
177
+ ApiFuture::new(async move {
178
+ let task = async {
179
+ update_task?;
180
+ let jstable = JsFuture::from(promise)
181
+ .await
182
+ .map_err(|x| apierror!(TableError(x)))?;
183
+
184
+ if let Some(table) =
185
+ wasm_bindgen_derive::try_from_js_option::<perspective_js::Table>(jstable)?
186
+ {
187
+ if let Some(existing_table) = session.get_table() {
188
+ if table.get_table() == &existing_table {
189
+ tracing::info!(
190
+ "Table `{}` already loaded, skipping",
191
+ table.get_name().await
192
+ );
193
+
194
+ return Ok(&session);
195
+ } else {
196
+ tracing::debug!(
197
+ "New table {} vs {}",
198
+ table.get_table().get_name(),
199
+ existing_table.get_name()
200
+ );
201
+ }
202
+ }
203
+
204
+ tracing::debug!(
205
+ "Successfully loaded {:.0} rows from Table",
206
+ table.size().await?
207
+ );
208
+
209
+ session.set_table(table.get_table().clone()).await?;
210
+ session.validate().await?.create_view().await
211
+ } else {
212
+ Err(ApiError::new("Invalid Table"))
213
+ }
214
+ };
215
+
216
+ renderer.set_throttle(None);
217
+ let (draw, delete) = join(renderer.draw(task), delete_task).await;
218
+ let result = draw.and(delete);
219
+ if let Err(e) = &result {
220
+ session.set_error(false, e.clone()).await?;
221
+ }
222
+
223
+ result
224
+ })
225
+ }
226
+
227
+ /// Delete the internal [`View`] and all associated state, rendering this
228
+ /// `<perspective-viewer>` unusable and freeing all associated resources.
229
+ /// Does not delete the supplied [`Table`] (as this is constructed by the
230
+ /// callee).
231
+ ///
232
+ /// Calling _any_ method on a `<perspective-viewer>` after [`Self::delete`]
233
+ /// will throw.
234
+ ///
235
+ /// <div class="warning">
236
+ ///
237
+ /// Allowing a `<perspective-viewer>` to be garbage-collected
238
+ /// without calling [`PerspectiveViewerElement::delete`] will leak WASM
239
+ /// memory!
240
+ ///
241
+ /// </div>
242
+ ///
243
+ /// # JavaScript Examples
244
+ ///
245
+ /// ```javascript
246
+ /// await viewer.delete();
247
+ /// ```
248
+ pub fn delete(self) -> ApiFuture<()> {
249
+ clone!(self.renderer, self.session, self.root);
250
+ ApiFuture::new(self.renderer.clone().with_lock(async move {
251
+ renderer.delete()?;
252
+ root.borrow_mut()
253
+ .take()
254
+ .ok_or("Already deleted!")?
255
+ .destroy();
256
+ session.delete().await?;
257
+ tracing::info!("Deleted <perspective-viewer>");
258
+ Ok(())
259
+ }))
260
+ }
261
+
262
+ /// Restart this `<perspective-viewer>` to its initial state, before
263
+ /// `load()`.
264
+ ///
265
+ /// Use `Self::restart` if you plan to call `Self::load` on this viewer
266
+ /// again, or alternatively `Self::delete` if this viewer is no longer
267
+ /// needed.
268
+ pub fn eject(&mut self) -> ApiFuture<()> {
269
+ if self.session.has_table() {
270
+ let mut state = Self::new_from_shadow(
271
+ self.elem.clone(),
272
+ self.elem.shadow_root().unwrap().unchecked_into(),
273
+ );
274
+
275
+ std::mem::swap(self, &mut state);
276
+ state.delete()
277
+ } else {
278
+ ApiFuture::new(async move { Ok(()) })
279
+ }
280
+ }
281
+
282
+ /// Get the underlying [`View`] for this viewer.
283
+ ///
284
+ /// Use this method to get promgrammatic access to the [`View`] as currently
285
+ /// configured by the user, for e.g. serializing as an
286
+ /// [Apache Arrow](https://arrow.apache.org/) before passing to another
287
+ /// library.
288
+ ///
289
+ /// The [`View`] returned by this method is owned by the
290
+ /// [`PerspectiveViewerElement`] and may be _invalidated_ by
291
+ /// [`View::delete`] at any time. Plugins which rely on this [`View`] for
292
+ /// their [`HTMLPerspectiveViewerPluginElement::draw`] implementations
293
+ /// should treat this condition as a _cancellation_ by silently aborting on
294
+ /// "View already deleted" errors from method calls.
295
+ ///
296
+ /// # JavaScript Examples
297
+ ///
298
+ /// ```javascript
299
+ /// const view = await viewer.getView();
300
+ /// ```
301
+ #[wasm_bindgen]
302
+ pub fn getView(&self) -> ApiFuture<View> {
303
+ let session = self.session.clone();
304
+ ApiFuture::new(async move { Ok(session.get_view().ok_or("No table set")?.into()) })
305
+ }
306
+
307
+ /// Get the underlying [`Table`] for this viewer (as passed to
308
+ /// [`PerspectiveViewerElement::load`]).
309
+ ///
310
+ /// # Arguments
311
+ ///
312
+ /// - `wait_for_table` - whether to wait for
313
+ /// [`PerspectiveViewerElement::load`] to be called, or fail immediately
314
+ /// if [`PerspectiveViewerElement::load`] has not yet been called.
315
+ ///
316
+ /// # JavaScript Examples
317
+ ///
318
+ /// ```javascript
319
+ /// const table = await viewer.getTable();
320
+ /// ```
321
+ #[wasm_bindgen]
322
+ pub fn getTable(&self, wait_for_table: Option<bool>) -> ApiFuture<Table> {
323
+ let session = self.session.clone();
324
+ ApiFuture::new(async move {
325
+ match session.get_table() {
326
+ Some(table) => Ok(table.into()),
327
+ None if !wait_for_table.unwrap_or_default() => Err("No table set".into()),
328
+ None => {
329
+ session.table_loaded.listen_once().await?;
330
+ Ok(session.get_table().ok_or("No table set")?.into())
331
+ },
332
+ }
333
+ })
334
+ }
335
+
336
+ /// Get render statistics. Some fields of the returned stats object are
337
+ /// relative to the last time [`PerspectiveViewerElement::getRenderStats`]
338
+ /// was called, ergo calling this method resets these fields.
339
+ ///
340
+ /// # JavaScript Examples
341
+ ///
342
+ /// ```javascript
343
+ /// const {virtual_fps, actual_fps} = await viewer.getRenderStats();
344
+ /// ```
345
+ #[wasm_bindgen]
346
+ pub fn getRenderStats(&self) -> ApiResult<JsValue> {
347
+ Ok(JsValue::from_serde_ext(
348
+ &self.renderer.render_timer().get_stats(),
349
+ )?)
350
+ }
351
+
352
+ /// Flush any pending modifications to this `<perspective-viewer>`. Since
353
+ /// `<perspective-viewer>`'s API is almost entirely `async`, it may take
354
+ /// some milliseconds before any user-initiated changes to the [`View`]
355
+ /// affects the rendered element. If you want to make sure all pending
356
+ /// actions have been rendered, call and await [`Self::flush`].
357
+ ///
358
+ /// [`Self::flush`] will resolve immediately if there is no [`Table`] set.
359
+ ///
360
+ /// # JavaScript Examples
361
+ ///
362
+ /// In this example, [`Self::restore`] is called without `await`, but the
363
+ /// eventual render which results from this call can still be awaited by
364
+ /// immediately awaiting [`Self::flush`] instead.
365
+ ///
366
+ /// ```javascript
367
+ /// viewer.restore(config);
368
+ /// await viewer.flush();
369
+ /// ```
370
+ pub fn flush(&self) -> ApiFuture<()> {
371
+ clone!(self.renderer);
372
+ ApiFuture::new(async move {
373
+ request_animation_frame().await;
374
+ renderer.with_lock(async { Ok(()) }).await
375
+ })
376
+ }
377
+
378
+ /// Restores this element from a full/partial
379
+ /// [`perspective_js::JsViewConfig`].
380
+ ///
381
+ /// One of the best ways to use [`Self::restore`] is by first configuring
382
+ /// a `<perspective-viewer>` as you wish, then using either the `Debug`
383
+ /// panel or "Copy" -> "config.json" from the toolbar menu to snapshot
384
+ /// the [`Self::restore`] argument as JSON.
385
+ ///
386
+ /// # Arguments
387
+ ///
388
+ /// - `update` - The config to restore to, as returned by [`Self::save`] in
389
+ /// either "json", "string" or "arraybuffer" format.
390
+ ///
391
+ /// # JavaScript Examples
392
+ ///
393
+ /// Apply a `group_by` to the current [`View`], without modifying/resetting
394
+ /// other fields:
395
+ ///
396
+ /// ```javascript
397
+ /// await viewer.restore({group_by: ["State"]});
398
+ /// ```
399
+ pub fn restore(&self, update: JsValue) -> ApiFuture<()> {
400
+ tracing::info!("Restoring ViewerConfig");
401
+ let this = self.clone();
402
+ ApiFuture::new(async move {
403
+ let decoded_update = ViewerConfigUpdate::decode(&update)?;
404
+ let root = this.root.clone();
405
+ let settings = decoded_update.settings.clone();
406
+ let result = root
407
+ .borrow()
408
+ .as_ref()
409
+ .into_apierror()?
410
+ .send_message_async(move |x| {
411
+ PerspectiveViewerMsg::ToggleSettingsComplete(settings, x)
412
+ });
413
+
414
+ let task = this
415
+ .restore_and_render(decoded_update, async move { Ok(result.await?) })
416
+ .await;
417
+
418
+ if let Err(e) = task {
419
+ this.session().set_error(false, e.clone()).await?;
420
+ Err(e)
421
+ } else {
422
+ Ok(())
423
+ }
424
+ })
425
+ }
426
+
427
+ pub fn resetError(&self) -> ApiFuture<()> {
428
+ self.session.invalidate();
429
+ let this = self.clone();
430
+ ApiFuture::new(async move {
431
+ this.update_and_render(ViewConfigUpdate::default())?.await?;
432
+ Ok(())
433
+ })
434
+ }
435
+
436
+ /// Save this element to serialized state object, one which can be restored
437
+ /// via the [`Self::restore`] method.
438
+ ///
439
+ /// # Arguments
440
+ ///
441
+ /// - `format` - Supports "json" (default), "arraybuffer" or "string".
442
+ ///
443
+ /// # JavaScript Examples
444
+ ///
445
+ /// Get the current `group_by` setting:
446
+ ///
447
+ /// ```javascript
448
+ /// const {group_by} = await viewer.restore();
449
+ /// ```
450
+ ///
451
+ /// Reset workflow attached to an external button `myResetButton`:
452
+ ///
453
+ /// ```javascript
454
+ /// const token = await viewer.save();
455
+ /// myResetButton.addEventListener("clien", async () => {
456
+ /// await viewer.restore(token);
457
+ /// });
458
+ /// ```
459
+ pub fn save(&self, format: Option<String>) -> ApiFuture<JsValue> {
460
+ let this = self.clone();
461
+ ApiFuture::new(async move {
462
+ let viewer_config_task = this.get_viewer_config();
463
+ let format = format
464
+ .as_ref()
465
+ .map(|x| ViewerConfigEncoding::from_str(x))
466
+ .transpose()?;
467
+
468
+ let viewer_config = viewer_config_task.await?;
469
+ viewer_config.encode(&format)
470
+ })
471
+ }
472
+
473
+ /// Download this viewer's internal [`View`] data as a `.csv` file.
474
+ ///
475
+ /// # Arguments
476
+ ///
477
+ /// - `flat` - Whether to use the current [`perspective_js::JsViewConfig`]
478
+ /// to generate this data, or use the default.
479
+ ///
480
+ /// # JavaScript Examples
481
+ ///
482
+ /// ```javascript
483
+ /// myDownloadButton.addEventListener("click", async () => {
484
+ /// await viewer.download();
485
+ /// })
486
+ /// ```
487
+ pub fn download(&self, flat: Option<bool>) -> ApiFuture<()> {
488
+ let session = self.session.clone();
489
+ ApiFuture::new(async move {
490
+ let val = session
491
+ .csv_as_jsvalue(flat.unwrap_or_default(), None)
492
+ .await?
493
+ .as_blob()?;
494
+
495
+ // TODO name.as_deref().unwrap_or("untitled.csv")
496
+ download("untitled.csv", &val)
497
+ })
498
+ }
499
+
500
+ /// Copy this viewer's `View` or `Table` data as CSV to the system
501
+ /// clipboard.
502
+ ///
503
+ /// # Arguments
504
+ ///
505
+ /// - `method` - The `ExportMethod` (serialized as a `String`) to use to
506
+ /// render the data to the Clipboard.
507
+ ///
508
+ /// # JavaScript Examples
509
+ ///
510
+ /// ```javascript
511
+ /// myDownloadButton.addEventListener("click", async () => {
512
+ /// await viewer.copy();
513
+ /// })
514
+ /// ```
515
+ pub fn copy(&self, method: Option<JsString>) -> ApiFuture<()> {
516
+ let this = self.clone();
517
+ ApiFuture::new(async move {
518
+ let method = if let Some(method) = method
519
+ .map(|x| x.unchecked_into())
520
+ .map(serde_wasm_bindgen::from_value)
521
+ {
522
+ method?
523
+ } else {
524
+ ExportMethod::Csv
525
+ };
526
+
527
+ let js_task = this.export_method_to_jsvalue(method);
528
+ copy_to_clipboard(js_task, MimeType::TextPlain).await
529
+ })
530
+ }
531
+
532
+ /// Reset the viewer's `ViewerConfig` to the default.
533
+ ///
534
+ /// # Arguments
535
+ ///
536
+ /// - `reset_all` - If set, will clear expressions and column settings as
537
+ /// well.
538
+ ///
539
+ /// # JavaScript Examples
540
+ ///
541
+ /// ```javascript
542
+ /// await viewer.reset();
543
+ /// ```
544
+ pub fn reset(&self, reset_all: Option<bool>) -> ApiFuture<()> {
545
+ tracing::info!("Resetting config");
546
+ let root = self.root.clone();
547
+ let all = reset_all.unwrap_or_default();
548
+ ApiFuture::new(async move {
549
+ let task = root
550
+ .borrow()
551
+ .as_ref()
552
+ .ok_or("Already deleted")?
553
+ .send_message_async(move |x| PerspectiveViewerMsg::Reset(all, Some(x)));
554
+
555
+ Ok(task.await?)
556
+ })
557
+ }
558
+
559
+ /// Recalculate the viewer's dimensions and redraw.
560
+ ///
561
+ /// Use this method to tell `<perspective-viewer>` its dimensions have
562
+ /// changed when auto-size mode has been disabled via [`Self::setAutoSize`].
563
+ /// [`Self::resize`] resolves when the resize-initiated redraw of this
564
+ /// element has completed.
565
+ ///
566
+ /// # Arguments
567
+ ///
568
+ /// - `force` - If [`Self::resize`] is called with `false` or without an
569
+ /// argument, and _auto-size_ mode is enabled via [`Self::setAutoSize`],
570
+ /// [`Self::resize`] will log a warning and auto-disable auto-size mode.
571
+ ///
572
+ /// # JavaScript Examples
573
+ ///
574
+ /// ```javascript
575
+ /// await viewer.resize(true)
576
+ /// ```
577
+ #[wasm_bindgen]
578
+ pub fn resize(&self, force: Option<bool>) -> ApiFuture<()> {
579
+ if !force.unwrap_or_default() && self.resize_handle.borrow().is_some() {
580
+ let msg: JsValue = "`resize(false)` called, disabling auto-size. It can be \
581
+ re-enabled with `setAutoSize(true)`."
582
+ .into();
583
+ web_sys::console::warn_1(&msg);
584
+ *self.resize_handle.borrow_mut() = None;
585
+ }
586
+
587
+ let renderer = self.renderer.clone();
588
+ ApiFuture::new(async move { renderer.resize().await })
589
+ }
590
+
591
+ /// Sets the auto-size behavior of this component.
592
+ ///
593
+ /// When `true`, this `<perspective-viewer>` will register a
594
+ /// `ResizeObserver` on itself and call [`Self::resize`] whenever its own
595
+ /// dimensions change. However, when embedded in a larger application
596
+ /// context, you may want to call [`Self::resize`] manually to avoid
597
+ /// over-rendering; in this case auto-sizing can be disabled via this
598
+ /// method. Auto-size behavior is enabled by default.
599
+ ///
600
+ /// # Arguments
601
+ ///
602
+ /// - `autosize` - Whether to enable `auto-size` behavior or not.
603
+ ///
604
+ /// # JavaScript Examples
605
+ ///
606
+ /// Disable auto-size behavior:
607
+ ///
608
+ /// ```javascript
609
+ /// viewer.setAutoSize(false);
610
+ /// ```
611
+ #[wasm_bindgen]
612
+ pub fn setAutoSize(&self, autosize: bool) {
613
+ if autosize {
614
+ let handle = Some(ResizeObserverHandle::new(
615
+ &self.elem,
616
+ &self.renderer,
617
+ self.root.borrow().as_ref().unwrap(),
618
+ ));
619
+ *self.resize_handle.borrow_mut() = handle;
620
+ } else {
621
+ *self.resize_handle.borrow_mut() = None;
622
+ }
623
+ }
624
+
625
+ /// Sets the auto-pause behavior of this component.
626
+ ///
627
+ /// When `true`, this `<perspective-viewer>` will register an
628
+ /// `IntersectionObserver` on itself and subsequently skip rendering
629
+ /// whenever its viewport visibility changes. Auto-pause is enabled by
630
+ /// default.
631
+ ///
632
+ /// # Arguments
633
+ ///
634
+ /// - `autopause` Whether to enable `auto-pause` behavior or not.
635
+ ///
636
+ /// # JavaScript Examples
637
+ ///
638
+ /// Disable auto-size behavior:
639
+ ///
640
+ /// ```javascript
641
+ /// viewer.setAutoPause(false);
642
+ /// ```
643
+ #[wasm_bindgen]
644
+ pub fn setAutoPause(&self, autopause: bool) {
645
+ if autopause {
646
+ let handle = Some(IntersectionObserverHandle::new(
647
+ &self.elem,
648
+ &self.session,
649
+ &self.renderer,
650
+ ));
651
+ *self.intersection_handle.borrow_mut() = handle;
652
+ } else {
653
+ *self.intersection_handle.borrow_mut() = None;
654
+ }
655
+ }
656
+
657
+ /// Return a [`perspective_js::JsViewWindow`] for the currently selected
658
+ /// region.
659
+ #[wasm_bindgen]
660
+ pub fn getSelection(&self) -> Option<JsViewWindow> {
661
+ self.renderer.get_selection().map(|x| x.into())
662
+ }
663
+
664
+ /// Set the selection [`perspective_js::JsViewWindow`] for this element.
665
+ #[wasm_bindgen]
666
+ pub fn setSelection(&self, window: Option<JsViewWindow>) -> ApiResult<()> {
667
+ let window = window.map(|x| x.into_serde_ext()).transpose()?;
668
+ if self.renderer.get_selection() != window {
669
+ self.events.dispatch_select(window.as_ref())?;
670
+ }
671
+
672
+ self.renderer.set_selection(window);
673
+ Ok(())
674
+ }
675
+
676
+ /// Get this viewer's edit port for the currently loaded [`Table`] (see
677
+ /// [`Table::update`] for details on ports).
678
+ #[wasm_bindgen]
679
+ pub fn getEditPort(&self) -> Result<f64, JsValue> {
680
+ self.session
681
+ .metadata()
682
+ .get_edit_port()
683
+ .ok_or_else(|| "No `Table` loaded".into())
684
+ }
685
+
686
+ /// Restyle all plugins from current document.
687
+ ///
688
+ /// <div class="warning">
689
+ ///
690
+ /// [`Self::restyleElement`] _must_ be called for many runtime changes to
691
+ /// CSS properties to be reflected in an already-rendered
692
+ /// `<perspective-viewer>`.
693
+ ///
694
+ /// </div>
695
+ ///
696
+ /// # JavaScript Examples
697
+ ///
698
+ /// ```javascript
699
+ /// viewer.style = "--icon--color: red";
700
+ /// await viewer.restyleElement();
701
+ /// ```
702
+ #[wasm_bindgen]
703
+ pub fn restyleElement(&self) -> ApiFuture<JsValue> {
704
+ clone!(self.renderer, self.session);
705
+ ApiFuture::new(async move {
706
+ let view = session.get_view().into_apierror()?;
707
+ renderer.restyle_all(&view).await
708
+ })
709
+ }
710
+
711
+ /// Set the available theme names available in the status bar UI.
712
+ ///
713
+ /// Calling [`Self::resetThemes`] may cause the current theme to switch,
714
+ /// if e.g. the new theme set does not contain the current theme.
715
+ ///
716
+ /// # JavaScript Examples
717
+ ///
718
+ /// Restrict `<perspective-viewer>` theme options to _only_ default light
719
+ /// and dark themes, regardless of what is auto-detected from the page's
720
+ /// CSS:
721
+ ///
722
+ /// ```javascript
723
+ /// viewer.resetThemes(["Pro Light", "Pro Dark"])
724
+ /// ```
725
+ #[wasm_bindgen]
726
+ pub fn resetThemes(&self, themes: Option<Box<[JsValue]>>) -> ApiFuture<JsValue> {
727
+ clone!(self.renderer, self.session, self.presentation);
728
+ ApiFuture::new(async move {
729
+ let themes: Option<Vec<String>> = themes
730
+ .unwrap_or_default()
731
+ .iter()
732
+ .map(|x| x.as_string())
733
+ .collect();
734
+
735
+ let theme_name = presentation.get_selected_theme_name().await;
736
+ let mut changed = presentation.reset_available_themes(themes).await;
737
+ let reset_theme = presentation
738
+ .get_available_themes()
739
+ .await?
740
+ .iter()
741
+ .find(|y| theme_name.as_ref() == Some(y))
742
+ .cloned();
743
+
744
+ changed = presentation.set_theme_name(reset_theme.as_deref()).await? || changed;
745
+ if changed && let Some(view) = session.get_view() {
746
+ return renderer.restyle_all(&view).await;
747
+ }
748
+
749
+ Ok(JsValue::UNDEFINED)
750
+ })
751
+ }
752
+
753
+ /// Determines the render throttling behavior. Can be an integer, for
754
+ /// millisecond window to throttle render event; or, if `None`, adaptive
755
+ /// throttling will be calculated from the measured render time of the
756
+ /// last 5 frames.
757
+ ///
758
+ /// # Arguments
759
+ ///
760
+ /// - `throttle` - The throttle rate in milliseconds (f64), or `None` for
761
+ /// adaptive throttling.
762
+ ///
763
+ /// # JavaScript Examples
764
+ ///
765
+ /// Only draws at most 1 frame/sec:
766
+ ///
767
+ /// ```rust
768
+ /// viewer.setThrottle(1000);
769
+ /// ```
770
+ #[wasm_bindgen]
771
+ pub fn setThrottle(&self, val: Option<f64>) {
772
+ self.renderer.set_throttle(val);
773
+ }
774
+
775
+ /// Toggle (or force) the config panel open/closed.
776
+ ///
777
+ /// # Arguments
778
+ ///
779
+ /// - `force` - Force the state of the panel open or closed, or `None` to
780
+ /// toggle.
781
+ ///
782
+ /// # JavaScript Examples
783
+ ///
784
+ /// ```javascript
785
+ /// await viewer.toggleConfig();
786
+ /// ```
787
+ #[wasm_bindgen]
788
+ pub fn toggleConfig(&self, force: Option<bool>) -> ApiFuture<JsValue> {
789
+ let root = self.root.clone();
790
+ ApiFuture::new(async move {
791
+ let force = force.map(SettingsUpdate::Update);
792
+ let task = root
793
+ .borrow()
794
+ .as_ref()
795
+ .into_apierror()?
796
+ .send_message_async(|x| PerspectiveViewerMsg::ToggleSettingsInit(force, Some(x)));
797
+
798
+ task.await.map_err(|_| JsValue::from("Cancelled"))?
799
+ })
800
+ }
801
+
802
+ /// Get an `Array` of all of the plugin custom elements registered for this
803
+ /// element. This may not include plugins which called
804
+ /// [`registerPlugin`] after the host has rendered for the first time.
805
+ #[wasm_bindgen]
806
+ pub fn getAllPlugins(&self) -> Array {
807
+ self.renderer.get_all_plugins().iter().collect::<Array>()
808
+ }
809
+
810
+ /// Gets a plugin Custom Element with the `name` field, or get the active
811
+ /// plugin if no `name` is provided.
812
+ ///
813
+ /// # Arguments
814
+ ///
815
+ /// - `name` - The `name` property of a perspective plugin Custom Element,
816
+ /// or `None` for the active plugin's Custom Element.
817
+ #[wasm_bindgen]
818
+ pub fn getPlugin(&self, name: Option<String>) -> ApiResult<JsPerspectiveViewerPlugin> {
819
+ match name {
820
+ None => self.renderer.get_active_plugin(),
821
+ Some(name) => self.renderer.get_plugin(&name),
822
+ }
823
+ }
824
+
825
+ /// Create a new JavaScript Heap reference for this model instance.
826
+ #[doc(hidden)]
827
+ #[allow(clippy::use_self)]
828
+ #[wasm_bindgen]
829
+ pub fn get_model(&self) -> PerspectiveViewerElement {
830
+ self.clone()
831
+ }
832
+
833
+ /// Asynchronously opens the column settings for a specific column.
834
+ /// When finished, the `<perspective-viewer>` element will emit a
835
+ /// "perspective-toggle-column-settings" CustomEvent.
836
+ /// The event's details property has two fields: `{open: bool, column_name?:
837
+ /// string}`. The CustomEvent is also fired whenever the user toggles the
838
+ /// sidebar manually.
839
+ #[wasm_bindgen]
840
+ pub fn toggleColumnSettings(&self, column_name: String) -> ApiFuture<()> {
841
+ clone!(self.session, self.root);
842
+ ApiFuture::new(async move {
843
+ let locator = session.metadata().get_column_locator(Some(column_name));
844
+ let task = root
845
+ .borrow()
846
+ .as_ref()
847
+ .into_apierror()?
848
+ .send_message_async(|sender| PerspectiveViewerMsg::OpenColumnSettings {
849
+ locator,
850
+ sender: Some(sender),
851
+ toggle: true,
852
+ });
853
+ task.await.map_err(|_| ApiError::from("Cancelled"))
854
+ })
855
+ }
856
+
857
+ /// Force open the settings for a particular column. Pass `null` to close
858
+ /// the column settings panel. See [`Self::toggleColumnSettings`] for more.
859
+ #[wasm_bindgen]
860
+ pub fn openColumnSettings(
861
+ &self,
862
+ column_name: Option<String>,
863
+ toggle: Option<bool>,
864
+ ) -> ApiFuture<()> {
865
+ clone!(self.session, self.root);
866
+ ApiFuture::new(async move {
867
+ let locator = session.metadata().get_column_locator(column_name);
868
+ let task = root
869
+ .borrow()
870
+ .as_ref()
871
+ .into_apierror()?
872
+ .send_message_async(|sender| PerspectiveViewerMsg::OpenColumnSettings {
873
+ locator,
874
+ sender: Some(sender),
875
+ toggle: toggle.unwrap_or_default(),
876
+ });
877
+ task.await.map_err(|_| ApiError::from("Cancelled"))
878
+ })
879
+ }
880
+ }