when in main branch It could look like this
import panel as pn
import param
from panel.reactive import ReactiveHTML
pn.extension()
class CustomInputTodoList(ReactiveHTML):
value = param.String()
enter_event = param.Event()
_template = """
<div class="bk bk-input-group">
<input class="bk bk-input" id="input" value="${value}" style="margin: 5px;" onkeydown="${_input_keydown}"></input>
</div>
"""
_dom_events = {"input": ["input"]}
def __init__(self, todolist, **params):
self._todolist = todolist
super().__init__(**params)
def _input_keydown(self, event):
if event.data['key'] == "Enter":
self._todolist.todo = self.value
self.value = ""
class TodoList(param.Parameterized):
""" Class to manage state of a List of items """
@param.depends("todo", watch=True)
def _record_todo(self):
# Record new item if its unique and non-empty
value = self.todo.strip()
if len(value) > 0 and value not in [i.todo for i in self.todo_list]:
new_item = TodoListItem(parent=self, todo=value, name="")
new_item.param.watch(self._delete_item, ['done'])
self.todo_list.append(new_item)
self.param.trigger('todo_list')
def _delete_item(self, *events):
for event in events:
if event.name == 'done':
self.todo_list.remove(event.obj)
self.param.trigger('todo_list')
todo_list = param.List([])
todo = param.String()
class TodoListItem(param.Parameterized):
""" Class to manage a a single list element """
done = param.Event()
todo = ""
todo_list = TodoList()
input_todo_list = CustomInputTodoList(todo_list, width=300)
@pn.depends(todo_list.param.todo_list)
def view_list(todo_list):
todo_text = lambda x : pn.pane.Markdown("###" + x, width=200)
delete_button = lambda x : pn.Param(
x, widgets={'done': {'widget_type' : pn.widgets.Button,
'button_type': 'danger', 'name':'x', 'width':15}})
return pn.Column(*[pn.Row(todo_text(todo.todo), delete_button(todo.param.done))
for todo in todo_list])
pn.Column(
pn.pane.Markdown('## My To-Do List'),
pn.Row(input_todo_list, width=300),
view_list,
).servable()