@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,483 @@
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::cmp::max;
14
+
15
+ use perspective_js::utils::global;
16
+ use wasm_bindgen::JsCast;
17
+ use wasm_bindgen::prelude::*;
18
+ use web_sys::HtmlElement;
19
+ use yew::html::Scope;
20
+ use yew::prelude::*;
21
+
22
+ use crate::components::style::LocalStyle;
23
+ #[cfg(test)]
24
+ use crate::utils::*;
25
+ use crate::*;
26
+
27
+ /// The state for the `Resizing` action, including the `MouseEvent` callbacks
28
+ /// and panel starting dimensions.
29
+ struct ResizingState {
30
+ mousemove: Closure<dyn Fn(MouseEvent)>,
31
+ mouseup: Closure<dyn Fn(MouseEvent)>,
32
+ cursor: String,
33
+ index: usize,
34
+ start: i32,
35
+ total: i32,
36
+ alt: i32,
37
+ orientation: Orientation,
38
+ reverse: bool,
39
+ body_style: web_sys::CssStyleDeclaration,
40
+ pointer_id: i32,
41
+ pointer_elem: HtmlElement,
42
+ }
43
+
44
+ impl Drop for ResizingState {
45
+ /// On `drop`, we must remove these event listeners from the document
46
+ /// `body`. Without this, the `Closure` objects would not leak, but the
47
+ /// document will continue to call them, causing runtime exceptions.
48
+ fn drop(&mut self) {
49
+ let result: ApiResult<()> = maybe! {
50
+ let mousemove = self.mousemove.as_ref().unchecked_ref();
51
+ global::body().remove_event_listener_with_callback("mousemove", mousemove)?;
52
+ let mouseup = self.mouseup.as_ref().unchecked_ref();
53
+ global::body().remove_event_listener_with_callback("mouseup", mouseup)?;
54
+ self.release_cursor()?;
55
+ Ok(())
56
+ };
57
+
58
+ result.expect("Drop failed")
59
+ }
60
+ }
61
+
62
+ /// The minimum size a split panel child can be, including when overridden via
63
+ /// user drag/drop.
64
+ const MINIMUM_SIZE: i32 = 8;
65
+
66
+ /// When the instantiated, capture the initial dimensions and create the
67
+ /// MouseEvent callbacks.
68
+ impl ResizingState {
69
+ pub fn new(
70
+ index: usize,
71
+ client_offset: i32,
72
+ ctx: &Context<SplitPanel>,
73
+ first_elem: &HtmlElement,
74
+ pointer_id: i32,
75
+ pointer_elem: HtmlElement,
76
+ ) -> ApiResult<Self> {
77
+ let orientation = ctx.props().orientation;
78
+ let reverse = ctx.props().reverse;
79
+ let split_panel = ctx.link();
80
+ let total = match orientation {
81
+ Orientation::Horizontal => first_elem.offset_width(),
82
+ Orientation::Vertical => first_elem.offset_height(),
83
+ };
84
+
85
+ let alt = match orientation {
86
+ Orientation::Horizontal => first_elem.offset_height(),
87
+ Orientation::Vertical => first_elem.offset_width(),
88
+ };
89
+
90
+ let mouseup = Closure::new({
91
+ let cb = split_panel.callback(|_| SplitPanelMsg::StopResizing);
92
+ move |x| cb.emit(x)
93
+ });
94
+
95
+ let mousemove = Closure::new({
96
+ let cb = split_panel.callback(move |event: MouseEvent| {
97
+ SplitPanelMsg::MoveResizing(match orientation {
98
+ Orientation::Horizontal => event.client_x(),
99
+ Orientation::Vertical => event.client_y(),
100
+ })
101
+ });
102
+ move |x| cb.emit(x)
103
+ });
104
+
105
+ let mut state = Self {
106
+ index,
107
+ cursor: "".to_owned(),
108
+ start: client_offset,
109
+ orientation,
110
+ reverse,
111
+ total,
112
+ alt,
113
+ body_style: global::body().style(),
114
+ mouseup,
115
+ mousemove,
116
+ pointer_id,
117
+ pointer_elem,
118
+ };
119
+
120
+ state.capture_cursor()?;
121
+ state.register_listeners()?;
122
+ Ok(state)
123
+ }
124
+
125
+ fn get_offset(&self, client_offset: i32) -> i32 {
126
+ let delta = if self.reverse {
127
+ self.start - client_offset
128
+ } else {
129
+ client_offset - self.start
130
+ };
131
+
132
+ max(MINIMUM_SIZE, self.total + delta)
133
+ }
134
+
135
+ pub fn get_style(&self, client_offset: i32) -> Option<String> {
136
+ let offset = self.get_offset(client_offset);
137
+ Some(match self.orientation {
138
+ Orientation::Horizontal => {
139
+ format!("max-width:{offset}px;min-width:{offset}px;width:{offset}px")
140
+ },
141
+ Orientation::Vertical => {
142
+ format!("max-height:{offset}px;min-height:{offset}px;height:{offset}px")
143
+ },
144
+ })
145
+ }
146
+
147
+ pub fn get_dimensions(&self, client_offset: i32) -> (i32, i32) {
148
+ let offset = self.get_offset(client_offset);
149
+ match self.orientation {
150
+ Orientation::Horizontal => (std::cmp::max(MINIMUM_SIZE, offset), self.alt),
151
+ Orientation::Vertical => (self.alt, std::cmp::max(MINIMUM_SIZE, offset)),
152
+ }
153
+ }
154
+
155
+ /// Adds the event listeners, the corollary of `Drop`.
156
+ fn register_listeners(&self) -> ApiResult<()> {
157
+ let mousemove = self.mousemove.as_ref().unchecked_ref();
158
+ global::body().add_event_listener_with_callback("mousemove", mousemove)?;
159
+ let mouseup = self.mouseup.as_ref().unchecked_ref();
160
+ Ok(global::body().add_event_listener_with_callback("mouseup", mouseup)?)
161
+ }
162
+
163
+ /// Helper functions capture and release the global cursor while dragging is
164
+ /// occurring.
165
+ fn capture_cursor(&mut self) -> ApiResult<()> {
166
+ self.pointer_elem.set_pointer_capture(self.pointer_id)?;
167
+ self.cursor = self.body_style.get_property_value("cursor")?;
168
+ self.body_style
169
+ .set_property("cursor", match self.orientation {
170
+ Orientation::Horizontal => "col-resize",
171
+ Orientation::Vertical => "row-resize",
172
+ })?;
173
+
174
+ Ok(())
175
+ }
176
+
177
+ /// " but for release
178
+ fn release_cursor(&self) -> ApiResult<()> {
179
+ self.pointer_elem.release_pointer_capture(self.pointer_id)?;
180
+ Ok(self.body_style.set_property("cursor", &self.cursor)?)
181
+ }
182
+ }
183
+
184
+ #[derive(Clone, Copy, Default, Eq, PartialEq)]
185
+ pub enum Orientation {
186
+ #[default]
187
+ Horizontal,
188
+ Vertical,
189
+ }
190
+
191
+ #[derive(Properties, Default)]
192
+ pub struct SplitPanelProps {
193
+ pub children: Children,
194
+
195
+ #[prop_or_default]
196
+ pub id: Option<String>,
197
+
198
+ #[prop_or_default]
199
+ pub orientation: Orientation,
200
+
201
+ /// Whether to render `<></>` empty templates as empty child panels, or
202
+ /// omit them entirely.
203
+ #[prop_or_default]
204
+ pub skip_empty: bool,
205
+
206
+ /// Should the child panels by wrapped in `<div>` elements?
207
+ #[prop_or_default]
208
+ pub no_wrap: bool,
209
+
210
+ /// Should the panels be rendered/sized in _reverse_ order?
211
+ #[prop_or_default]
212
+ pub reverse: bool,
213
+
214
+ #[prop_or_default]
215
+ pub on_reset: Option<Callback<()>>,
216
+
217
+ #[prop_or_default]
218
+ pub on_resize: Option<Callback<(i32, i32)>>,
219
+
220
+ #[prop_or_default]
221
+ pub on_resize_finished: Option<Callback<()>>,
222
+
223
+ #[cfg(test)]
224
+ #[prop_or_default]
225
+ pub weak_link: WeakScope<SplitPanel>,
226
+
227
+ #[prop_or_default]
228
+ pub initial_size: Option<i32>,
229
+ }
230
+
231
+ impl SplitPanelProps {
232
+ fn validate(&self) -> bool {
233
+ !self.children.is_empty()
234
+ }
235
+ }
236
+
237
+ impl PartialEq for SplitPanelProps {
238
+ fn eq(&self, other: &Self) -> bool {
239
+ self.id == other.id
240
+ && self.children == other.children
241
+ && self.orientation == other.orientation
242
+ && self.reverse == other.reverse
243
+ }
244
+ }
245
+
246
+ pub enum SplitPanelMsg {
247
+ StartResizing(usize, i32, i32, HtmlElement),
248
+ MoveResizing(i32),
249
+ StopResizing,
250
+ Reset(usize),
251
+ }
252
+
253
+ /// A panel with 2 sub panels and a mouse-draggable divider which allows
254
+ /// apportioning the panel's width.
255
+ ///
256
+ /// # Examples
257
+ ///
258
+ /// ```
259
+ /// html! {
260
+ /// <SplitPanel id="app_panel">
261
+ /// <div id="A">
262
+ /// <div id="B">
263
+ /// <a href=".."></a>
264
+ /// </div>
265
+ /// </SplitPanel>
266
+ /// }
267
+ /// ```
268
+ pub struct SplitPanel {
269
+ resize_state: Option<ResizingState>,
270
+ refs: Vec<NodeRef>,
271
+ styles: Vec<Option<String>>,
272
+ on_reset: Option<Callback<()>>,
273
+ }
274
+
275
+ impl Component for SplitPanel {
276
+ type Message = SplitPanelMsg;
277
+ type Properties = SplitPanelProps;
278
+
279
+ fn create(ctx: &Context<Self>) -> Self {
280
+ assert!(ctx.props().validate());
281
+ enable_weak_link_test!(ctx.props(), ctx.link());
282
+ let len = ctx.props().children.len();
283
+ // cant just use vec![Default::default(); len] as it would
284
+ // use the same underlying NodeRef for each element.
285
+ let refs = Vec::from_iter(std::iter::repeat_with(Default::default).take(len));
286
+
287
+ let mut styles = vec![Default::default(); len];
288
+ if let Some(x) = &ctx.props().initial_size {
289
+ styles[0] = Some(match ctx.props().orientation {
290
+ Orientation::Horizontal => {
291
+ format!("max-width:{x}px;min-width:{x}px;width:{x}px")
292
+ },
293
+ Orientation::Vertical => {
294
+ format!("max-height:{x}px;min-height:{x}px;height:{x}px")
295
+ },
296
+ });
297
+ }
298
+
299
+ Self {
300
+ resize_state: None,
301
+ refs,
302
+ styles,
303
+ on_reset: None,
304
+ }
305
+ }
306
+
307
+ fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
308
+ match msg {
309
+ SplitPanelMsg::Reset(index) => {
310
+ self.styles[index] = None;
311
+ self.on_reset.clone_from(&ctx.props().on_reset);
312
+ },
313
+ SplitPanelMsg::StartResizing(index, client_offset, pointer_id, pointer_elem) => {
314
+ let elem = self.refs[index].cast::<HtmlElement>().unwrap();
315
+ let state =
316
+ ResizingState::new(index, client_offset, ctx, &elem, pointer_id, pointer_elem);
317
+
318
+ self.resize_state = state.ok();
319
+ },
320
+ SplitPanelMsg::StopResizing => {
321
+ self.resize_state = None;
322
+ if let Some(cb) = &ctx.props().on_resize_finished {
323
+ cb.emit(());
324
+ }
325
+ },
326
+ SplitPanelMsg::MoveResizing(client_offset) => {
327
+ if let Some(state) = self.resize_state.as_ref() {
328
+ if let Some(ref cb) = ctx.props().on_resize {
329
+ cb.emit(state.get_dimensions(client_offset));
330
+ }
331
+
332
+ self.styles[state.index] = state.get_style(client_offset);
333
+ }
334
+ },
335
+ };
336
+ true
337
+ }
338
+
339
+ fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {
340
+ if let Some(on_reset) = self.on_reset.take() {
341
+ on_reset.emit(());
342
+ }
343
+ }
344
+
345
+ fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
346
+ assert!(ctx.props().validate());
347
+ let new_len = ctx.props().children.len();
348
+ self.refs.resize_with(new_len, Default::default);
349
+ self.styles.resize(new_len, Default::default());
350
+ true
351
+ }
352
+
353
+ fn view(&self, ctx: &Context<Self>) -> Html {
354
+ let mut iter = ctx.props().children.iter();
355
+ let orientation = ctx.props().orientation;
356
+ let mut classes = classes!("split-panel");
357
+ if orientation == Orientation::Vertical {
358
+ classes.push("orient-vertical");
359
+ }
360
+
361
+ if ctx.props().reverse {
362
+ classes.push("orient-reverse");
363
+ }
364
+
365
+ let head = iter.next().unwrap();
366
+
367
+ let tail = iter
368
+ .filter(|x| !ctx.props().skip_empty || x != &html! { <></> })
369
+ .enumerate()
370
+ .map(|(i, x)| {
371
+ html! {
372
+ <key={i + 2}>
373
+ <SplitPanelDivider
374
+ {i}
375
+ orientation={ctx.props().orientation}
376
+ link={ctx.link().clone()}
377
+ />
378
+ if i == ctx.props().children.len() - 2 { { x } } else {
379
+ <SplitPanelChild
380
+ style={self.styles[i + 1].clone()}
381
+ ref_={self.refs[i + 1].clone()}
382
+ >
383
+ { x }
384
+ </SplitPanelChild>
385
+ }
386
+ </>
387
+ }
388
+ });
389
+
390
+ let contents = html! {
391
+ <>
392
+ <LocalStyle key=0 href={css!("containers/split-panel")} />
393
+ <SplitPanelChild key=1 style={self.styles[0].clone()} ref_={self.refs[0].clone()}>
394
+ { head }
395
+ </SplitPanelChild>
396
+ { for tail }
397
+ </>
398
+ };
399
+
400
+ // TODO consider removing this
401
+ if ctx.props().no_wrap {
402
+ html! { { contents } }
403
+ } else {
404
+ html! { <div id={ctx.props().id.clone()} class={classes}>{ contents }</div> }
405
+ }
406
+ }
407
+ }
408
+
409
+ #[derive(Properties)]
410
+ struct SplitPanelDividerProps {
411
+ i: usize,
412
+ orientation: Orientation,
413
+ link: Scope<SplitPanel>,
414
+ }
415
+
416
+ impl PartialEq for SplitPanelDividerProps {
417
+ fn eq(&self, rhs: &Self) -> bool {
418
+ self.i == rhs.i && self.orientation == rhs.orientation
419
+ }
420
+ }
421
+
422
+ /// The resize handle for a `SplitPanel`.
423
+ #[function_component(SplitPanelDivider)]
424
+ fn split_panel_divider(props: &SplitPanelDividerProps) -> Html {
425
+ let orientation = props.orientation;
426
+ let i = props.i;
427
+ let link = props.link.clone();
428
+ let onmousedown = link.callback(move |event: PointerEvent| {
429
+ let target = event.target().unwrap().unchecked_into::<HtmlElement>();
430
+ let pointer_id = event.pointer_id();
431
+ let size = match orientation {
432
+ Orientation::Horizontal => event.client_x(),
433
+ Orientation::Vertical => event.client_y(),
434
+ };
435
+
436
+ SplitPanelMsg::StartResizing(i, size, pointer_id, target)
437
+ });
438
+
439
+ let ondblclick = props.link.callback(move |event: MouseEvent| {
440
+ event.prevent_default();
441
+ event.stop_propagation();
442
+ SplitPanelMsg::Reset(i)
443
+ });
444
+
445
+ // TODO Not sure why, but under some circumstances this can trigger a
446
+ // `dragstart`, leading to further drag events which cause perspective
447
+ // havoc. `event.prevent_default()` in `onmousedown` alternatively fixes
448
+ // this, but also prevents this event from trigger focus-stealing e.g. from
449
+ // open dialogs.
450
+ let ondragstart = Callback::from(|event: DragEvent| event.prevent_default());
451
+
452
+ html! {
453
+ <>
454
+ <div
455
+ class="split-panel-divider"
456
+ {ondragstart}
457
+ onpointerdown={onmousedown}
458
+ {ondblclick}
459
+ />
460
+ </>
461
+ }
462
+ }
463
+
464
+ #[derive(Properties, PartialEq)]
465
+ struct SplitPanelChildProps {
466
+ style: Option<String>,
467
+ ref_: NodeRef,
468
+ children: Children,
469
+ }
470
+
471
+ #[function_component(SplitPanelChild)]
472
+ fn split_panel_child(props: &SplitPanelChildProps) -> Html {
473
+ let class = if props.style.is_some() {
474
+ classes!("split-panel-child", "is-width-override")
475
+ } else {
476
+ classes!("split-panel-child")
477
+ };
478
+ html! {
479
+ <div {class} ref={props.ref_.clone()} style={props.style.clone()}>
480
+ { props.children.iter().next().unwrap() }
481
+ </div>
482
+ }
483
+ }
@@ -0,0 +1,104 @@
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 yew::{Callback, Children, Component, Html, Properties, classes, html};
14
+
15
+ use crate::components::style::LocalStyle;
16
+ use crate::css;
17
+
18
+ pub trait Tab: PartialEq + std::fmt::Display + Clone + Default + 'static {}
19
+
20
+ impl Tab for String {}
21
+
22
+ impl Tab for &'static str {}
23
+
24
+ #[derive(Properties, Debug, PartialEq)]
25
+ pub struct TabListProps<T: Tab> {
26
+ // all possible tabs
27
+ pub tabs: Vec<T>,
28
+ pub on_tab_change: Callback<(usize, T)>,
29
+ pub selected_tab: Option<usize>,
30
+ // the curently instantiated tabs
31
+ pub children: Children,
32
+ }
33
+
34
+ pub enum TabListMsg {
35
+ SetSelected(usize),
36
+ }
37
+
38
+ pub struct TabList<T: Tab> {
39
+ t: std::marker::PhantomData<T>,
40
+ selected_idx: usize,
41
+ }
42
+
43
+ impl<T: Tab> Component for TabList<T> {
44
+ type Message = TabListMsg;
45
+ type Properties = TabListProps<T>;
46
+
47
+ fn create(_ctx: &yew::Context<Self>) -> Self {
48
+ Self {
49
+ t: std::marker::PhantomData,
50
+ selected_idx: 0,
51
+ }
52
+ }
53
+
54
+ fn update(&mut self, ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
55
+ match msg {
56
+ TabListMsg::SetSelected(idx) => {
57
+ ctx.props()
58
+ .on_tab_change
59
+ .emit((idx, ctx.props().tabs[idx].clone()));
60
+ self.selected_idx = idx;
61
+ true
62
+ },
63
+ }
64
+ }
65
+
66
+ fn changed(&mut self, ctx: &yew::Context<Self>, _old_props: &Self::Properties) -> bool {
67
+ self.selected_idx = ctx.props().selected_tab.unwrap_or_default();
68
+ true
69
+ }
70
+
71
+ fn view(&self, ctx: &yew::Context<Self>) -> Html {
72
+ let p = ctx.props();
73
+ let gutter_tabs = p.tabs.iter().enumerate().map(|(idx, tab)| {
74
+ let mut class = classes!("tab");
75
+ if idx == self.selected_idx {
76
+ class.push("selected");
77
+ }
78
+
79
+ let onclick = ctx.link().callback(move |_| TabListMsg::SetSelected(idx));
80
+ html! {
81
+ <span {class} {onclick}>
82
+ <div class="tab-title" id={tab.to_string()} />
83
+ <div class="tab-border" />
84
+ </span>
85
+ }
86
+ });
87
+
88
+ html! {
89
+ <>
90
+ <LocalStyle href={css!("containers/tabs")} />
91
+ <div class="tab-gutter">
92
+ { for gutter_tabs }
93
+ <span class="tab tab-padding">
94
+ <div class="tab-title">{ "\u{00a0}" }</div>
95
+ <div class="tab-border" />
96
+ </span>
97
+ </div>
98
+ <div id="format-tab" class="tab-content">
99
+ { ctx.props().children.iter().nth(self.selected_idx) }
100
+ </div>
101
+ </>
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,11 @@
1
+ // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2
+ // ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3
+ // ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4
+ // ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5
+ // ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6
+ // ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7
+ // ┃ Copyright (c) 2017, the Perspective Authors. ┃
8
+ // ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9
+ // ┃ This file is part of the Perspective library, distributed under the terms ┃
10
+ // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
+ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
@@ -0,0 +1,91 @@
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 wasm_bindgen_test::*;
14
+ use web_sys::HtmlElement;
15
+ use yew::prelude::*;
16
+
17
+ use super::super::split_panel::{SplitPanel, SplitPanelMsg};
18
+ use crate::utils::{await_animation_frame, WeakScope};
19
+ use crate::*;
20
+
21
+ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
22
+
23
+ #[wasm_bindgen_test]
24
+ pub async fn test_resizes_larger() {
25
+ let link: WeakScope<SplitPanel> = WeakScope::default();
26
+ let panel_div = NodeRef::default();
27
+ test_html! {
28
+ <SplitPanel id="test" weak_link={ link.clone() }>
29
+ <div ref={ panel_div.clone() } style="background-color: red"></div>
30
+ <div style="background-color: green"></div>
31
+ </SplitPanel>
32
+ };
33
+
34
+ await_animation_frame().await.unwrap();
35
+ let split_panel = link.borrow().clone().unwrap();
36
+ split_panel.send_message(SplitPanelMsg::StartResizing(0, 10));
37
+ split_panel.send_message(SplitPanelMsg::MoveResizing(100));
38
+ split_panel.send_message(SplitPanelMsg::StopResizing);
39
+ await_animation_frame().await.unwrap();
40
+
41
+ let width = panel_div.cast::<HtmlElement>().unwrap().offset_width();
42
+ assert_eq!(width, 90);
43
+ }
44
+
45
+ #[wasm_bindgen_test]
46
+ pub async fn test_resizes_narrower() {
47
+ let link: WeakScope<SplitPanel> = WeakScope::default();
48
+ let panel_div = NodeRef::default();
49
+ test_html! {
50
+ <SplitPanel id="test" weak_link={ link.clone() }>
51
+ <div ref={ panel_div.clone() } style="background-color: red"></div>
52
+ <div style="background-color: green"></div>
53
+ </SplitPanel>
54
+ };
55
+
56
+ await_animation_frame().await.unwrap();
57
+ let split_panel = link.borrow().clone().unwrap();
58
+ split_panel.send_message(SplitPanelMsg::StartResizing(0, 10));
59
+ split_panel.send_message(SplitPanelMsg::MoveResizing(100));
60
+ split_panel.send_message(SplitPanelMsg::StopResizing);
61
+ await_animation_frame().await.unwrap();
62
+ split_panel.send_message(SplitPanelMsg::StartResizing(0, 100));
63
+ split_panel.send_message(SplitPanelMsg::MoveResizing(50));
64
+ split_panel.send_message(SplitPanelMsg::StopResizing);
65
+ await_animation_frame().await.unwrap();
66
+
67
+ let width = panel_div.cast::<HtmlElement>().unwrap().offset_width();
68
+ assert_eq!(width, 40);
69
+ }
70
+
71
+ #[wasm_bindgen_test]
72
+ pub async fn test_double_click_reset() {
73
+ let link: WeakScope<SplitPanel> = WeakScope::default();
74
+ let panel_div = NodeRef::default();
75
+ test_html! {
76
+ <SplitPanel id="test" weak_link={ link.clone() }>
77
+ <div ref={ panel_div.clone() } style="background-color: red"></div>
78
+ <div style="background-color: green"></div>
79
+ </SplitPanel>
80
+ };
81
+
82
+ await_animation_frame().await.unwrap();
83
+ let split_panel = link.borrow().clone().unwrap();
84
+ split_panel.send_message(SplitPanelMsg::StartResizing(0, 10));
85
+ split_panel.send_message(SplitPanelMsg::MoveResizing(100));
86
+ split_panel.send_message(SplitPanelMsg::StopResizing);
87
+ split_panel.send_message(SplitPanelMsg::Reset(0));
88
+
89
+ let width = panel_div.cast::<HtmlElement>().unwrap().offset_width();
90
+ assert_eq!(width, 0);
91
+ }