{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import idom\n",
    "\n",
    "import panel as pn\n",
    "\n",
    "pn.extension()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**WARNING**: Currently Panel only support idom version 0.24. We are working on supporting later version as part of the [idom-bokeh project](https://github.com/idom-team/idom-bokeh/).\n",
    "\n",
    "The ``IDOM`` pane renders any [IDOM component](http://idom-docs.herokuapp.com/) both in the notebook and in a deployed server. IDOM defines an API for defining and controlling interactive HTML components directly from Python. Note that in the notebook the IDOM support for loading external modules relies on Panel's Jupyter serverextension. To check if this is enabled you can run:\n",
    "\n",
    "    jupyter serverextension list\n",
    "    \n",
    "You should see:\n",
    "\n",
    "    panel.io.jupyter_server_extension  enabled\n",
    "    - Validating...\n",
    "      panel.io.jupyter_server_extension  OK\n",
    "\n",
    "If you don't see this but have installed panel you can manually enable the server extension with:\n",
    "\n",
    "    jupyter serverextension enable --sys-prefix panel.io.jupyter_server_extension\n",
    "    \n",
    "which will install it where your Python is installed or to place it in the Jupyter config in your home directory:\n",
    "\n",
    "    jupyter serverextension enable --py panel\n",
    "\n",
    "#### Parameters:\n",
    "\n",
    "For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n",
    "\n",
    "* **``object``** (object): The IDOM component being displayed\n",
    "\n",
    "##### Display\n",
    "\n",
    "* **``default_layout``** (pn.layout.Panel, default=Row): Layout to wrap the plot and widgets in\n",
    "\n",
    "___"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `panel` function will automatically convert any ``idom.component`` into a displayable panel, while keeping all of its interactive features:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@idom.component\n",
    "def ClickCount():\n",
    "    count, set_count = idom.hooks.use_state(0)\n",
    "\n",
    "    return idom.html.button(\n",
    "        {\"onClick\": lambda event: set_count(count + 1)},\n",
    "        [f\"Click count: {count}\"],\n",
    "    )\n",
    "\n",
    "pn.pane.IDOM(ClickCount, width=300)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This makes it possible to generate even complex interactive components directly from Python, e.g. here we will create a ToDo list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@idom.component\n",
    "def Todo():\n",
    "    items, set_items = idom.hooks.use_state([])\n",
    "\n",
    "    async def add_new_task(event):\n",
    "        if event[\"key\"] == \"Enter\":\n",
    "            set_items(items + [event[\"value\"]])\n",
    "\n",
    "    tasks = []\n",
    "\n",
    "    for index, text in enumerate(items):\n",
    "\n",
    "        async def remove_task(event, index=index):\n",
    "            set_items(items[:index] + items[index + 1 :])\n",
    "\n",
    "        task_text = idom.html.td(idom.html.p(text))\n",
    "        delete_button = idom.html.td({\"onClick\": remove_task}, idom.html.button([\"x\"]))\n",
    "        tasks.append(idom.html.tr(task_text, delete_button))\n",
    "\n",
    "    task_input = idom.html.input({\"onKeyDown\": add_new_task})\n",
    "    task_table = idom.html.table(tasks)\n",
    "\n",
    "    return idom.html.div(task_input, task_table)\n",
    "\n",
    "pn.pane.IDOM(Todo)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you have a live server backing your session, whether that is a notebook server or a Bokeh/Panel server deployment you can also use external Javascript components which will be compiled before first use. See the [idom documentation](https://idom-docs.herokuapp.com/docs/javascript-components.html) for more details on using external components. Note that to ensure that the JS modules are installed in the correct place you should use `pn.pane.IDOM.install` rather than simply using `idom.install`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "victory = pn.pane.IDOM.install(\"victory\", fallback=\"loading...\")\n",
    "\n",
    "victory_com = idom.component(\n",
    "    lambda: victory.VictoryBar({\"style\": {\"parent\": {\"width\": \"500px\"}}}),\n",
    ")\n",
    "\n",
    "pn.pane.IDOM(victory_com)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In order to work with Panel components seamlessly the `IDOM` pane also provides a `use_param` method which allows us to use the current parameter value much like we would when using `pn.depends`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "aw = pn.widgets.IntSlider(name='a', start=0, end=20, value=1)\n",
    "bw = pn.widgets.IntSlider(name='b', start=0, end=20, value=1)\n",
    "\n",
    "@idom.component\n",
    "def view():\n",
    "    a = pn.pane.IDOM.use_param(aw)\n",
    "    b = pn.pane.IDOM.use_param(bw.param.value) # equivalent to passing in the widget\n",
    "    return idom.html.div({}, f'{a}+{b}={a+b}')\n",
    "\n",
    "pn.Row(aw, bw, view)"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
