Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Picker - initial scroll position (#1942)
NOTE: This PR depends on deephaven/deephaven-plugins#424 in order for element type checks to work for `Item`, `Text`, `Section`, etc. - Refactored non-jsapi Picker to support JSX children with minimal wrapping instead of having to normalize items (#1890 should do the same for ListView, and we should be able to delete some of the normalization code) - Updated scroll position logic to be able to traverse JSX elements - Disable initial scrolling when children contain descriptions or sections **Testing** This illustrates different configurations and shows how initial scroll behavior differs for Pickers with plain items, descriptions, or sections: ```python import deephaven.ui as ui from math import floor import datetime # Ticking table with initial row count of 200 that adds a row every second initial_row_count=1000 items_table = time_table("PT1S", start_time=datetime.datetime.now() - datetime.timedelta(seconds=initial_row_count)).update([ "Id=new Integer(i)", "Display=new String(`Display `+i)", ]) @ui.component def pickers(): value, set_value = ui.use_state('2SSS') def handle_change(v): print(v) set_value(v) on_change = ui.use_callback(handle_change, []) # Picker with text options text = ui.picker( label="Text", children=[ 'Text 1', 'Text 2', 'Text 3' ] ) # Picker with boolean options boolean = ui.picker( label="Boolean", children=[ True, False ] ) # Picker with numeric options numeric = ui.picker( label="Numeric", children=[ 10, 20, 30 ] ) ################ Icons ####################################### # Icons icons = ui.picker( label = "Icons", children = [ item_with_icon('Add', 'vsAdd'), item_with_icon('Remove', 'vsRemove'), ] ) # Icons (default selection) icons_default_selection = ui.picker( label = "Icons (default selection)", default_selected_key="3GGG", children = list(map( lambda args : item(args[1]) if args[0] % 7 > 0 else item_with_icon(args[1], 'vsAccount'), enumerate(generate_item_texts(0, 500)))) ) # Icons (controlled) icons_controlled = ui.picker( label = "Icons (controlled)", selected_key=value, on_change=on_change, children = list(map( lambda args : item(args[1]) if args[0] % 7 > 0 else item_with_icon(args[1], 'vsAccount'), enumerate(generate_item_texts(0, 500)))) ) ################ Descriptions ####################################### # Descriptions (default selection) descriptions = ui.picker( label = "Descriptions", children = list(map(lambda txt : item(txt, True), generate_item_texts(0, 500))) ) # Descriptions (default selection) descriptions_default_selection = ui.picker( label = "Descriptions (default selection)", default_selected_key="3GGG", children = list(map(lambda txt : item(txt, True), generate_item_texts(0, 500))) ) # Descriptions (controlled) descriptions_controlled = ui.picker( label = "Descriptions (controlled)", selected_key=value, on_change=on_change, children = list(map(lambda txt : item(txt, True), generate_item_texts(0, 500))) ) ################ Sections ####################################### # Sections sections = ui.picker( label = "Sections (default selection)", children = [ section(x, i * 10, i * 10 + 9) for i, x in enumerate(generate_item_texts(0, 19)) ] ) # Sections (default selection) sections_default_selection = ui.picker( label = "Sections (default selection)", default_selected_key = "3GGG", children = [ section(x, i * 10, i * 10 + 9) for i, x in enumerate(generate_item_texts(0, 19)) ] ) # Sections (controlled) sections_controlled = ui.picker( label = "Sections (controlled)", selected_key=value, on_change=on_change, children = [ section(x, i * 10, i * 10 + 9) for i, x in enumerate(generate_item_texts(0, 19)) ] ) ################ Tables ####################################### table_value, set_table_value = ui.use_state('Display 824') # Uncontrolled table with default selection table = ui.picker( items_table, key_column="Display", label_column="Display", label="Table", ) # Uncontrolled table with default selection table_default_selection = ui.picker( items_table, key_column="Display", label_column="Display", label="Table (default selection)", default_selected_key="Display 86", ) # Controlled table table_controlled = ui.picker( items_table, key_column="Display", label_column="Display", label="Table (controlled)", on_selection_change=set_table_value, selected_key=table_value, ) return ui.flex( direction="column", UNSAFE_style={"overflow":"scroll"}, children = [ ui.heading("Basic", margin=0), ui.flex( direction='row', children=[ text, boolean, numeric, ] ), ui.heading("Icons", margin=0), ui.flex( direction='row', children=[ icons, icons_default_selection, icons_controlled, ] ), ui.heading("Descriptions", margin=0), ui.flex( direction='row', children=[ descriptions, descriptions_default_selection, descriptions_controlled, ] ), ui.heading("Sections", margin=0), ui.flex( direction='row', children=[ sections, sections_default_selection, sections_controlled, ] ), ui.heading("Table", margin=0), ui.flex( direction='row', children=[ table, table_default_selection, table_controlled, ] ) ], ) pick = pickers() ################ Helpers ####################################### # Generate a list of unique item text for a start / stop range def generate_item_texts(start, stop): characters = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ") size = len(characters) return [str(floor((i + start) / size)) + (characters[x % size] * 3) for i, x in enumerate(range(start, stop))] @ui.component def item(txt, include_description=False): return ui.item( ui.text(txt, key="label"), ui.text("Description " + txt, key="description", slot="description"), # key=txt, text_value=txt ) if include_description else ui.item(txt, text_value=txt) @ui.component def item_with_icon(txt, icon): return ui.item( text_value=txt, children=[ ui.icon(icon), txt, ] ) @ui.component def section(txt, start, end): return ui.section( title = "Section " + txt, children = list(map(lambda txt : item(txt), generate_item_texts(start, end))) ) ``` resolves #1935
- Loading branch information