Skip to content

Commit dece554

Browse files
committed
misc progress on your first component section
1 parent ef9b6e4 commit dece554

File tree

8 files changed

+120
-19
lines changed

8 files changed

+120
-19
lines changed

docs/source/creating-interfaces/index.rst

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Creating Interfaces
55
:hidden:
66

77
html-with-idom
8-
your-first-component
8+
your-first-components
99
parametrizing-components
1010
conditional-rendering
1111
dynamic-element-children
@@ -23,11 +23,11 @@ Creating Interfaces
2323
Learn how to construct HTML layouts with IDOM and the underlying data
2424
structure we use to represent them.
2525

26-
.. grid-item-card:: :octicon:`package` Your First Component
27-
:link: your-first-component
26+
.. grid-item-card:: :octicon:`package` Your First Components
27+
:link: your-first-components
2828
:link-type: doc
2929

30-
Discover what components are and why their one of IDOM's foundational
30+
Discover what components are and why they're one of IDOM's foundational
3131
concepts.
3232

3333
.. grid-item-card:: :octicon:`plug` Parametrizing Components
@@ -63,9 +63,9 @@ Section 1: HTML with IDOM
6363

6464
In a typical Python-base web application the resonsibility of defining the view along
6565
with its backing data and logic are distributed between a client and server
66-
respectively. With IDOM, both these tasks are centralized in a single place. This is
67-
done by allowing HTML interfaces to be constructed in Python. Let's consider the HTML
68-
sample below:
66+
respectively. With IDOM, both these tasks are centralized in a single place. The most
67+
foundational pilar of this capability is formed by allowing HTML interfaces to be
68+
constructed in Python. Let's consider the HTML sample below:
6969

7070
.. code-block:: html
7171

@@ -102,8 +102,34 @@ To recreate the same thing in IDOM you would write:
102102
use to represent them.
103103

104104

105-
Section 2: Your First Component
106-
-------------------------------
105+
Section 2: Your First Components
106+
--------------------------------
107+
108+
The next building block in our journey with IDOM are components. At their core,
109+
components are just a normal Python functions that return :ref:`HTML <HTML with IDOM>`.
110+
The one special thing about them that we need to be concerned with now, is that to
111+
create them they require the addition of the :func:`~idom.core.component.component`
112+
decorator. Take a quick look at this "hello world" example you make have seen earlier to
113+
check out what this looks like in practice:
114+
115+
.. example:: hello_world
116+
:activate-result:
117+
118+
.. note::
119+
120+
Not all functions that return HTML need to be decorated with the ``@component``
121+
decorator - when and where they are required will be discussed when we start
122+
:ref:`adding interactivity`.
123+
124+
.. card::
125+
:link: html-with-idom
126+
:link-type: doc
127+
128+
:octicon:`book` Read More
129+
^^^^^^^^^^^^^^^^^^^^^^^^^
130+
131+
Discover what components are and why they're one of IDOM's foundational concepts.
132+
107133

108134

109135
Section 3: Parametrizing Components

