|
70 | 70 | "outputs": [], |
71 | 71 | "source": [ |
72 | 72 | "from idom.server.sanic import PerClientState\n", |
73 | | - "from example_utils import example_uri_root, html_link, pretty_dict_string\n", |
| 73 | + "from example_utils import (\n", |
| 74 | + " example_uri_root,\n", |
| 75 | + " HtmlLink,\n", |
| 76 | + " pretty_dict_string,\n", |
| 77 | + " is_on_jupyterhub,\n", |
| 78 | + ")\n", |
74 | 79 | "\n", |
75 | | - "websocket_url = example_uri_root(\"ws\", 8765) + \"/stream\"\n", |
76 | | - "webpage_url = html_link(example_uri_root(\"http\", 8765) + \"/client/index.html\")\n", |
| 80 | + "webpage_url = HtmlLink(example_uri_root(\"http\", 8765))\n", |
77 | 81 | "\n", |
78 | 82 | "mount, element = idom.hotswap()\n", |
79 | | - "PerClientState(element).daemon(\"127.0.0.1\", 8765, access_log=False)\n", |
| 83 | + "PerClientState(element).configure({\"cors\": not is_on_jupyterhub()}).daemon(\n", |
| 84 | + " \"127.0.0.1\", 8765, access_log=False\n", |
| 85 | + ")\n", |
| 86 | + "\n", |
80 | 87 | "\n", |
81 | 88 | "def display(*args, **kwargs):\n", |
82 | 89 | " element, *args = args\n", |
83 | 90 | " mount(element, *args, **kwargs)\n", |
84 | | - " return idom.display(\"jupyter\", websocket_url)" |
| 91 | + " return idom.display(\"jupyter\", str(webpage_url), secure=is_on_jupyterhub())" |
85 | 92 | ] |
86 | 93 | }, |
87 | 94 | { |
|
653 | 660 | "print()\n", |
654 | 661 | "print(\"Slow internet may cause inconsistent frame pacing 😅\")\n", |
655 | 662 | "\n", |
656 | | - "display(GameView, 8, 50)" |
| 663 | + "display(GameView, 7, 50)" |
657 | 664 | ] |
658 | 665 | }, |
659 | 666 | { |
|
662 | 669 | "source": [ |
663 | 670 | "# Importing Javascript - Leveraging The Ecosystem\n", |
664 | 671 | "\n", |
665 | | - "With IDOM, you're able to leverage existing Javascript libraries by specifying packages that you'd like to import and the css needed to style the components. In the following example we display a [date picker](https://ant.design/components/date-picker/) from the [Ant Design System](https://ant.design/) and register a callback to it. The cool part here is that the `onChange` callback conforms to the [specification](https://ant.design/components/date-picker/#DatePicker) defined by Ant and handles two arguments instead of one containing a DOM event dictionary.\n", |
666 | | - "\n", |
667 | | - "Since we've seen what's possible with IDOM all we'll do is print out the event information." |
| 672 | + "With IDOM, you're able to leverage existing Javascript libraries by specifying React-based packages that you'd like to install and import. It's worth noting that not every package will work with IDOM since the packages source must be compilable to ES6 using [Snowpack](https://www.snowpack.dev/), many should just work out of the box though. In the following example we display a [Bar Chart](https://formidable.com/open-source/victory/docs/victory-bar/) from the [Victory Chart Library](https://formidable.com/open-source/victory/) using its default data." |
668 | 673 | ] |
669 | 674 | }, |
670 | 675 | { |
|
673 | 678 | "metadata": {}, |
674 | 679 | "outputs": [], |
675 | 680 | "source": [ |
676 | | - "antd = idom.Import(\"https://dev.jspm.io/antd\", fallback=\"Loading...\")\n", |
| 681 | + "print(\"It may take a moment to download and install Victory... 🕒\")\n", |
677 | 682 | "\n", |
| 683 | + "victory = idom.Import(\"victory\", fallback=\"loading...\", install=True)\n", |
678 | 684 | "\n", |
679 | | - "@idom.element\n", |
680 | | - "async def AntDatePicker(self):\n", |
| 685 | + "display(victory.VictoryBar, {\"style\": {\"parent\": {\"width\": \"500px\"}}})" |
| 686 | + ] |
| 687 | + }, |
| 688 | + { |
| 689 | + "cell_type": "markdown", |
| 690 | + "metadata": {}, |
| 691 | + "source": [ |
| 692 | + "## Making Your Own React Components\n", |
681 | 693 | "\n", |
682 | | - " async def changed(moment, datestring):\n", |
683 | | - " print(\"CLIENT DATETIME:\", moment)\n", |
684 | | - " print(\"PICKED DATETIME:\", datestring)\n", |
| 694 | + "While using existing Javascript packages out of the box is great, sometimes you need to create your own native Javascript modules. This might be because a package you installed doesn't play well with IDOM, or because you need to create your own custom logic that can only be achieved using client-side Javascript. In the case of Victory, it's actually both - unfortunately Victory's higher level components can't be constructed purely using VDOM in Python in addition to the fact that many of its more complex features require writing custom Javascript hooks. \n", |
685 | 695 | "\n", |
686 | | - " return idom.html.div(\n", |
687 | | - " [\n", |
688 | | - " idom.html.link({\n", |
689 | | - " \"rel\": \"stylesheet\", \"type\": \"text/css\", \"href\": \"https://dev.jspm.io/antd/dist/antd.css\"\n", |
690 | | - " }),\n", |
691 | | - " module.DatePicker({\"onChange\": changed}),\n", |
692 | | - " ]\n", |
693 | | - " )\n", |
| 696 | + "Thankfully IDOM allows you to write your own Javascript modules the import and use packages you've installed. In the example below we created a module `chart.js` that exports a `VictoryBar` chart with some extra styling and an `onClick` event adapter that allows Python and Victory to interoperate." |
| 697 | + ] |
| 698 | + }, |
| 699 | + { |
| 700 | + "cell_type": "code", |
| 701 | + "execution_count": null, |
| 702 | + "metadata": {}, |
| 703 | + "outputs": [], |
| 704 | + "source": [ |
| 705 | + "print(\"Click the bars to see event data printed in Python 👇\")\n", |
694 | 706 | "\n", |
| 707 | + "chart = idom.widgets.import_module(\"chart\", \"chart.js\")\n", |
695 | 708 | "\n", |
696 | | - "print(\"Select a date to see the event print-out 📅\")\n", |
| 709 | + "async def handle_event(event):\n", |
| 710 | + " print(event)\n", |
697 | 711 | "\n", |
698 | | - "display(AntDatePicker)" |
| 712 | + "display(\n", |
| 713 | + " chart.ClickableChart,\n", |
| 714 | + " {\"onClick\": handle_event, \"style\": {\"parent\": {\"width\": \"500px\"}}},\n", |
| 715 | + ")" |
699 | 716 | ] |
700 | 717 | }, |
701 | 718 | { |
702 | 719 | "cell_type": "markdown", |
703 | 720 | "metadata": {}, |
704 | 721 | "source": [ |
705 | | - "## More Ant Design\n", |
706 | | - "\n", |
707 | | - "Here's a bunch of other fun components that we can use from Ant Design." |
| 722 | + "Here's the source that was used to generate the chart above" |
708 | 723 | ] |
709 | 724 | }, |
710 | 725 | { |
|
713 | 728 | "metadata": {}, |
714 | 729 | "outputs": [], |
715 | 730 | "source": [ |
716 | | - "@idom.element\n", |
717 | | - "async def MoreAntDesign(self):\n", |
718 | | - " \n", |
719 | | - " async def changed(*data):\n", |
720 | | - " print(*data)\n", |
721 | | - "\n", |
722 | | - " return idom.html.div([\n", |
723 | | - " antd.Button({\"onClick\": changed}),\n", |
724 | | - " antd.Switch({\"onChange\": changed}),\n", |
725 | | - " antd.TimePicker({\"onChange\": changed}),\n", |
726 | | - " antd.Progress(\n", |
727 | | - " {\n", |
728 | | - " \"percent\": \"90\",\n", |
729 | | - " \"status\": \"active\",\n", |
730 | | - " \"strokeColor\": {\n", |
731 | | - " \"0%\": \"#108ee9\",\n", |
732 | | - " \"100%\": \"#87d068\",\n", |
733 | | - " },\n", |
734 | | - " }\n", |
735 | | - " )\n", |
736 | | - " ]\n", |
737 | | - " )\n", |
738 | | - "\n", |
739 | | - "\n", |
740 | | - "print(\"A bunch more examples 🎉\")\n", |
741 | | - "\n", |
742 | | - "display(MoreAntDesign)" |
| 731 | + "with open(\"chart.js\") as f:\n", |
| 732 | + " print(f.read())" |
743 | 733 | ] |
744 | 734 | }, |
745 | 735 | { |
|
781 | 771 | "source": [ |
782 | 772 | "from idom.server.sanic import SharedClientState\n", |
783 | 773 | "\n", |
784 | | - "shared_websocket_url = example_uri_root(\"ws\", 5678) + \"/stream\"\n", |
785 | | - "shared_webpage_url = html_link(example_uri_root(\"http\", 5678) + \"/client/index.html\")\n", |
| 774 | + "shared_webpage_url = HtmlLink(example_uri_root(\"http\", 5678))\n", |
786 | 775 | "\n", |
787 | | - "mount_shared, element = idom.hotswap(shared=True)\n", |
788 | | - "SharedClientState(element).daemon(\"127.0.0.1\", 5678, access_log=False)\n", |
| 776 | + "mount_shared, element = idom.hotswap()\n", |
| 777 | + "SharedClientState(element).configure({\"cors\": not is_on_jupyterhub()}).daemon(\n", |
| 778 | + " \"127.0.0.1\", 5678, access_log=False\n", |
| 779 | + ")\n", |
789 | 780 | "\n", |
790 | | - "def shared_display(element, *args, **kwargs):\n", |
| 781 | + "\n", |
| 782 | + "def shared_display(*args, **kwargs):\n", |
| 783 | + " element, *args = args\n", |
791 | 784 | " mount_shared(element, *args, **kwargs)\n", |
792 | | - " return idom.display(\"jupyter\", shared_websocket_url)" |
| 785 | + " return idom.display(\"jupyter\", str(shared_webpage_url), secure=is_on_jupyterhub())" |
793 | 786 | ] |
794 | 787 | }, |
795 | 788 | { |
|
0 commit comments