diff --git a/README.md b/README.md
index 4fde58a..3e73c65 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,40 @@
-Build on top of ipyreact
+ipywidget wrapper for [Ant Design components](https://ant.design/) using [ipyreact](https://github.com/widgetti/ipyreact/).
+
+# Demo
+
+
+
+# Components
+
+The following components are wrapped (more will be coming):
+
+- General
+ - Button
+- Layout
+ - Flex
+ - Grid (Col / Row)
+- Navigation
+ - Dropdown
+- Data entry
+ - DatePicker
+ - ColorPicker
+ - Select
+ - Switch
+- Feedback
+ - Modal
+
+# Installation
+
+```
+pip install ipyantd
+```
+
+# Dev install
+
+```
+npm ci
+npm run build
+pip install -e .
+```
diff --git a/examples/demo.ipynb b/examples/demo.ipynb
new file mode 100644
index 0000000..0db4899
--- /dev/null
+++ b/examples/demo.ipynb
@@ -0,0 +1,232 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e88d1c8e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import ipyantd.widgets as antd\n",
+ "import ipyantd.icons.widgets as icons\n",
+ "import ipyreact"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a713bb10",
+ "metadata": {},
+ "source": [
+ "# Widget interface\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e84fa867",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import ipywidgets\n",
+ "from IPython.display import clear_output\n",
+ "\n",
+ "options = [\n",
+ " dict(label=\"Apple\", value=\"apple\"),\n",
+ " dict(label=\"Pear\", value=\"pear\"),\n",
+ " dict(label=\"Cherry\", value=\"cherry\"),\n",
+ "]\n",
+ "\n",
+ "menu_items = [\n",
+ " dict(key=\"1\", label=ipyreact.Widget(_type=\"div\", children=[\"Click me 1\"], events={\"onClick\": print})),\n",
+ " dict(key=\"2\", label=ipyreact.Widget(_type=\"div\", children=[\"Click me 2\"], events={\"onClick\": print})),\n",
+ "]\n",
+ "text = \"\"\"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n",
+ "Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. \n",
+ "Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. \n",
+ "Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. \n",
+ "Duis semper.\n",
+ "Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue.\n",
+ "\"\"\"\n",
+ "\n",
+ "\n",
+ "def dialog_open(event_data):\n",
+ " with output:\n",
+ " clear_output(wait=True)\n",
+ " print(\"Modal opened\")\n",
+ " dialog.value = True\n",
+ "\n",
+ "\n",
+ "def dialog_close(event_data):\n",
+ " with output:\n",
+ " clear_output(wait=True)\n",
+ " print(\"Modal closed\")\n",
+ " dialog.value = False\n",
+ " \n",
+ "def show_value(change):\n",
+ " new = change[\"new\"]\n",
+ " with output:\n",
+ " clear_output(wait=True)\n",
+ " print(\"value = \", new)\n",
+ "\n",
+ "def report_click(event_data=None):\n",
+ " with output:\n",
+ " clear_output(wait=True)\n",
+ " print(\"Clicked\")\n",
+ "\n",
+ "demo = ipyreact.Widget(_type=\"div\", children=[\n",
+ " antd.Row(props=dict(gutter=[48,48], style={\"padding\": \"100px\"}), children=[\n",
+ " antd.Col(props=dict(span=8, style={\"boxSizing\": \"border-box\"}), children=[\n",
+ " ipyreact.Widget(_type=\"div\", children=[\n",
+ " antd.Button(children=[\"Button\"], props=dict(type=\"primary\"), events={\"onClick\": report_click}),\n",
+ " antd.Button(children=[\"Button\"]),\n",
+ " ]),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " antd.Button(children=[\"Button\"], props=dict(type=\"primary\", shape=\"round\")),\n",
+ " antd.Button(props=dict(type=\"primary\", shape=\"circle\", icon=icons.Icon(\"SearchOutlined\"))),\n",
+ " antd.Button(props=dict(shape=\"circle\", icon=icons.Icon(\"SearchOutlined\"))),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " antd.Button(children=[\"Button\"], props=dict(type=\"text\")),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " antd.Button(children=[\"Button\"], props=dict(type=\"primary\", size=\"small\")),\n",
+ " antd.Button(children=[\"Button\"], props=dict(size=\"small\")),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " antd.Button(children=[\"Button\"], props=dict(type=\"primary\", shape=\"round\", size=\"small\")),\n",
+ " antd.Button(props=dict(type=\"primary\", shape=\"circle\", icon=icons.Icon(\"SearchOutlined\"), size=\"small\")),\n",
+ " antd.Button(props=dict(shape=\"circle\", icon=icons.Icon(\"SearchOutlined\"), size=\"small\")),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " antd.Button(children=[\"Button\"], props=dict(type=\"text\", size=\"small\")),\n",
+ " ]),\n",
+ " \n",
+ " # sliders\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " antd.Slider(value=0, props=dict(min=0, max=100)),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " slider_range := antd.Slider(value=[20, 70], props=dict(min=0, max=100, range=True)),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " slider := antd.Slider(value=30, props=dict(min=0, max=100, tooltip=dict(open=True))),\n",
+ " ]),\n",
+ "\n",
+ " # select\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " select := antd.Select(value=\"pear\", props=dict(options=options, style=dict(width=\"120px\"))),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " multi_select := antd.Select(value=[\"cherry\"], props=dict(options=options, style=dict(width=\"220px\"), mode=\"multiple\"))\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " # only supported in 5.31+\n",
+ " # antd.Select(value=\"pear\", props=dict(options=options, variant=\"filled\", style=dict(width=\"120px\"))),\n",
+ " ]),\n",
+ " \n",
+ " # misc\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " switch := antd.Switch(value=True),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " dropdown := antd.Dropdown(props=dict(menu=dict(items=menu_items), trigger=[\"click\"]), children=\n",
+ " [ipyreact.Widget(_type=\"span\", children=[\"Menu\"])]\n",
+ " ),\n",
+ " ]),\n",
+ " antd.Col(props=dict(span=8), children=[\n",
+ " dialog := antd.Modal(events={\"onOk\": dialog_close, \"onCancel\": dialog_close}, children=[\n",
+ " ipyreact.Widget(_type=\"div\", children=[text])\n",
+ " ]),\n",
+ " antd.Button(children=[\"Dialog\"], props=dict(type=\"primary\"), events={\"onClick\": dialog_open}),\n",
+ " ]),\n",
+ "\n",
+ " \n",
+ " ]),\n",
+ " output := ipywidgets.Output()\n",
+ "])\n",
+ "select.observe(show_value, \"value\")\n",
+ "multi_select.observe(show_value, \"value\")\n",
+ "slider.observe(show_value, \"value\")\n",
+ "slider_range.observe(show_value, \"value\")\n",
+ "switch.observe(show_value, \"value\")\n",
+ "with output:\n",
+ " print(\" \")\n",
+ "demo"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bcfd2971",
+ "metadata": {},
+ "source": [
+ "# Solara component interface\n",
+ "\n",
+ "Coming soon"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8b2bc0b3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import ipyantd.icons.widgets as icons"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d4ca25cc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# import ipyantd.components as antd\n",
+ "# # import solara\n",
+ "# import reacton\n",
+ "# import ipyreact"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5fdc936b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# @reacton.component\n",
+ "# def Page():\n",
+ "# with antd.Flex(props=dict(style={\"padding\": \"24px\"}, gap=\"small\")) as m:\n",
+ "# antd.Button(children=[\"Button\"], props=dict(type=\"primary\"))\n",
+ "# antd.Button(children=[\"Button\"])\n",
+ "# antd.Button(children=[\"Button\"], props=dict(type=\"primary\", shape=\"round\"))\n",
+ "# antd.Button(children=[\"Button\"], props=dict(type=\"primary\", shape=\"round\"))\n",
+ "# } />\n",
+ "# return m\n",
+ "# Page()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.16"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/ipyantd/assets/antd-jupyter.tsx b/ipyantd/assets/antd-jupyter.tsx
index 9de2581..25f92e8 100644
--- a/ipyantd/assets/antd-jupyter.tsx
+++ b/ipyantd/assets/antd-jupyter.tsx
@@ -1,6 +1,54 @@
import * as React from "react";
-import { Slider } from "antd";
+import * as antd from "antd";
export function SliderStatefull({ value, setValue, ...rest }) {
- return setValue(v)} {...rest} />;
+ return setValue(v)} {...rest} />;
+}
+
+export function SelectStatefull({ value, setValue, ...rest }) {
+ return setValue(v)} {...rest} />;
+}
+
+export function SwitchStatefull({ value, setValue, ...rest }) {
+ return setValue(v)} {...rest} />;
+}
+
+export function DropdownStatefull({ value, setValue, ...rest }) {
+ const onOpenChange = (open, info) => {
+ setValue(open);
+ if (rest.onOpenChange) {
+ rest.onOpenChange({ open, info });
+ }
+ };
+ return ;
+}
+
+export function ModalStatefull({ value, setValue, ...rest }) {
+ const onOpenChange = (open) => {
+ setValue(open);
+ if (rest.onOpenChange) {
+ rest.afterOpenChange(open);
+ }
+ };
+ const handleOk = () => {
+ // setValue(false);
+ if (rest.onOk) {
+ rest.onOk();
+ }
+ };
+ const handleCancel = () => {
+ // setValue(false);
+ if (rest.onCancel) {
+ rest.onCancel();
+ }
+ };
+ return (
+
+ );
}
diff --git a/ipyantd/widgets.py b/ipyantd/widgets.py
index 1488ef0..7347d76 100644
--- a/ipyantd/widgets.py
+++ b/ipyantd/widgets.py
@@ -18,6 +18,38 @@ class Flex(ipyreact.Widget):
_type = traitlets.Unicode("Flex").tag(sync=True)
+class Row(ipyreact.Widget):
+ _module = traitlets.Unicode("antd").tag(sync=True)
+ _type = traitlets.Unicode("Row").tag(sync=True)
+
+
+class Col(ipyreact.Widget):
+ _module = traitlets.Unicode("antd").tag(sync=True)
+ _type = traitlets.Unicode("Col").tag(sync=True)
+
+
+class Select(ipyreact.ValueWidget):
+ _module = traitlets.Unicode("antd-jupyter").tag(sync=True)
+ _type = traitlets.Unicode("SelectStatefull").tag(sync=True)
+
+
+class Switch(ipyreact.ValueWidget):
+ _module = traitlets.Unicode("antd-jupyter").tag(sync=True)
+ _type = traitlets.Unicode("SwitchStatefull").tag(sync=True)
+
+
+class Dropdown(ipyreact.ValueWidget):
+ value = traitlets.Bool(False).tag(sync=True)
+ _module = traitlets.Unicode("antd-jupyter").tag(sync=True)
+ _type = traitlets.Unicode("DropdownStatefull").tag(sync=True)
+
+
+class Modal(ipyreact.ValueWidget):
+ value = traitlets.Bool(False).tag(sync=True)
+ _module = traitlets.Unicode("antd-jupyter").tag(sync=True)
+ _type = traitlets.Unicode("ModalStatefull").tag(sync=True)
+
+
class DatePicker(ipyreact.ValueWidget):
# _module = traitlets.Unicode("antd").tag(sync=True)
# _type = traitlets.Unicode("DatePicker").tag(sync=True)