def Input( callback: Callable[[str], None], type: str, value: str = "", attributes: Optional[Dict[str, Any]] = None, cast: Optional[Callable[[str], Any]] = None, ignore_empty: bool = True, ) -> VdomDict: """Utility for making an ``<input/>`` with a callback""" attrs = attributes or {} value, set_value = idom.hooks.use_state(value) events = idom.Events() @events.on("change") def on_change(event: Dict[str, Any]) -> None: value = event["value"] set_value(value) if not value and ignore_empty: return callback(value if cast is None else cast(value)) return html.input({ "type": type, "value": value, **attrs }, event_handlers=events)
async def DivInDiv(self): inner_events = idom.Events() inner_events.on("Click", stop_propagation=True) async def outer_click_is_not_triggered(): assert False inner = idom.html.div( { "style": { "height": "30px", "width": "30px", "backgroundColor": "blue" }, "id": "inner", }, event_handlers=inner_events, ) outer = idom.html.div( { "style": { "height": "35px", "width": "35px", "backgroundColor": "red" }, "onClick": outer_click_is_not_triggered, "id": "outer", }, [inner], ) return outer
def GameLoop(grid_size, block_scale, set_game_state): # we `use_ref` here to capture the latest direction press without any delay direction = idom.hooks.use_ref(Direction.ArrowRight.value) snake, set_snake = idom.hooks.use_state([(grid_size // 2 - 1, grid_size // 2 - 1)]) food, set_food = use_snake_food(grid_size, snake) grid = create_grid(grid_size, block_scale) grid_events = grid["eventHandlers"] = idom.Events() @grid_events.on("KeyDown", prevent_default=True) async def on_direction_change(event): if hasattr(Direction, event["key"]): maybe_new_direction = Direction[event["key"]].value direction_vector_sum = tuple( map(sum, zip(direction.current, maybe_new_direction))) if direction_vector_sum != (0, 0): direction.current = maybe_new_direction assign_grid_block_color(grid, food, "blue") for location in snake: assign_grid_block_color(grid, location, "white") new_game_state = None if snake[-1] in snake[:-1]: assign_grid_block_color(grid, snake[-1], "red") new_game_state = GameState.lost elif len(snake) == grid_size**2: assign_grid_block_color(grid, snake[-1], "yellow") new_game_state = GameState.won interval = use_interval(0.5) @idom.hooks.use_effect async def animate(): if new_game_state is not None: await asyncio.sleep(1) set_game_state(new_game_state) return await interval new_snake_head = ( # grid wraps due to mod op here (snake[-1][0] + direction.current[0]) % grid_size, (snake[-1][1] + direction.current[1]) % grid_size, ) if snake[-1] == food: set_food() new_snake = snake + [new_snake_head] else: new_snake = snake[1:] + [new_snake_head] set_snake(new_snake) return grid
def test_simple_events_object(): events = idom.Events() @events.on("Click") async def click_handler(): pass @events.on("keyPress") async def key_press_handler(): pass assert isinstance(events["onClick"], EventHandler) assert isinstance(events["onKeyPress"], EventHandler)
def test_simple_events(): events = idom.Events() @events.on("Click") def click_handler(): pass @events.on("keyPress") def key_press_handler(): pass assert events == {"onClick": click_handler, "onKeyPress": key_press_handler} assert isinstance(events["onClick"], EventHandler) assert isinstance(events["onKeyPress"], EventHandler)
def Grid(grid_size, block_size): return idom.html.div( [ idom.html.div( [Block("white", block_size) for i in range(grid_size)], style={"height": block_size}, ) for i in range(grid_size) ], style={ "height": f"{block_size * grid_size}px", "width": f"{block_size * grid_size}px", }, eventHandlers=idom.Events(), tabIndex=-1, )
async def test_register_multiple_handlers_to_same_event(): events = idom.Events() calls = [] @events.on("change") async def handler_1(): calls.append(1) @events.on("change") async def handler_2(): calls.append(2) await events["onChange"]([]) assert calls == [1, 2]
def Grid(grid_size, block_size): return idom.html.div( { "style": { "height": f"{block_size * grid_size}px", "width": f"{block_size * grid_size}px", }, "tabIndex": -1, }, [ idom.html.div( {"style": {"height": block_size}}, [Block("white", block_size) for i in range(grid_size)], ) for i in range(grid_size) ], event_handlers=idom.Events(), )
import pytest import idom from idom.core.vdom import make_vdom_constructor fake_events = idom.Events() @fake_events.on("Click") async def handler(event): pass @pytest.mark.parametrize( "actual, expected", [ ( idom.vdom("div", [idom.vdom("div")]), { "tagName": "div", "children": [{ "tagName": "div" }] }, ), ( idom.vdom("div", {"style": { "backgroundColor": "red" }}), { "tagName": "div",
( # lists and tuples passed to children are flattened idom.nodes.div([idom.nodes.div(), 1], (idom.nodes.div(), 2)), { "tagName": "div", "children": [{"tagName": "div"}, 1, {"tagName": "div"}, 2], }, ), ( # keywords become attributes idom.nodes.div(style={"backgroundColor": "blue"}), {"tagName": "div", "attributes": {"style": {"backgroundColor": "blue"}}}, ), ( # eventHandlers is popped from attributes and made a top level field idom.nodes.div(eventHandlers=idom.Events()), {"tagName": "div", "eventHandlers": idom.Events()}, ), ], ) def test_simple_node_construction(actual, expected): assert actual == expected def test_node_constructor_factory(): elmt = node_constructor("some-tag") assert elmt(elmt(), data=1) == { "tagName": "some-tag", "children": [{"tagName": "some-tag"}], "attributes": {"data": 1},