1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize, de::DeserializeOwned};
4use serde_json::Value;
5use wasm_bindgen::prelude::*;
6
7use ui_grid_core::{
8 display::format_grid_cell_display_value,
9 edit::{
10 GridMoveDirection, begin_grid_edit_session, build_grid_focus_cell_result,
11 clear_grid_edit_session, find_next_grid_cell, is_grid_cell_position, is_printable_grid_key,
12 parse_grid_edited_value, should_grid_edit_on_focus, stringify_grid_editor_value,
13 },
14 export::{export_csv_rows, header_label},
15 filtering::{clear_grid_filter_reasons, matches_grid_row_filters},
16 grouping::build_grid_display_items,
17 identity::{build_grid_sort_state, find_grid_row_by_id, resolve_grid_row_id},
18 infinite_scroll::{
19 MaybeRequestInfiniteScrollDataContext, complete_infinite_scroll_data_load,
20 maybe_request_infinite_scroll_data, reset_infinite_scroll_state,
21 save_infinite_scroll_percentage, set_infinite_scroll_directions_state,
22 },
23 models::{
24 BuildGridPipelineContext, GridCellPosition, GridColumnDef, GridLabels, GridOptions,
25 GridRecord, GridRow, SortState,
26 },
27 pagination::{
28 get_current_page_value, get_effective_page_size, get_first_row_index_value,
29 get_last_row_index_value, get_total_pages_value, is_virtualization_enabled,
30 paginate_grid_rows, resolve_grid_page_size, seek_grid_page,
31 },
32 pinning::{
33 PinDirection, PinnedColumnState, build_initial_pinned_state, compute_pinned_offset,
34 get_column_pin_direction, is_column_pinnable, is_pinning_enabled, pin_column_state,
35 pinning_button_label,
36 },
37 pipeline::build_grid_pipeline,
38 row_state::{
39 add_grid_row_invisible_reason, are_all_grid_rows_expanded, clear_grid_row_invisible_reason,
40 expand_all_grid_rows, expand_all_grid_tree_rows, get_grid_tree_row_children,
41 set_grid_tree_row_expanded, toggle_grid_row_expanded, toggle_grid_tree_row_expanded,
42 },
43 sorting::sort_grid_rows,
44 state::{
45 BuildGridSavedStateContext, build_grid_saved_state, is_safe_state_key,
46 normalize_boolean_map, normalize_grid_saved_state, sanitize_download_filename,
47 },
48 tree::{build_grid_rows, filter_and_flatten_grid_tree_rows, is_tree_enabled},
49 utils::{get_cell_value, get_path_value, stringify_cell_value, titleize},
50 viewmodel::{
51 can_grid_expand_rows, can_grid_move_columns, grid_cell_indent, grid_column_width,
52 grid_editor_input_type, grid_expand_toggle_label, grid_expand_toggle_label_for_row,
53 grid_filter_placeholder, grid_group_disclosure_label, grid_grouping_button_label,
54 grid_sort_aria_sort, grid_sort_button_label, grid_tree_toggle_label,
55 grid_tree_toggle_label_for_row, is_grid_column_filterable, is_grid_column_grouped,
56 is_grid_column_sortable, is_grid_filtering_enabled, is_grid_grouping_enabled,
57 is_grid_infinite_scroll_enabled, is_grid_pagination_enabled, is_grid_primary_column,
58 is_grid_sorting_enabled, is_grid_tree_enabled, is_grid_tree_row_expanded,
59 resolve_grid_labels, should_show_grid_expand_toggle, should_show_grid_pagination_controls,
60 should_show_grid_tree_toggle,
61 },
62};
63use ui_grid_virtualization::{VirtualWindowRequest, calculate_virtual_window};
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
66#[serde(rename_all = "camelCase")]
67struct OptionsColumnInput {
68 options: GridOptions,
69 column: GridColumnDef,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
73#[serde(rename_all = "camelCase")]
74struct VisibleColumnsColumnInput {
75 visible_columns: Vec<GridColumnDef>,
76 column: GridColumnDef,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
80#[serde(rename_all = "camelCase")]
81struct OptionsVisibleColumnsRowColumnInput {
82 options: GridOptions,
83 visible_columns: Vec<GridColumnDef>,
84 row: GridRow,
85 column: GridColumnDef,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
89#[serde(rename_all = "camelCase")]
90struct OptionsVisibleColumnsColumnInput {
91 options: GridOptions,
92 visible_columns: Vec<GridColumnDef>,
93 column: GridColumnDef,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
97#[serde(rename_all = "camelCase")]
98struct DirectionLabelsInput {
99 direction: ui_grid_core::constants::SortDirection,
100 labels: GridLabels,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
104#[serde(rename_all = "camelCase")]
105struct BooleanLabelsInput {
106 value: bool,
107 labels: GridLabels,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(rename_all = "camelCase")]
112struct GroupByColumnInput {
113 group_by_columns: Vec<String>,
114 column: GridColumnDef,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
118#[serde(rename_all = "camelCase")]
119struct ExpandedTreeRowsRowInput {
120 expanded_tree_rows: BTreeMap<String, bool>,
121 row: GridRow,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125#[serde(rename_all = "camelCase")]
126struct ExpandedTreeRowsRowLabelsInput {
127 expanded_tree_rows: BTreeMap<String, bool>,
128 row: GridRow,
129 labels: GridLabels,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133#[serde(rename_all = "camelCase")]
134struct RowLabelsInput {
135 row: GridRow,
136 labels: GridLabels,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
140#[serde(rename_all = "camelCase")]
141struct PinnedColumnsColumnInput {
142 pinned_columns: PinnedColumnState,
143 column: GridColumnDef,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148struct PinColumnStateInput {
149 current: PinnedColumnState,
150 column_name: String,
151 direction: PinDirection,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
155#[serde(rename_all = "camelCase")]
156struct VisibleColumnsPinnedColumnsColumnInput {
157 visible_columns: Vec<GridColumnDef>,
158 pinned_columns: PinnedColumnState,
159 column: GridColumnDef,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
163#[serde(rename_all = "camelCase")]
164struct PinnedColumnsColumnLabelsInput {
165 pinned_columns: PinnedColumnState,
166 column: GridColumnDef,
167 labels: GridLabels,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
171#[serde(rename_all = "camelCase")]
172struct CellPositionMatchInput {
173 position: Option<GridCellPosition>,
174 row_id: String,
175 column_name: String,
176}
177
178#[derive(Debug, Clone, Serialize, Deserialize)]
179#[serde(rename_all = "camelCase")]
180struct BeginEditSessionInput {
181 row_id: String,
182 column_name: String,
183 editing_value: String,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
187#[serde(rename_all = "camelCase")]
188struct BuildGridFocusCellResultInput {
189 current_focused_cell: Option<GridCellPosition>,
190 current_editing_cell: Option<GridCellPosition>,
191 row_id: String,
192 column_name: String,
193 should_edit_on_focus: bool,
194 is_cell_editable: bool,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
198#[serde(rename_all = "camelCase")]
199struct FindNextGridCellInput {
200 rows: Vec<GridRow>,
201 columns: Vec<GridColumnDef>,
202 row_id: String,
203 column_name: String,
204 direction: GridMoveDirection,
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize)]
208#[serde(rename_all = "camelCase")]
209struct ParseGridEditedValueInput {
210 column: GridColumnDef,
211 value: String,
212 old_value: Value,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
216#[serde(rename_all = "camelCase")]
217struct PrintableGridKeyInput {
218 key: String,
219 ctrl_key: bool,
220 meta_key: bool,
221 alt_key: bool,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
225#[serde(rename_all = "camelCase")]
226struct InfiniteScrollLoadInput {
227 state: ui_grid_core::models::GridInfiniteScrollState,
228 scroll_up: bool,
229 scroll_down: bool,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
233#[serde(rename_all = "camelCase")]
234struct InfiniteScrollVisibleRowsInput {
235 state: ui_grid_core::models::GridInfiniteScrollState,
236 visible_rows: usize,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize)]
240#[serde(rename_all = "camelCase")]
241struct InfiniteScrollDirectionsInput {
242 state: ui_grid_core::models::GridInfiniteScrollState,
243 scroll_up: bool,
244 scroll_down: bool,
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
248#[serde(rename_all = "camelCase")]
249struct ExpandedRowsRowIdInput {
250 expanded_rows: BTreeMap<String, bool>,
251 row_id: String,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
255#[serde(rename_all = "camelCase")]
256struct ExpandedTreeRowsRowIdExpandedInput {
257 expanded_tree_rows: BTreeMap<String, bool>,
258 row_id: String,
259 expanded: bool,
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize)]
263#[serde(rename_all = "camelCase")]
264struct RowsExpandedRowsInput {
265 rows: Vec<GridRow>,
266 expanded_rows: BTreeMap<String, bool>,
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize)]
270#[serde(rename_all = "camelCase")]
271struct HiddenRowReasonInput {
272 hidden_row_reasons: BTreeMap<String, Vec<String>>,
273 row_id: String,
274 reason: String,
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
278#[serde(rename_all = "camelCase")]
279struct PaginationInput {
280 options: GridOptions,
281 page_size: usize,
282 total_items: usize,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
286#[serde(rename_all = "camelCase")]
287struct PaginationPageInput {
288 options: GridOptions,
289 current_page: usize,
290 total_items: usize,
291 page_size: usize,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
295#[serde(rename_all = "camelCase")]
296struct PaginateRowsInput {
297 rows: Vec<GridRow>,
298 options: GridOptions,
299 current_page: usize,
300 page_size: usize,
301 total_items: usize,
302}
303
304#[derive(Debug, Clone, Serialize, Deserialize)]
305#[serde(rename_all = "camelCase")]
306struct VirtualizationInput {
307 options: GridOptions,
308 item_count: usize,
309}
310
311#[derive(Debug, Clone, Serialize, Deserialize)]
312#[serde(rename_all = "camelCase")]
313struct SeekGridPageInput {
314 page: usize,
315 total_pages: usize,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
319#[serde(rename_all = "camelCase")]
320struct SortRowsInput {
321 rows: Vec<GridRow>,
322 columns: Vec<GridColumnDef>,
323 options: GridOptions,
324 sort_state: SortState,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize)]
328#[serde(rename_all = "camelCase")]
329struct FindGridRowByIdInput {
330 rows: Vec<GridRow>,
331 row_id: String,
332}
333
334#[derive(Debug, Clone, Serialize, Deserialize)]
335#[serde(rename_all = "camelCase")]
336struct BuildGridSortStateInput {
337 column_name: String,
338 direction: Option<ui_grid_core::constants::SortDirection>,
339}
340
341#[derive(Debug, Clone, Serialize, Deserialize)]
342#[serde(rename_all = "camelCase")]
343struct ResolveGridRowIdInput {
344 options: GridOptions,
345 row: Value,
346}
347
348#[derive(Debug, Clone, Serialize, Deserialize)]
349#[serde(rename_all = "camelCase")]
350struct FormatGridCellDisplayValueInput {
351 row: GridRow,
352 column: GridColumnDef,
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize)]
356#[serde(rename_all = "camelCase")]
357struct HeaderLabelInput {
358 column: GridColumnDef,
359}
360
361#[derive(Debug, Clone, Serialize, Deserialize)]
362#[serde(rename_all = "camelCase")]
363struct MatchesGridRowFiltersInput {
364 row: GridRow,
365 columns: Vec<GridColumnDef>,
366 options: GridOptions,
367 active_filters: BTreeMap<String, String>,
368}
369
370#[derive(Debug, Clone, Serialize, Deserialize)]
371#[serde(rename_all = "camelCase")]
372struct MatchesGridRowFiltersResult {
373 row: GridRow,
374 matches: bool,
375}
376
377#[derive(Debug, Clone, Serialize, Deserialize)]
378#[serde(rename_all = "camelCase")]
379struct BuildGridRowsInput {
380 options: GridOptions,
381 row_size: usize,
382 hidden_row_reasons: BTreeMap<String, Vec<String>>,
383 expanded_rows: BTreeMap<String, bool>,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize)]
387#[serde(rename_all = "camelCase")]
388struct FilterFlattenTreeRowsInput {
389 rows: Vec<GridRow>,
390 columns: Vec<GridColumnDef>,
391 options: GridOptions,
392 active_filters: BTreeMap<String, String>,
393 expanded_tree_rows: BTreeMap<String, bool>,
394 sort_state: SortState,
395}
396
397#[derive(Debug, Clone, Serialize, Deserialize)]
398#[serde(rename_all = "camelCase")]
399struct PathValueInput {
400 record: GridRecord,
401 path: String,
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize)]
405#[serde(rename_all = "camelCase")]
406struct CellValueInput {
407 row: GridRecord,
408 column: GridColumnDef,
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize)]
412#[serde(rename_all = "camelCase")]
413struct StringifyCellValueInput {
414 value: Value,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
418#[serde(rename_all = "camelCase")]
419struct TitleizeInput {
420 value: String,
421}
422
423#[derive(Debug, Clone, Serialize, Deserialize)]
424#[serde(rename_all = "camelCase")]
425struct BuildGridDisplayItemsInput {
426 rows: Vec<GridRow>,
427 columns: Vec<GridColumnDef>,
428 options: GridOptions,
429 group_by: Vec<String>,
430 collapsed_groups: BTreeMap<String, bool>,
431}
432
433#[derive(Debug, Clone, Serialize, Deserialize)]
434#[serde(rename_all = "camelCase")]
435struct NormalizeBooleanMapInput {
436 value: serde_json::Map<String, Value>,
437}
438
439fn from_js<T: DeserializeOwned>(value: JsValue) -> Result<T, JsValue> {
440 serde_wasm_bindgen::from_value(value)
441 .map_err(|error| JsValue::from_str(&format!("failed to decode wasm input: {error}")))
442}
443
444fn to_js<T: serde::Serialize>(value: &T) -> Result<JsValue, JsValue> {
445 let serializer = serde_wasm_bindgen::Serializer::json_compatible();
446 value
447 .serialize(&serializer)
448 .map_err(|error| JsValue::from_str(&format!("failed to encode wasm output: {error}")))
449}
450
451#[wasm_bindgen(start)]
452pub fn start() {
453 console_error_panic_hook::set_once();
454}
455
456#[wasm_bindgen]
457pub fn version() -> String {
458 env!("CARGO_PKG_VERSION").to_string()
459}
460
461#[wasm_bindgen]
464pub fn build_pipeline_js(context: JsValue) -> Result<JsValue, JsValue> {
465 let context: BuildGridPipelineContext = from_js(context)?;
466 let result = build_grid_pipeline(&context);
467 to_js(&result)
468}
469
470#[wasm_bindgen]
471pub fn build_grid_pipeline_js(context: JsValue) -> Result<JsValue, JsValue> {
472 build_pipeline_js(context)
473}
474
475#[wasm_bindgen]
478pub fn resolve_grid_labels_js(overrides: JsValue) -> Result<JsValue, JsValue> {
479 if overrides.is_null() || overrides.is_undefined() {
480 return to_js(&resolve_grid_labels(None));
481 }
482
483 let overrides: GridLabels = from_js(overrides)?;
484 to_js(&resolve_grid_labels(Some(&overrides)))
485}
486
487#[wasm_bindgen]
488pub fn is_grid_tree_enabled_js(options: JsValue) -> Result<bool, JsValue> {
489 let options: GridOptions = from_js(options)?;
490 Ok(is_grid_tree_enabled(&options))
491}
492
493#[wasm_bindgen]
494pub fn is_grid_grouping_enabled_js(options: JsValue) -> Result<bool, JsValue> {
495 let options: GridOptions = from_js(options)?;
496 Ok(is_grid_grouping_enabled(&options))
497}
498
499#[wasm_bindgen]
500pub fn can_grid_expand_rows_js(options: JsValue) -> Result<bool, JsValue> {
501 let options: GridOptions = from_js(options)?;
502 Ok(can_grid_expand_rows(&options))
503}
504
505#[wasm_bindgen]
506pub fn is_grid_pagination_enabled_js(options: JsValue) -> Result<bool, JsValue> {
507 let options: GridOptions = from_js(options)?;
508 Ok(is_grid_pagination_enabled(&options))
509}
510
511#[wasm_bindgen]
512pub fn should_show_grid_pagination_controls_js(options: JsValue) -> Result<bool, JsValue> {
513 let options: GridOptions = from_js(options)?;
514 Ok(should_show_grid_pagination_controls(&options))
515}
516
517#[wasm_bindgen]
518pub fn is_grid_infinite_scroll_enabled_js(options: JsValue) -> Result<bool, JsValue> {
519 let options: GridOptions = from_js(options)?;
520 Ok(is_grid_infinite_scroll_enabled(&options))
521}
522
523#[wasm_bindgen]
524pub fn is_grid_sorting_enabled_js(options: JsValue) -> Result<bool, JsValue> {
525 let options: GridOptions = from_js(options)?;
526 Ok(is_grid_sorting_enabled(&options))
527}
528
529#[wasm_bindgen]
530pub fn is_grid_filtering_enabled_js(options: JsValue) -> Result<bool, JsValue> {
531 let options: GridOptions = from_js(options)?;
532 Ok(is_grid_filtering_enabled(&options))
533}
534
535#[wasm_bindgen]
536pub fn can_grid_move_columns_js(options: JsValue) -> Result<bool, JsValue> {
537 let options: GridOptions = from_js(options)?;
538 Ok(can_grid_move_columns(&options))
539}
540
541#[wasm_bindgen]
542pub fn is_grid_primary_column_js(input: JsValue) -> Result<bool, JsValue> {
543 let input: VisibleColumnsColumnInput = from_js(input)?;
544 Ok(is_grid_primary_column(
545 &input.visible_columns,
546 &input.column,
547 ))
548}
549
550#[wasm_bindgen]
551pub fn is_grid_column_sortable_js(input: JsValue) -> Result<bool, JsValue> {
552 let input: OptionsColumnInput = from_js(input)?;
553 Ok(is_grid_column_sortable(&input.options, &input.column))
554}
555
556#[wasm_bindgen]
557pub fn is_grid_column_filterable_js(input: JsValue) -> Result<bool, JsValue> {
558 let input: OptionsColumnInput = from_js(input)?;
559 Ok(is_grid_column_filterable(&input.options, &input.column))
560}
561
562#[wasm_bindgen]
563pub fn should_show_grid_tree_toggle_js(input: JsValue) -> Result<bool, JsValue> {
564 let input: OptionsVisibleColumnsRowColumnInput = from_js(input)?;
565 Ok(should_show_grid_tree_toggle(
566 &input.options,
567 &input.visible_columns,
568 &input.row,
569 &input.column,
570 ))
571}
572
573#[wasm_bindgen]
574pub fn should_show_grid_expand_toggle_js(input: JsValue) -> Result<bool, JsValue> {
575 let input: OptionsVisibleColumnsColumnInput = from_js(input)?;
576 Ok(should_show_grid_expand_toggle(
577 &input.options,
578 &input.visible_columns,
579 &input.column,
580 ))
581}
582
583#[wasm_bindgen]
584pub fn grid_sort_button_label_js(input: JsValue) -> Result<String, JsValue> {
585 let input: DirectionLabelsInput = from_js(input)?;
586 Ok(grid_sort_button_label(input.direction, &input.labels))
587}
588
589#[wasm_bindgen]
590pub fn grid_sort_aria_sort_js(direction: JsValue) -> Result<String, JsValue> {
591 let direction: ui_grid_core::constants::SortDirection = from_js(direction)?;
592 Ok(grid_sort_aria_sort(direction))
593}
594
595#[wasm_bindgen]
596pub fn grid_grouping_button_label_js(input: JsValue) -> Result<String, JsValue> {
597 let input: BooleanLabelsInput = from_js(input)?;
598 Ok(grid_grouping_button_label(input.value, &input.labels))
599}
600
601#[wasm_bindgen]
602pub fn grid_filter_placeholder_js(input: JsValue) -> Result<String, JsValue> {
603 let input: BooleanLabelsInput = from_js(input)?;
604 Ok(grid_filter_placeholder(input.value, &input.labels))
605}
606
607#[wasm_bindgen]
608pub fn grid_group_disclosure_label_js(input: JsValue) -> Result<String, JsValue> {
609 let input: BooleanLabelsInput = from_js(input)?;
610 Ok(grid_group_disclosure_label(input.value, &input.labels))
611}
612
613#[wasm_bindgen]
614pub fn grid_editor_input_type_js(column: JsValue) -> Result<String, JsValue> {
615 let column: GridColumnDef = from_js(column)?;
616 Ok(grid_editor_input_type(&column))
617}
618
619#[wasm_bindgen]
620pub fn grid_column_width_js(column: JsValue) -> Result<String, JsValue> {
621 let column: GridColumnDef = from_js(column)?;
622 Ok(grid_column_width(&column))
623}
624
625#[wasm_bindgen]
626pub fn grid_cell_indent_js(input: JsValue) -> Result<String, JsValue> {
627 let input: OptionsVisibleColumnsRowColumnInput = from_js(input)?;
628 Ok(grid_cell_indent(
629 &input.options,
630 &input.visible_columns,
631 &input.row,
632 &input.column,
633 ))
634}
635
636#[wasm_bindgen]
637pub fn grid_tree_toggle_label_js(input: JsValue) -> Result<String, JsValue> {
638 let input: BooleanLabelsInput = from_js(input)?;
639 Ok(grid_tree_toggle_label(input.value, &input.labels))
640}
641
642#[wasm_bindgen]
643pub fn grid_expand_toggle_label_js(input: JsValue) -> Result<String, JsValue> {
644 let input: BooleanLabelsInput = from_js(input)?;
645 Ok(grid_expand_toggle_label(input.value, &input.labels))
646}
647
648#[wasm_bindgen]
649pub fn is_grid_column_grouped_js(input: JsValue) -> Result<bool, JsValue> {
650 let input: GroupByColumnInput = from_js(input)?;
651 Ok(is_grid_column_grouped(
652 &input.group_by_columns,
653 &input.column,
654 ))
655}
656
657#[wasm_bindgen]
658pub fn is_grid_tree_row_expanded_js(input: JsValue) -> Result<bool, JsValue> {
659 let input: ExpandedTreeRowsRowInput = from_js(input)?;
660 Ok(is_grid_tree_row_expanded(
661 &input.expanded_tree_rows,
662 &input.row,
663 ))
664}
665
666#[wasm_bindgen]
667pub fn grid_tree_toggle_label_for_row_js(input: JsValue) -> Result<String, JsValue> {
668 let input: ExpandedTreeRowsRowLabelsInput = from_js(input)?;
669 Ok(grid_tree_toggle_label_for_row(
670 &input.expanded_tree_rows,
671 &input.row,
672 &input.labels,
673 ))
674}
675
676#[wasm_bindgen]
677pub fn grid_expand_toggle_label_for_row_js(input: JsValue) -> Result<String, JsValue> {
678 let input: RowLabelsInput = from_js(input)?;
679 Ok(grid_expand_toggle_label_for_row(&input.row, &input.labels))
680}
681
682#[wasm_bindgen]
685pub fn is_pinning_enabled_js(options: JsValue) -> Result<bool, JsValue> {
686 let options: GridOptions = from_js(options)?;
687 Ok(is_pinning_enabled(&options))
688}
689
690#[wasm_bindgen]
691pub fn is_column_pinnable_js(input: JsValue) -> Result<bool, JsValue> {
692 let input: OptionsColumnInput = from_js(input)?;
693 Ok(is_column_pinnable(&input.options, &input.column))
694}
695
696#[wasm_bindgen]
697pub fn get_column_pin_direction_js(input: JsValue) -> Result<JsValue, JsValue> {
698 let input: PinnedColumnsColumnInput = from_js(input)?;
699 to_js(&get_column_pin_direction(
700 &input.pinned_columns,
701 &input.column,
702 ))
703}
704
705#[wasm_bindgen]
706pub fn pin_column_state_js(input: JsValue) -> Result<JsValue, JsValue> {
707 let input: PinColumnStateInput = from_js(input)?;
708 to_js(&pin_column_state(
709 &input.current,
710 &input.column_name,
711 input.direction,
712 ))
713}
714
715#[wasm_bindgen]
716pub fn build_initial_pinned_state_js(columns: JsValue) -> Result<JsValue, JsValue> {
717 let columns: Vec<GridColumnDef> = from_js(columns)?;
718 to_js(&build_initial_pinned_state(&columns))
719}
720
721#[wasm_bindgen]
722pub fn compute_pinned_offset_js(input: JsValue) -> Result<JsValue, JsValue> {
723 let input: VisibleColumnsPinnedColumnsColumnInput = from_js(input)?;
724 to_js(&compute_pinned_offset(
725 &input.visible_columns,
726 &input.pinned_columns,
727 &input.column,
728 ))
729}
730
731#[wasm_bindgen]
732pub fn pinning_button_label_js(input: JsValue) -> Result<String, JsValue> {
733 let input: PinnedColumnsColumnLabelsInput = from_js(input)?;
734 Ok(pinning_button_label(
735 &input.pinned_columns,
736 &input.column,
737 &input.labels,
738 ))
739}
740
741#[wasm_bindgen]
744pub fn is_grid_cell_position_js(input: JsValue) -> Result<bool, JsValue> {
745 let input: CellPositionMatchInput = from_js(input)?;
746 Ok(is_grid_cell_position(
747 input.position.as_ref(),
748 &input.row_id,
749 &input.column_name,
750 ))
751}
752
753#[wasm_bindgen]
754pub fn begin_grid_edit_session_js(input: JsValue) -> Result<JsValue, JsValue> {
755 let input: BeginEditSessionInput = from_js(input)?;
756 to_js(&begin_grid_edit_session(
757 input.row_id,
758 input.column_name,
759 input.editing_value,
760 ))
761}
762
763#[wasm_bindgen]
764pub fn should_grid_edit_on_focus_js(input: JsValue) -> Result<bool, JsValue> {
765 let input: OptionsColumnInput = from_js(input)?;
766 Ok(should_grid_edit_on_focus(&input.options, &input.column))
767}
768
769#[wasm_bindgen]
770pub fn build_grid_focus_cell_result_js(input: JsValue) -> Result<JsValue, JsValue> {
771 let input: BuildGridFocusCellResultInput = from_js(input)?;
772 to_js(&build_grid_focus_cell_result(
773 input.current_focused_cell.as_ref(),
774 input.current_editing_cell.as_ref(),
775 input.row_id,
776 input.column_name,
777 input.should_edit_on_focus,
778 input.is_cell_editable,
779 ))
780}
781
782#[wasm_bindgen]
783pub fn clear_grid_edit_session_js() -> Result<JsValue, JsValue> {
784 to_js(&clear_grid_edit_session())
785}
786
787#[wasm_bindgen]
788pub fn find_next_grid_cell_js(input: JsValue) -> Result<JsValue, JsValue> {
789 let input: FindNextGridCellInput = from_js(input)?;
790 to_js(
791 &find_next_grid_cell::<fn(&GridRow, &GridColumnDef) -> bool>(
792 &input.rows,
793 &input.columns,
794 &input.row_id,
795 &input.column_name,
796 input.direction,
797 None,
798 ),
799 )
800}
801
802#[wasm_bindgen]
803pub fn stringify_grid_editor_value_js(value: JsValue) -> Result<String, JsValue> {
804 let value: Value = from_js(value)?;
805 Ok(stringify_grid_editor_value(&value))
806}
807
808#[wasm_bindgen]
809pub fn parse_grid_edited_value_js(input: JsValue) -> Result<JsValue, JsValue> {
810 let input: ParseGridEditedValueInput = from_js(input)?;
811 to_js(&parse_grid_edited_value(
812 &input.column,
813 &input.value,
814 &input.old_value,
815 ))
816}
817
818#[wasm_bindgen]
819pub fn is_printable_grid_key_js(input: JsValue) -> Result<bool, JsValue> {
820 let input: PrintableGridKeyInput = from_js(input)?;
821 Ok(is_printable_grid_key(
822 &input.key,
823 input.ctrl_key,
824 input.meta_key,
825 input.alt_key,
826 ))
827}
828
829#[wasm_bindgen]
832pub fn toggle_grid_row_expanded_js(input: JsValue) -> Result<JsValue, JsValue> {
833 let input: ExpandedRowsRowIdInput = from_js(input)?;
834 to_js(&toggle_grid_row_expanded(
835 &input.expanded_rows,
836 &input.row_id,
837 ))
838}
839
840#[wasm_bindgen]
841pub fn expand_all_grid_rows_js(rows: JsValue) -> Result<JsValue, JsValue> {
842 let rows: Vec<GridRow> = from_js(rows)?;
843 to_js(&expand_all_grid_rows(&rows))
844}
845
846#[wasm_bindgen]
847pub fn are_all_grid_rows_expanded_js(input: JsValue) -> Result<bool, JsValue> {
848 let input: RowsExpandedRowsInput = from_js(input)?;
849 Ok(are_all_grid_rows_expanded(
850 &input.rows,
851 &input.expanded_rows,
852 ))
853}
854
855#[wasm_bindgen]
856pub fn set_grid_tree_row_expanded_js(input: JsValue) -> Result<JsValue, JsValue> {
857 let input: ExpandedTreeRowsRowIdExpandedInput = from_js(input)?;
858 to_js(&set_grid_tree_row_expanded(
859 &input.expanded_tree_rows,
860 &input.row_id,
861 input.expanded,
862 ))
863}
864
865#[wasm_bindgen]
866pub fn toggle_grid_tree_row_expanded_js(input: JsValue) -> Result<JsValue, JsValue> {
867 let input: ExpandedRowsRowIdInput = from_js(input)?;
868 to_js(&toggle_grid_tree_row_expanded(
869 &input.expanded_rows,
870 &input.row_id,
871 ))
872}
873
874#[wasm_bindgen]
875pub fn expand_all_grid_tree_rows_js(rows: JsValue) -> Result<JsValue, JsValue> {
876 let rows: Vec<GridRow> = from_js(rows)?;
877 to_js(&expand_all_grid_tree_rows(&rows))
878}
879
880#[wasm_bindgen]
881pub fn get_grid_tree_row_children_js(input: JsValue) -> Result<JsValue, JsValue> {
882 let input: FindGridRowByIdInput = from_js(input)?;
883 to_js(&get_grid_tree_row_children(&input.rows, &input.row_id))
884}
885
886#[wasm_bindgen]
887pub fn add_grid_row_invisible_reason_js(input: JsValue) -> Result<JsValue, JsValue> {
888 let input: HiddenRowReasonInput = from_js(input)?;
889 to_js(&add_grid_row_invisible_reason(
890 &input.hidden_row_reasons,
891 &input.row_id,
892 &input.reason,
893 ))
894}
895
896#[wasm_bindgen]
897pub fn clear_grid_row_invisible_reason_js(input: JsValue) -> Result<JsValue, JsValue> {
898 let input: HiddenRowReasonInput = from_js(input)?;
899 to_js(&clear_grid_row_invisible_reason(
900 &input.hidden_row_reasons,
901 &input.row_id,
902 &input.reason,
903 ))
904}
905
906#[wasm_bindgen]
909pub fn get_effective_page_size_js(input: JsValue) -> Result<usize, JsValue> {
910 let input: PaginationInput = from_js(input)?;
911 Ok(get_effective_page_size(
912 &input.options,
913 input.page_size,
914 input.total_items,
915 ))
916}
917
918#[wasm_bindgen]
919pub fn get_total_pages_value_js(input: JsValue) -> Result<usize, JsValue> {
920 let input: PaginationInput = from_js(input)?;
921 Ok(get_total_pages_value(
922 &input.options,
923 input.total_items,
924 input.page_size,
925 ))
926}
927
928#[wasm_bindgen]
929pub fn get_current_page_value_js(input: JsValue) -> Result<usize, JsValue> {
930 let input: PaginationPageInput = from_js(input)?;
931 Ok(get_current_page_value(
932 &input.options,
933 input.current_page,
934 input.total_items,
935 input.page_size,
936 ))
937}
938
939#[wasm_bindgen]
940pub fn get_first_row_index_value_js(input: JsValue) -> Result<usize, JsValue> {
941 let input: PaginationPageInput = from_js(input)?;
942 Ok(get_first_row_index_value(
943 &input.options,
944 input.current_page,
945 input.total_items,
946 input.page_size,
947 ))
948}
949
950#[wasm_bindgen]
951pub fn get_last_row_index_value_js(input: JsValue) -> Result<usize, JsValue> {
952 let input: PaginationPageInput = from_js(input)?;
953 Ok(get_last_row_index_value(
954 &input.options,
955 input.current_page,
956 input.total_items,
957 input.page_size,
958 ))
959}
960
961#[wasm_bindgen]
962pub fn paginate_grid_rows_js(input: JsValue) -> Result<JsValue, JsValue> {
963 let input: PaginateRowsInput = from_js(input)?;
964 to_js(&paginate_grid_rows(
965 &input.rows,
966 &input.options,
967 input.current_page,
968 input.page_size,
969 input.total_items,
970 ))
971}
972
973#[wasm_bindgen]
974pub fn is_virtualization_enabled_js(input: JsValue) -> Result<bool, JsValue> {
975 let input: VirtualizationInput = from_js(input)?;
976 Ok(is_virtualization_enabled(&input.options, input.item_count))
977}
978
979#[wasm_bindgen]
980pub fn seek_grid_page_js(input: JsValue) -> Result<usize, JsValue> {
981 let input: SeekGridPageInput = from_js(input)?;
982 Ok(seek_grid_page(input.page, input.total_pages))
983}
984
985#[wasm_bindgen]
986pub fn resolve_grid_page_size_js(page_size: usize) -> Result<JsValue, JsValue> {
987 to_js(&resolve_grid_page_size(page_size))
988}
989
990#[wasm_bindgen]
993pub fn export_csv_rows_js(columns: JsValue, rows: JsValue) -> Result<String, JsValue> {
994 let columns: Vec<GridColumnDef> = from_js(columns)?;
995 let rows: Vec<GridRow> = from_js(rows)?;
996 Ok(export_csv_rows(&columns, &rows))
997}
998
999#[wasm_bindgen]
1000pub fn build_saved_state_js(context: JsValue) -> Result<JsValue, JsValue> {
1001 let context: BuildGridSavedStateContext = from_js(context)?;
1002 let result = build_grid_saved_state(context);
1003 to_js(&result)
1004}
1005
1006#[wasm_bindgen]
1007pub fn build_grid_saved_state_js(context: JsValue) -> Result<JsValue, JsValue> {
1008 build_saved_state_js(context)
1009}
1010
1011#[wasm_bindgen]
1012pub fn normalize_saved_state_js(state: JsValue) -> Result<JsValue, JsValue> {
1013 let state: serde_json::Value = from_js(state)?;
1014 let result = normalize_grid_saved_state(&state);
1015 to_js(&result)
1016}
1017
1018#[wasm_bindgen]
1019pub fn normalize_grid_saved_state_js(state: JsValue) -> Result<JsValue, JsValue> {
1020 normalize_saved_state_js(state)
1021}
1022
1023#[wasm_bindgen]
1024pub fn sanitize_download_filename_js(value: String) -> String {
1025 sanitize_download_filename(&value)
1026}
1027
1028#[wasm_bindgen]
1029pub fn normalize_boolean_map_js(input: JsValue) -> Result<JsValue, JsValue> {
1030 let input: NormalizeBooleanMapInput = from_js(input)?;
1031 to_js(&normalize_boolean_map(&input.value))
1032}
1033
1034#[wasm_bindgen]
1035pub fn is_safe_state_key_js(value: String) -> bool {
1036 is_safe_state_key(&value)
1037}
1038
1039#[wasm_bindgen]
1042pub fn find_grid_row_by_id_js(input: JsValue) -> Result<JsValue, JsValue> {
1043 let input: FindGridRowByIdInput = from_js(input)?;
1044 to_js(&find_grid_row_by_id(&input.rows, &input.row_id))
1045}
1046
1047#[wasm_bindgen]
1048pub fn build_grid_sort_state_js(input: JsValue) -> Result<JsValue, JsValue> {
1049 let input: BuildGridSortStateInput = from_js(input)?;
1050 to_js(&build_grid_sort_state(input.column_name, input.direction))
1051}
1052
1053#[wasm_bindgen]
1054pub fn resolve_grid_row_id_js(input: JsValue) -> Result<String, JsValue> {
1055 let input: ResolveGridRowIdInput = from_js(input)?;
1056 Ok(resolve_grid_row_id(&input.options, &input.row))
1057}
1058
1059#[wasm_bindgen]
1062pub fn maybe_request_infinite_scroll_data_js(input: JsValue) -> Result<JsValue, JsValue> {
1063 let input: MaybeRequestInfiniteScrollDataContext = from_js(input)?;
1064 to_js(&maybe_request_infinite_scroll_data(&input))
1065}
1066
1067#[wasm_bindgen]
1068pub fn complete_infinite_scroll_data_load_js(input: JsValue) -> Result<JsValue, JsValue> {
1069 let input: InfiniteScrollLoadInput = from_js(input)?;
1070 to_js(&complete_infinite_scroll_data_load(
1071 &input.state,
1072 input.scroll_up,
1073 input.scroll_down,
1074 ))
1075}
1076
1077#[wasm_bindgen]
1078pub fn reset_infinite_scroll_state_js(input: JsValue) -> Result<JsValue, JsValue> {
1079 let input: InfiniteScrollDirectionsInput = from_js(input)?;
1080 to_js(&reset_infinite_scroll_state(
1081 input.scroll_up,
1082 input.scroll_down,
1083 ))
1084}
1085
1086#[wasm_bindgen]
1087pub fn save_infinite_scroll_percentage_js(input: JsValue) -> Result<JsValue, JsValue> {
1088 let input: InfiniteScrollVisibleRowsInput = from_js(input)?;
1089 to_js(&save_infinite_scroll_percentage(
1090 &input.state,
1091 input.visible_rows,
1092 ))
1093}
1094
1095#[wasm_bindgen]
1096pub fn set_infinite_scroll_directions_state_js(input: JsValue) -> Result<JsValue, JsValue> {
1097 let input: InfiniteScrollDirectionsInput = from_js(input)?;
1098 to_js(&set_infinite_scroll_directions_state(
1099 &input.state,
1100 input.scroll_up,
1101 input.scroll_down,
1102 ))
1103}
1104
1105#[wasm_bindgen]
1108pub fn format_grid_cell_display_value_js(input: JsValue) -> Result<String, JsValue> {
1109 let input: FormatGridCellDisplayValueInput = from_js(input)?;
1110 Ok(format_grid_cell_display_value(&input.row, &input.column))
1111}
1112
1113#[wasm_bindgen]
1114pub fn header_label_js(input: JsValue) -> Result<String, JsValue> {
1115 let input: HeaderLabelInput = from_js(input)?;
1116 Ok(header_label(&input.column))
1117}
1118
1119#[wasm_bindgen]
1120pub fn clear_grid_filter_reasons_js(row: JsValue) -> Result<JsValue, JsValue> {
1121 let mut row: GridRow = from_js(row)?;
1122 clear_grid_filter_reasons(&mut row);
1123 to_js(&row)
1124}
1125
1126#[wasm_bindgen]
1127pub fn matches_grid_row_filters_js(input: JsValue) -> Result<JsValue, JsValue> {
1128 let mut input: MatchesGridRowFiltersInput = from_js(input)?;
1129 let matches = matches_grid_row_filters(
1130 &mut input.row,
1131 &input.columns,
1132 &input.options,
1133 &input.active_filters,
1134 );
1135 to_js(&MatchesGridRowFiltersResult {
1136 row: input.row,
1137 matches,
1138 })
1139}
1140
1141#[wasm_bindgen]
1142pub fn sort_grid_rows_js(input: JsValue) -> Result<JsValue, JsValue> {
1143 let input: SortRowsInput = from_js(input)?;
1144 to_js(&sort_grid_rows(
1145 &input.rows,
1146 &input.columns,
1147 &input.options,
1148 &input.sort_state,
1149 ))
1150}
1151
1152#[wasm_bindgen]
1153pub fn build_grid_rows_js(input: JsValue) -> Result<JsValue, JsValue> {
1154 let input: BuildGridRowsInput = from_js(input)?;
1155 to_js(&build_grid_rows(
1156 &input.options,
1157 input.row_size,
1158 &input.hidden_row_reasons,
1159 &input.expanded_rows,
1160 ))
1161}
1162
1163#[wasm_bindgen]
1164pub fn is_tree_enabled_js(options: JsValue) -> Result<bool, JsValue> {
1165 let options: GridOptions = from_js(options)?;
1166 Ok(is_tree_enabled(&options))
1167}
1168
1169#[wasm_bindgen]
1170pub fn filter_and_flatten_grid_tree_rows_js(input: JsValue) -> Result<JsValue, JsValue> {
1171 let input: FilterFlattenTreeRowsInput = from_js(input)?;
1172 to_js(&filter_and_flatten_grid_tree_rows(
1173 &input.rows,
1174 &input.columns,
1175 &input.options,
1176 &input.active_filters,
1177 &input.expanded_tree_rows,
1178 &input.sort_state,
1179 ))
1180}
1181
1182#[wasm_bindgen]
1183pub fn get_path_value_js(input: JsValue) -> Result<JsValue, JsValue> {
1184 let input: PathValueInput = from_js(input)?;
1185 to_js(&get_path_value(&input.record, &input.path))
1186}
1187
1188#[wasm_bindgen]
1189pub fn get_cell_value_js(input: JsValue) -> Result<JsValue, JsValue> {
1190 let input: CellValueInput = from_js(input)?;
1191 to_js(&get_cell_value(&input.row, &input.column))
1192}
1193
1194#[wasm_bindgen]
1195pub fn stringify_cell_value_js(input: JsValue) -> Result<String, JsValue> {
1196 let input: StringifyCellValueInput = from_js(input)?;
1197 Ok(stringify_cell_value(&input.value))
1198}
1199
1200#[wasm_bindgen]
1201pub fn titleize_js(input: JsValue) -> Result<String, JsValue> {
1202 let input: TitleizeInput = from_js(input)?;
1203 Ok(titleize(&input.value))
1204}
1205
1206#[wasm_bindgen]
1207pub fn build_grid_display_items_js(input: JsValue) -> Result<JsValue, JsValue> {
1208 let input: BuildGridDisplayItemsInput = from_js(input)?;
1209 to_js(&build_grid_display_items(
1210 &input.rows,
1211 &input.columns,
1212 &input.options,
1213 &input.group_by,
1214 &input.collapsed_groups,
1215 ))
1216}
1217
1218#[wasm_bindgen]
1221pub fn calculate_virtual_window_js(request: JsValue) -> Result<JsValue, JsValue> {
1222 let request: VirtualWindowRequest = from_js(request)?;
1223 let result = calculate_virtual_window(&request);
1224 to_js(&result)
1225}