@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,370 @@
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
+ use std::cell::RefCell;
14
+ use std::collections::{HashMap, HashSet};
15
+ use std::ops::Deref;
16
+ use std::rc::Rc;
17
+
18
+ use async_lock::Mutex;
19
+ use perspective_js::utils::{ApiFuture, ApiResult, ToApiError, global};
20
+ use wasm_bindgen::prelude::*;
21
+ use web_sys::*;
22
+ use yew::html::ImplicitClone;
23
+
24
+ use crate::components::column_settings_sidebar::ColumnSettingsTab;
25
+ use crate::components::viewer::ColumnLocator;
26
+ use crate::config::{ColumnConfigUpdate, ColumnConfigValueUpdate, ColumnConfigValues};
27
+ use crate::utils::*;
28
+
29
+ /// The available themes as detected in the browser environment or set
30
+ /// explicitly when CORS prevents detection. Detection is expensive and
31
+ /// typically must be performed only once, when `document.styleSheets` is
32
+ /// up-to-date.
33
+ #[derive(Clone)]
34
+ pub struct Presentation(Rc<PresentationHandle>);
35
+
36
+ impl PartialEq for Presentation {
37
+ fn eq(&self, other: &Self) -> bool {
38
+ Rc::ptr_eq(&self.0, &other.0)
39
+ }
40
+ }
41
+
42
+ impl Deref for Presentation {
43
+ type Target = PresentationHandle;
44
+
45
+ fn deref(&self) -> &Self::Target {
46
+ &self.0
47
+ }
48
+ }
49
+
50
+ impl ImplicitClone for Presentation {}
51
+
52
+ #[derive(Clone, Default, Debug, PartialEq)]
53
+ pub struct OpenColumnSettings {
54
+ pub locator: Option<ColumnLocator>,
55
+ pub tab: Option<ColumnSettingsTab>,
56
+ }
57
+ impl OpenColumnSettings {
58
+ pub fn name(&self) -> Option<String> {
59
+ self.locator
60
+ .as_ref()
61
+ .and_then(|l| l.name())
62
+ .map(|s| s.to_owned())
63
+ }
64
+ }
65
+
66
+ pub type ColumnConfigMap = HashMap<String, ColumnConfigValues>;
67
+
68
+ pub struct PresentationHandle {
69
+ viewer_elem: HtmlElement,
70
+ theme_data: Mutex<ThemeData>,
71
+ name: RefCell<Option<String>>,
72
+ is_settings_open: RefCell<bool>,
73
+ open_column_settings: RefCell<OpenColumnSettings>,
74
+ is_workspace: RefCell<Option<bool>>,
75
+ columns_config: RefCell<ColumnConfigMap>,
76
+ pub settings_open_changed: PubSub<bool>,
77
+ pub column_settings_open_changed: PubSub<(bool, Option<String>)>,
78
+ pub column_settings_updated: PubSub<JsValue>,
79
+ pub theme_config_updated: PubSub<(Rc<Vec<String>>, Option<usize>)>,
80
+ pub title_changed: PubSub<Option<String>>,
81
+ }
82
+
83
+ #[derive(Default)]
84
+ pub struct ThemeData {
85
+ themes: Option<Vec<String>>,
86
+ }
87
+
88
+ impl Presentation {
89
+ pub fn new(elem: &HtmlElement) -> Self {
90
+ let theme = Self(Rc::new(PresentationHandle {
91
+ viewer_elem: elem.clone(),
92
+ name: Default::default(),
93
+ theme_data: Default::default(),
94
+ settings_open_changed: Default::default(),
95
+ column_settings_open_changed: Default::default(),
96
+ column_settings_updated: Default::default(),
97
+ columns_config: Default::default(),
98
+ is_settings_open: Default::default(),
99
+ is_workspace: Default::default(),
100
+ open_column_settings: Default::default(),
101
+ theme_config_updated: PubSub::default(),
102
+ title_changed: PubSub::default(),
103
+ }));
104
+
105
+ ApiFuture::spawn(theme.clone().init());
106
+ theme
107
+ }
108
+
109
+ pub fn get_title(&self) -> Option<String> {
110
+ self.name.borrow().clone()
111
+ }
112
+
113
+ pub fn set_title(&self, title: Option<String>) {
114
+ self.name.borrow_mut().clone_from(&title);
115
+ self.title_changed.emit(title);
116
+ }
117
+
118
+ pub fn get_is_workspace(&self) -> bool {
119
+ if self.is_workspace.borrow().is_none() {
120
+ let is_workspace = self
121
+ .viewer_elem
122
+ .parent_element()
123
+ .map(|x| x.tag_name() == "PERSPECTIVE-WORKSPACE")
124
+ .unwrap_or_default();
125
+
126
+ *self.is_workspace.borrow_mut() = Some(is_workspace);
127
+ }
128
+
129
+ self.is_workspace.borrow().unwrap()
130
+ }
131
+
132
+ pub fn set_settings_attribute(&self, opt: bool) {
133
+ self.viewer_elem
134
+ .toggle_attribute_with_force("settings", opt)
135
+ .unwrap();
136
+ }
137
+
138
+ pub fn is_settings_open(&self) -> bool {
139
+ *self.is_settings_open.borrow()
140
+ }
141
+
142
+ pub fn set_settings_open(&self, open: Option<bool>) -> ApiResult<bool> {
143
+ let open_state = open.unwrap_or_else(|| !*self.is_settings_open.borrow());
144
+ if *self.is_settings_open.borrow() != open_state {
145
+ *self.is_settings_open.borrow_mut() = open_state;
146
+ self.set_settings_attribute(open_state);
147
+ self.settings_open_changed.emit(open_state);
148
+ }
149
+
150
+ Ok(open_state)
151
+ }
152
+
153
+ /// Sets the currently opened column settings. Emits an internal event on
154
+ /// change. Passing None is a shorthand for setting all fields to
155
+ /// None.
156
+ pub fn set_open_column_settings(&self, settings: Option<OpenColumnSettings>) {
157
+ let settings = settings.unwrap_or_default();
158
+ if *(self.open_column_settings.borrow()) != settings {
159
+ settings.clone_into(&mut *self.open_column_settings.borrow_mut());
160
+ self.column_settings_open_changed
161
+ .emit((true, settings.name()));
162
+ }
163
+ }
164
+
165
+ /// Gets a clone of the current OpenColumnSettings.
166
+ pub fn get_open_column_settings(&self) -> OpenColumnSettings {
167
+ self.open_column_settings.borrow().deref().clone()
168
+ }
169
+
170
+ async fn init(self) -> ApiResult<()> {
171
+ self.set_theme_attribute(self.get_selected_theme_name().await.as_deref())
172
+ }
173
+
174
+ /// Get the available theme names from the browser environment by parsing
175
+ /// readable stylesheets. This method is memoized - the state can be
176
+ /// flushed by calling `reset()`.
177
+ pub async fn get_available_themes(&self) -> ApiResult<Rc<Vec<String>>> {
178
+ let mut data = self.0.theme_data.lock().await;
179
+ if data.themes.is_none() {
180
+ await_dom_loaded().await?;
181
+ let themes = get_theme_names(&self.0.viewer_elem)?;
182
+ data.themes = Some(themes);
183
+ }
184
+
185
+ Ok(data.themes.clone().unwrap().into())
186
+ }
187
+
188
+ /// Reset the state. `styleSheets` will be re-parsed next time
189
+ /// `get_themes()` is called if the `themes` argument is `None`.
190
+ ///
191
+ /// # Returns
192
+ /// A `bool` indicating whether the internal state changed.
193
+ pub async fn reset_available_themes(&self, themes: Option<Vec<String>>) -> bool {
194
+ fn as_set(x: &Option<Vec<String>>) -> HashSet<&'_ String> {
195
+ x.as_ref()
196
+ .map(|x| x.iter().collect::<HashSet<_>>())
197
+ .unwrap_or_default()
198
+ }
199
+
200
+ let mut mutex = self.0.theme_data.lock().await;
201
+ let changed = as_set(&mutex.themes) != as_set(&themes);
202
+ mutex.themes = themes;
203
+ changed
204
+ }
205
+
206
+ pub async fn get_selected_theme_config(&self) -> ApiResult<(Rc<Vec<String>>, Option<usize>)> {
207
+ let themes = self.get_available_themes().await?;
208
+ let name = self.0.viewer_elem.get_attribute("theme");
209
+ let index = name
210
+ .and_then(|x| themes.iter().position(|y| y == &x))
211
+ .or(if !themes.is_empty() { Some(0) } else { None });
212
+
213
+ Ok((themes, index))
214
+ }
215
+
216
+ /// Returns the currently applied theme, or the default theme if no theme
217
+ /// has been set and themes are detected in the `document`, or `None` if
218
+ /// no themes are available.
219
+ pub async fn get_selected_theme_name(&self) -> Option<String> {
220
+ let (themes, index) = self.get_selected_theme_config().await.ok()?;
221
+ index.and_then(|x| themes.get(x).cloned())
222
+ }
223
+
224
+ fn set_theme_attribute(&self, theme: Option<&str>) -> ApiResult<()> {
225
+ if let Some(theme) = theme {
226
+ Ok(self.0.viewer_elem.set_attribute("theme", theme)?)
227
+ } else {
228
+ Ok(self.0.viewer_elem.remove_attribute("theme")?)
229
+ }
230
+ }
231
+
232
+ pub async fn reset_theme(&self) -> ApiResult<()> {
233
+ let themes = self.get_available_themes().await?;
234
+ let default_theme = themes.first().map(|x| x.as_str());
235
+ self.set_theme_name(default_theme).await?;
236
+ Ok(())
237
+ }
238
+
239
+ /// Set the theme by name, or `None` for the default theme.
240
+ ///
241
+ /// # Returns
242
+ /// A `bool` indicating whether the internal state changed.
243
+ pub async fn set_theme_name(&self, theme: Option<&str>) -> ApiResult<bool> {
244
+ let (themes, selected) = self.get_selected_theme_config().await?;
245
+ if let Some(x) = selected
246
+ && themes.get(x).map(|x| x.as_str()) == theme
247
+ {
248
+ return Ok(false);
249
+ }
250
+
251
+ let index = if let Some(theme) = theme {
252
+ self.set_theme_attribute(Some(theme))?;
253
+ themes.iter().position(|x| x == theme)
254
+ } else if !themes.is_empty() {
255
+ self.set_theme_attribute(themes.first().map(|x| x.as_str()))?;
256
+ Some(0)
257
+ } else {
258
+ self.set_theme_attribute(None)?;
259
+ None
260
+ };
261
+
262
+ self.theme_config_updated.emit((themes, index));
263
+ Ok(true)
264
+ }
265
+
266
+ /// Returns an owned copy of the curent column configuration map.
267
+ pub fn all_columns_configs(&self) -> ColumnConfigMap {
268
+ self.columns_config.borrow().clone()
269
+ }
270
+
271
+ pub fn reset_columns_configs(&self) {
272
+ *self.columns_config.borrow_mut() = ColumnConfigMap::new();
273
+ }
274
+
275
+ /// Gets a clone of the ColumnConfig for the given column name.
276
+ pub fn get_columns_config(&self, column_name: &str) -> Option<ColumnConfigValues> {
277
+ self.columns_config.borrow().get(column_name).cloned()
278
+ }
279
+
280
+ /// Updates the entire column config struct. (like from a restore() call)
281
+ pub fn update_columns_configs(&self, update: ColumnConfigUpdate) {
282
+ match update {
283
+ crate::config::OptionalUpdate::SetDefault => {
284
+ let mut config = self.columns_config.borrow_mut();
285
+ *config = HashMap::default()
286
+ },
287
+ crate::config::OptionalUpdate::Missing => {},
288
+ crate::config::OptionalUpdate::Update(update) => {
289
+ for (col_name, new_config) in update.into_iter() {
290
+ self.columns_config
291
+ .borrow_mut()
292
+ .insert(col_name, new_config);
293
+ }
294
+ },
295
+ }
296
+ }
297
+
298
+ pub fn update_columns_config_value(
299
+ &self,
300
+ column_name: String,
301
+ update: ColumnConfigValueUpdate,
302
+ ) {
303
+ let mut config = self.columns_config.borrow_mut();
304
+ let value = config.remove(&column_name).unwrap_or_default();
305
+ let update = value.update(update);
306
+ if !update.is_empty() {
307
+ config.insert(column_name, update);
308
+ }
309
+ }
310
+ }
311
+
312
+ macro_rules! iter_index {
313
+ ($x:expr) => {
314
+ (0..$x.length()).map(|x| $x.item(x))
315
+ };
316
+ }
317
+
318
+ fn fill_rule_theme_names(
319
+ themes: &mut Vec<String>,
320
+ rule: &Option<CssRule>,
321
+ elem: &HtmlElement,
322
+ ) -> ApiResult<()> {
323
+ if let Some(rule) = rule.as_ref().into_apierror()?.dyn_ref::<CssStyleRule>() {
324
+ let txt = rule.selector_text();
325
+ if elem.matches(&txt)? {
326
+ let style = rule.style();
327
+ let x = (0..style.length()).map(|x| style.item(x));
328
+ for property in x {
329
+ if property == "--theme-name" {
330
+ let name = style.get_property_value("--theme-name")?;
331
+ let trimmed = name.trim();
332
+ themes.push(trimmed[1..trimmed.len() - 1].to_owned());
333
+ }
334
+ }
335
+ }
336
+ }
337
+
338
+ Ok(())
339
+ }
340
+
341
+ fn fill_sheet_theme_names(
342
+ themes: &mut Vec<String>,
343
+ sheet: &Option<StyleSheet>,
344
+ elem: &HtmlElement,
345
+ ) -> ApiResult<()> {
346
+ let sheet = sheet
347
+ .as_ref()
348
+ .into_apierror()?
349
+ .unchecked_ref::<CssStyleSheet>();
350
+
351
+ if let Ok(rules) = sheet.css_rules() {
352
+ for rule in iter_index!(&rules) {
353
+ fill_rule_theme_names(themes, &rule, elem).unwrap_or_default();
354
+ }
355
+ }
356
+
357
+ Ok(())
358
+ }
359
+
360
+ /// Search the document's `styleSheets` for rules which apply to `elem` and
361
+ /// provide the `--theme-name` CSS custom property.
362
+ fn get_theme_names(elem: &HtmlElement) -> Result<Vec<String>, JsValue> {
363
+ let sheets = global::document().style_sheets();
364
+ let mut themes: Vec<String> = vec![];
365
+ for sheet in iter_index!(sheets) {
366
+ fill_sheet_theme_names(&mut themes, &sheet, elem)?;
367
+ }
368
+
369
+ Ok(themes)
370
+ }
@@ -0,0 +1,49 @@
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
+ use std::future::Future;
14
+
15
+ use perspective_js::utils::ApiResult;
16
+ use wasm_bindgen::JsCast;
17
+ use web_sys::*;
18
+
19
+ use crate::js::plugin::JsPerspectiveViewerPlugin;
20
+
21
+ /// Given an async `task` which draws `plugin`, activates the plugin in stages
22
+ /// to prevent screen shearing. First, and plugin is appended ot the DOM with
23
+ /// opacity 0, then rendered. After rendering, the previous plugin is removed
24
+ /// and the opacity is set back to 1.
25
+ ///
26
+ /// # Arguments
27
+ /// - `viewer` the root `<perspective-viewer>` element.
28
+ /// - `plugin` the plugin custom element.
29
+ /// - `task` an async task which renders the plugin.
30
+ pub async fn activate_plugin<T>(
31
+ viewer: &HtmlElement,
32
+ plugin: &JsPerspectiveViewerPlugin,
33
+ task: impl Future<Output = ApiResult<T>>,
34
+ ) -> ApiResult<T> {
35
+ let html_plugin = plugin.unchecked_ref::<HtmlElement>();
36
+ if html_plugin.parent_node().is_none() {
37
+ html_plugin.style().set_property("opacity", "0")?;
38
+ viewer.append_child(html_plugin)?;
39
+ }
40
+
41
+ let result = task.await;
42
+ let first_child = viewer.children().item(0).unwrap();
43
+ if first_child != *plugin.unchecked_ref::<Element>() {
44
+ viewer.remove_child(&first_child)?;
45
+ }
46
+
47
+ html_plugin.style().set_property("opacity", "1")?;
48
+ result
49
+ }
@@ -0,0 +1,200 @@
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
+ use perspective_js::utils::ApiError;
14
+
15
+ use crate::js::plugin::*;
16
+
17
+ pub async fn get_row_and_col_limits(
18
+ view: &perspective_client::View,
19
+ plugin_metadata: &ViewConfigRequirements,
20
+ ) -> Result<(usize, usize, Option<usize>, Option<usize>), ApiError> {
21
+ let dimensions = view.dimensions().await?;
22
+ let num_cols = dimensions.num_view_columns as usize;
23
+ let num_rows = dimensions.num_view_rows as usize;
24
+ match (plugin_metadata.max_columns, plugin_metadata.render_warning) {
25
+ (Some(_), false) => Ok((num_cols, num_rows, None, None)),
26
+ (max_columns, _) => {
27
+ let schema = view.schema().await?;
28
+ let keys = schema.keys();
29
+ let num_schema_columns = std::cmp::max(1, keys.len() as usize);
30
+ let max_cols = max_columns.and_then(|max_columns| {
31
+ let column_group_diff = max_columns % num_schema_columns;
32
+ let column_limit = max_columns + column_group_diff;
33
+ if column_limit < num_cols {
34
+ Some(column_limit)
35
+ } else {
36
+ None
37
+ }
38
+ });
39
+
40
+ let max_rows = plugin_metadata.max_cells.map(|max_cells| {
41
+ match max_cols {
42
+ Some(max_cols) => max_cells as f64 / max_cols as f64,
43
+ None => max_cells as f64 / num_cols as f64,
44
+ }
45
+ .ceil() as usize
46
+ });
47
+
48
+ Ok((num_cols, num_rows, max_cols, max_rows))
49
+ },
50
+ }
51
+ }
52
+
53
+ // #[cfg(test)]
54
+ // mod tests {
55
+ // use super::*;
56
+
57
+ // fn closure_helper<T>(x: T) -> Closure<dyn Fn(JsValue) -> js_sys::Promise>
58
+ // where
59
+ // T: Into<JsValue>,
60
+ // {
61
+ // let val = x.into();
62
+ // Closure::new(move |_: JsValue| {
63
+ // clone!(val);
64
+ // future_to_promise(async move { Ok(val.clone()) })
65
+ // })
66
+ // }
67
+
68
+ // #[wasm_bindgen_test]
69
+ // pub async fn test_emtpy_schema_no_columns() {
70
+ // let closure = closure_helper(0);
71
+ // let closure2 = closure_helper(json!({}));
72
+ // let view = json!({
73
+ // "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
74
+ // "num_rows": closure.as_ref().unchecked_ref::<JsValue>(),
75
+ // "schema": closure2.as_ref().unchecked_ref::<JsValue>()
76
+ // })
77
+ // .unchecked_into::<JsPerspectiveView>();
78
+
79
+ // let reqs = ViewConfigRequirements {
80
+ // render_warning: true,
81
+ // ..ViewConfigRequirements::default()
82
+ // };
83
+ // let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
84
+ // &reqs).await.unwrap(); assert_eq!(max_cols, None);
85
+ // assert_eq!(max_rows, None);
86
+ // }
87
+
88
+ // #[wasm_bindgen_test]
89
+ // pub async fn test_columns_do_not_exceed_max_columns() {
90
+ // let closure = closure_helper(1);
91
+ // let closure2 = closure_helper(0);
92
+ // let closure3 = closure_helper(json!({}));
93
+ // let view = json!({
94
+ // "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
95
+ // "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
96
+ // "schema": closure3.as_ref().unchecked_ref::<JsValue>()
97
+ // })
98
+ // .unchecked_into::<JsPerspectiveView>();
99
+
100
+ // let reqs = ViewConfigRequirements {
101
+ // max_columns: Some(2),
102
+ // render_warning: true,
103
+ // ..ViewConfigRequirements::default()
104
+ // };
105
+
106
+ // let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
107
+ // &reqs).await.unwrap(); assert_eq!(max_cols, None);
108
+ // assert_eq!(max_rows, None);
109
+ // }
110
+
111
+ // #[wasm_bindgen_test]
112
+ // pub async fn test_columns_exceed_max_columns() {
113
+ // let closure = closure_helper(2);
114
+ // let closure2 = closure_helper(0);
115
+ // let closure3 = closure_helper(json!({}));
116
+ // let view = json!({
117
+ // "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
118
+ // "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
119
+ // "schema": closure3.as_ref().unchecked_ref::<JsValue>()
120
+ // })
121
+ // .unchecked_into::<JsPerspectiveView>();
122
+
123
+ // let reqs = ViewConfigRequirements {
124
+ // max_columns: Some(1),
125
+ // render_warning: true,
126
+ // ..ViewConfigRequirements::default()
127
+ // };
128
+ // let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
129
+ // &reqs).await.unwrap(); assert_eq!(max_cols, Some(1));
130
+ // assert_eq!(max_rows, None);
131
+ // }
132
+
133
+ // #[wasm_bindgen_test]
134
+ // pub async fn test_when_schema_columns_are_present() {
135
+ // let closure = closure_helper(100);
136
+ // let closure2 = closure_helper(0);
137
+ // let closure3 = closure_helper(json!({"x": "string", "y": "string"}));
138
+ // let view = json!({
139
+ // "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
140
+ // "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
141
+ // "schema": closure3.as_ref().unchecked_ref::<JsValue>()
142
+ // })
143
+ // .unchecked_into::<JsPerspectiveView>();
144
+
145
+ // let reqs = ViewConfigRequirements {
146
+ // max_columns: Some(3),
147
+ // render_warning: true,
148
+ // ..ViewConfigRequirements::default()
149
+ // };
150
+ // let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
151
+ // &reqs).await.unwrap(); assert_eq!(max_cols, Some(4));
152
+ // assert_eq!(max_rows, None);
153
+ // }
154
+
155
+ // #[wasm_bindgen_test]
156
+ // pub async fn test_when_max_cells_exits() {
157
+ // let closure = closure_helper(1);
158
+ // let closure2 = closure_helper(0);
159
+ // let closure3 = closure_helper(json!({}));
160
+ // let view = json!({
161
+ // "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
162
+ // "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
163
+ // "schema": closure3.as_ref().unchecked_ref::<JsValue>()
164
+ // })
165
+ // .unchecked_into::<JsPerspectiveView>();
166
+
167
+ // let reqs = ViewConfigRequirements {
168
+ // max_cells: Some(2),
169
+ // render_warning: true,
170
+ // ..ViewConfigRequirements::default()
171
+ // };
172
+ // let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
173
+ // &reqs).await.unwrap(); assert_eq!(max_cols, None);
174
+ // assert_eq!(max_rows, Some(2));
175
+ // }
176
+
177
+ // #[wasm_bindgen_test]
178
+ // pub async fn test_when_columns_exceed_max_columns_and_max_cells_exists()
179
+ // { let closure = closure_helper(4);
180
+ // let closure2 = closure_helper(0);
181
+ // let closure3 = closure_helper(json!({}));
182
+ // let view = json!({
183
+ // "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
184
+ // "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
185
+ // "schema": closure3.as_ref().unchecked_ref::<JsValue>()
186
+ // })
187
+ // .unchecked_into::<JsPerspectiveView>();
188
+
189
+ // let reqs = ViewConfigRequirements {
190
+ // max_columns: Some(2),
191
+ // max_cells: Some(10),
192
+ // render_warning: true,
193
+ // ..ViewConfigRequirements::default()
194
+ // };
195
+
196
+ // let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
197
+ // &reqs).await.unwrap(); assert_eq!(max_cols, Some(2));
198
+ // assert_eq!(max_rows, Some(5));
199
+ // }
200
+ // }
@@ -0,0 +1,45 @@
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
+ use std::collections::HashMap;
14
+
15
+ use super::registry::*;
16
+ use crate::js::plugin::*;
17
+
18
+ #[derive(Default)]
19
+ pub struct PluginStore {
20
+ plugins: Option<Vec<JsPerspectiveViewerPlugin>>,
21
+ plugin_records: Option<HashMap<String, Vec<String>>>,
22
+ }
23
+
24
+ impl PluginStore {
25
+ fn init_lazy(&mut self) {
26
+ self.plugins = Some(PLUGIN_REGISTRY.create_plugins());
27
+ self.plugin_records = Some(PLUGIN_REGISTRY.available_plugin_names_by_category());
28
+ }
29
+
30
+ pub fn plugins(&mut self) -> &Vec<JsPerspectiveViewerPlugin> {
31
+ if self.plugins.is_none() {
32
+ self.init_lazy();
33
+ }
34
+
35
+ self.plugins.as_ref().unwrap()
36
+ }
37
+
38
+ pub fn plugin_records(&mut self) -> &HashMap<String, Vec<String>> {
39
+ if self.plugins.is_none() {
40
+ self.init_lazy();
41
+ }
42
+
43
+ self.plugin_records.as_ref().unwrap()
44
+ }
45
+ }