22Widget Tools
33============
44"""
5+ from __future__ import annotations
56
6- from typing import Any , Callable , Dict , Set , Tuple , TypeVar
7+ from typing import Any , Callable , Dict , Optional , Set , Tuple , TypeVar
78
89from idom .core import hooks
910from idom .core .component import ComponentConstructor , component
@@ -97,30 +98,36 @@ def _use_callable(initial_func: _FuncVar) -> Tuple[_FuncVar, Callable[[_Func], N
9798 return state [0 ], lambda new : state [1 ](lambda old : new )
9899
99100
100- def multiview () -> Tuple [" MultiViewMount" , ComponentConstructor ]:
101+ def multiview () -> Tuple [MultiViewMount , ComponentConstructor ]:
101102 """Dynamically add components to a layout on the fly
102103
103104 Since you can't change the component functions used to create a layout
104105 in an imperative manner, you can use ``multiview`` to do this so
105106 long as you set things up ahead of time.
106107
107- Returns:
108- A function for adding views and the root of the dynamic view
109-
110108 Examples:
111109
112110 .. code-block::
113111
114112 import idom
115113
116- define, root = idom.widgets.multiview()
114+ mount, multiview = idom.widgets.multiview()
115+
116+ @idom.component
117+ def Hello():
118+ return idom.html.h1(["hello"])
117119
118- @component
119- def Hello(self, phrase):
120- return idom.html.h1(["hello " + phrase])
120+ # auto static view ID
121+ mount.add("hello", Hello)
122+ # use the view ID to create the associate component instance
123+ hello_component_instance = multiview("hello")
121124
122- add_hello = define(Hello)
123- hello_world_view_id = add_hello("world")
125+ @idom.component
126+ def World():
127+ return idom.html.h1(["world"])
128+
129+ generated_view_id = mount.add(None, World)
130+ world_component_instance = multiview(generated_view_id)
124131
125132 Displaying ``root`` with the parameter ``view_id=hello_world_view_id`` will show
126133 the message 'hello world'. Usually though this is achieved by connecting to the
@@ -141,28 +148,37 @@ def MultiView(view_id: str) -> Any:
141148
142149
143150class MultiViewMount :
151+ """Mount point for :func:`multiview`"""
144152
145153 __slots__ = "_next_auto_id" , "_views"
146154
147155 def __init__ (self , views : Dict [str , ComponentConstructor ]):
148156 self ._next_auto_id = 0
149157 self ._views = views
150158
151- def remove (self , view_id : str ) -> None :
152- del self ._views [view_id ]
153-
154- def __getitem__ (self , view_id : str ) -> Callable [[ComponentConstructor ], str ]:
155- def mount (constructor : ComponentConstructor ) -> str :
156- self ._views [view_id ] = constructor
157- return view_id
158-
159- return mount
160-
161- def __call__ (self , constructor : ComponentConstructor ) -> str :
162- self ._next_auto_id += 1
163- view_id = str (self ._next_auto_id )
159+ def add (self , view_id : Optional [str ], constructor : ComponentConstructor ) -> str :
160+ """Add a component constructor
161+
162+ Parameters:
163+ view_id:
164+ The view ID the constructor will be associated with. If ``None`` then
165+ a view ID will be automatically generated.
166+ constructor:
167+ The component constructor to be mounted. It must accept no arguments.
168+
169+ Returns:
170+ The view ID that was assocaited with the component - most useful for
171+ auto-generated view IDs
172+ """
173+ if view_id is None :
174+ self ._next_auto_id += 1
175+ view_id = str (self ._next_auto_id )
164176 self ._views [view_id ] = constructor
165177 return view_id
166178
179+ def remove (self , view_id : str ) -> None :
180+ """Remove a mounted component constructor given its view ID"""
181+ del self ._views [view_id ]
182+
167183 def __repr__ (self ) -> str :
168184 return f"{ type (self ).__name__ } ({ self ._views } )"
0 commit comments