docs/source/creating-interfaces/your-first-component.rst

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
Your First Component
2+
====================
3+
4+
The next building block in our journey with IDOM are components. At their core,
5+
components are just a normal Python functions that return :ref:`HTML <HTML with IDOM>`.
6+
The one special thing about them that we need to be concerned with now, is that to
7+
create them they require the addition of the :func:`~idom.core.component.component`
8+
decorator. Take a quick look at this "hello world" example you make have seen earlier to
9+
check out what this looks like in practice:
10+
11+
.. example:: hello_world
12+
:activate-result:
13+
14+
.. note::
15+
16+
Not all functions that return HTML need to be decorated with the ``@component``
17+
decorator - when and where they are required will be discussed when we start
18+
:ref:`adding interactivity`.
19+
20+
In the code above we have a function ``App`` that is decorated with ``@component`` to
21+
turn it into a component. This function then gets passed to
22+
:func:`~idom.server.prefab.run` in order to :ref:`run a server <Running IDOM>` to
23+
display it. If we had not decorated our ``App`` function with the ``@component``
24+
decorator, the server would start, but as soon as we tried to view the page it would be
25+
blank. The servers logs would then indicate:
26+
27+
.. code-block:: text
28+
29+
TypeError: Expected a ComponentType, not dict.
30+
31+
To see why this is we can check out what happens when we call ``App`` with and without
32+
the ``@component`` decorator. In the first instance we get a dictionary representing our
33+
HTML:
34+
35+
.. testcode::
36+
37+
from idom import html
38+
39+
def App():
40+
return html.h1("Hello, world!")
41+
42+
print(App())
43+
44+
.. testoutput::
45+
46+
{'tagName': 'h1', 'children': ['Hello, world!']}
47+
48+
But, if we decorate it we instead find:
49+
50+
.. testcode::
51+
52+
from idom import component, html, ComponentType
53+
54+
@component
55+
def App():
56+
return html.h1("Hello, world!")
57+
58+
app = App()
59+
print(app)
60+
print(type(app))
61+
62+
.. testcode::
63+
:hide:
64+
65+
import re
66+
# update the output code block below and this regex pattern if this fails
67+
assert re.match("Component\(\d+\)", str(App()))
68+
69+
.. code-block::
70+
71+
App(7fc0d881fbd0)
72+
<class 'idom.core.component.Component'>
73+
74+
This explains the error. If we don't decorate the function we just get out out HTML
75+
dict, but if we do, we get this special ``Component`` object back. Since the ``run``
76+
function expects the latter to do its job we get an error about it.

src/idom/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .core.dispatcher import Stop
55
from .core.events import EventHandler, event
66
from .core.layout import Layout
7+
from .core.proto import ComponentType, VdomDict
78
from .core.vdom import vdom
89
from .sample import run_sample_app
910
from .server.prefab import run
@@ -17,6 +18,7 @@
1718
__all__ = [
1819
"component",
1920
"Component",
21+
"ComponentType",
2022
"config",
2123
"event",
2224
"EventHandler",
@@ -28,9 +30,10 @@
2830
"log",
2931
"multiview",
3032
"Ref",
31-
"run",
3233
"run_sample_app",
34+
"run",
3335
"Stop",
3436
"vdom",
37+
"VdomDict",
3538
"web",
3639
]

src/idom/core/component.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,6 @@ def __repr__(self) -> str:
7474
else:
7575
items = ", ".join(f"{k}={v!r}" for k, v in args.items())
7676
if items:
77-
return f"{self._func.__name__}({id(self)}, {items})"
77+
return f"{self._func.__name__}({id(self):02x}, {items})"
7878
else:
79-
return f"{self._func.__name__}({id(self)})"
79+
return f"{self._func.__name__}({id(self):02x})"

src/idom/core/layout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class Layout:
8383
def __init__(self, root: "ComponentType") -> None:
8484
super().__init__()
8585
if not isinstance(root, ComponentType):
86-
raise TypeError("Expected an ComponentType, not %r" % root)
86+
raise TypeError(f"Expected a ComponentType, not {type(root)!r}.")
8787
self.root = root
8888

8989
def __enter__(self: _Self) -> _Self:

tests/test_core/test_component.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def MyComponent(a, *b, **c):
88

99
mc1 = MyComponent(1, 2, 3, x=4, y=5)
1010

11-
expected = f"MyComponent({id(mc1)}, a=1, b=(2, 3), c={{'x': 4, 'y': 5}})"
11+
expected = f"MyComponent({id(mc1):02x}, a=1, b=(2, 3), c={{'x': 4, 'y': 5}})"
1212
assert repr(mc1) == expected
1313

1414
# not enough args supplied to function

tests/test_core/test_layout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def MyComponent():
2020

2121
my_component = MyComponent()
2222
layout = idom.Layout(my_component)
23-
assert str(layout) == f"Layout(MyComponent({id(my_component)}))"
23+
assert str(layout) == f"Layout(MyComponent({id(my_component):02x}))"
2424

2525

2626
def test_layout_expects_abstract_component():

0 commit comments

Comments
 (0)