Skip to content

Commit 93a56b2

Browse files
committed
more fixes
1 parent c9a176d commit 93a56b2

File tree

20 files changed

+171
-92
lines changed

20 files changed

+171
-92
lines changed

docs/source/guides/adding-interactivity/dangers-of-mutability/_examples/moving_dot.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ async def handle_pointer_move(event):
1919
html.div(
2020
style={
2121
"position": "absolute",
22-
"backgroundColor": "red",
23-
"borderRadius": "50%",
22+
"background_color": "red",
23+
"border_radius": "50%",
2424
"width": "20px",
2525
"height": "20px",
2626
"left": "-10px",
@@ -33,7 +33,7 @@ async def handle_pointer_move(event):
3333
"position": "relative",
3434
"height": "200px",
3535
"width": "100%",
36-
"backgroundColor": "white",
36+
"background_color": "white",
3737
},
3838
)
3939

docs/source/guides/adding-interactivity/dangers-of-mutability/_examples/moving_dot_broken.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ def handle_pointer_move(event):
1717
html.div(
1818
style={
1919
"position": "absolute",
20-
"backgroundColor": "red",
21-
"borderRadius": "50%",
20+
"background_color": "red",
21+
"border_radius": "50%",
2222
"width": "20px",
2323
"height": "20px",
2424
"left": "-10px",
@@ -31,7 +31,7 @@ def handle_pointer_move(event):
3131
"position": "relative",
3232
"height": "200px",
3333
"width": "100%",
34-
"backgroundColor": "white",
34+
"background_color": "white",
3535
},
3636
)
3737

docs/source/guides/adding-interactivity/dangers-of-mutability/_examples/set_remove.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def handle_click(event):
2323
style={
2424
"height": "30px",
2525
"width": "30px",
26-
"backgroundColor": "black"
26+
"background_color": "black"
2727
if index in selected_indices
2828
else "white",
2929
"outline": "1px solid grey",

docs/source/guides/adding-interactivity/dangers-of-mutability/_examples/set_update.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def handle_click(event):
2020
style={
2121
"height": "30px",
2222
"width": "30px",
23-
"backgroundColor": "black"
23+
"background_color": "black"
2424
if index in selected_indices
2525
else "white",
2626
"outline": "1px solid grey",

docs/source/guides/adding-interactivity/multiple-state-updates/_examples/set_color_3_times.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ def handle_reset(event):
1515

1616
return html.div(
1717
html.button(
18-
"Set Color", on_click=handle_click, style={"backgroundColor": color}
18+
"Set Color", on_click=handle_click, style={"background_color": color}
1919
),
20-
html.button("Reset", on_click=handle_reset, style={"backgroundColor": color}),
20+
html.button("Reset", on_click=handle_reset, style={"background_color": color}),
2121
)
2222

2323

docs/source/guides/adding-interactivity/responding-to-events/_examples/stop_event_propagation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ def DivInDiv():
1313
lambda event: set_inner_count(inner_count + 1),
1414
stop_propagation=stop_propagatation,
1515
),
16-
style={"height": "50px", "width": "50px", "backgroundColor": "blue"},
16+
style={"height": "50px", "width": "50px", "background_color": "blue"},
1717
),
1818
on_click=lambda event: set_outer_count(outer_count + 1),
19-
style={"height": "100px", "width": "100px", "backgroundColor": "red"},
19+
style={"height": "100px", "width": "100px", "background_color": "red"},
2020
)
2121

2222
return html.div(

docs/source/reference/_examples/matplotlib_plot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def poly_coef_input(index, callback):
6161
idom.html.label("C", idom.html.sub(index), " × X", idom.html.sup(index)),
6262
idom.html.input(type="number", on_change=callback),
6363
key=index,
64-
style={"margin-top": "5px"},
64+
style={"margin_top": "5px"},
6565
)
6666

6767

docs/source/reference/_examples/simple_dashboard.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def update_value(value):
8383
set_value_callback(value)
8484

8585
return idom.html.fieldset(
86-
idom.html.legend(label, style={"font-size": "medium"}),
86+
idom.html.legend(label, style={"font_size": "medium"}),
8787
Input(update_value, "number", value, attributes=attrs, cast=float),
8888
Input(update_value, "range", value, attributes=attrs, cast=float),
8989
class_="number-input-container",

docs/source/reference/_examples/snake_game.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ def create_grid(grid_size, block_scale):
154154
"width": f"{block_scale * grid_size}px",
155155
"cursor": "pointer",
156156
"display": "grid",
157-
"grid-gap": 0,
158-
"grid-template-columns": f"repeat({grid_size}, {block_scale}px)",
159-
"grid-template-rows": f"repeat({grid_size}, {block_scale}px)",
157+
"grid_gap": 0,
158+
"grid_template_columns": f"repeat({grid_size}, {block_scale}px)",
159+
"grid_template_rows": f"repeat({grid_size}, {block_scale}px)",
160160
},
161161
tab_index=-1,
162162
)
@@ -168,7 +168,7 @@ def create_grid_block(color, block_scale, key):
168168
style={
169169
"height": f"{block_scale}px",
170170
"width": f"{block_scale}px",
171-
"backgroundColor": color,
171+
"background_color": color,
172172
"outline": "1px solid grey",
173173
},
174174
)
@@ -177,7 +177,7 @@ def create_grid_block(color, block_scale, key):
177177
def assign_grid_block_color(grid, point, color):
178178
x, y = point
179179
block = grid["children"][x]["children"][y]
180-
block["attributes"]["style"]["backgroundColor"] = color
180+
block["attributes"]["style"]["background_color"] = color
181181

182182

183183
idom.run(GameView)

src/client/packages/idom-client-react/src/element-utils.js

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ export function createElementAttributes(model, sendEvent) {
2626
}
2727
}
2828

29-
return Object.fromEntries(
30-
Object.entries(attributes).map(([key, value]) => [snakeToCamel(key), value])
29+
const attrs = Object.fromEntries(
30+
Object.entries(attributes).map(normalizeAttribute)
3131
);
32+
console.log(attrs);
33+
return attrs;
3234
}
3335

3436
function createEventHandler(sendEvent, eventSpec) {
@@ -53,12 +55,32 @@ function createEventHandler(sendEvent, eventSpec) {
5355
};
5456
}
5557

56-
function snakeToCamel(str) {
57-
if (str.startsWith("data_") || str.startsWith("aria_")) {
58-
return str.replace("_", "-");
58+
function normalizeAttribute([key, value]) {
59+
let normKey = key;
60+
let normValue = value;
61+
62+
if (key === "style" && typeof value === "object") {
63+
normValue = Object.fromEntries(
64+
Object.entries(value).map(([k, v]) => [snakeToCamel(k), v])
65+
);
66+
} else if (
67+
key.startsWith("data_") ||
68+
key.startsWith("aria_") ||
69+
DASHED_HTML_ATTRS.includes(key)
70+
) {
71+
normKey = key.replace("_", "-");
5972
} else {
60-
return str
61-
.toLowerCase()
62-
.replace(/([-_][a-z])/g, (group) => group.toUpperCase().replace("_", ""));
73+
normKey = snakeToCamel(key);
6374
}
75+
return [normKey, normValue];
6476
}
77+
78+
function snakeToCamel(str) {
79+
return str.replace(/([_][a-z])/g, (group) =>
80+
group.toUpperCase().replace("_", "")
81+
);
82+
}
83+
84+
// see list of HTML attributes with dashes in them:
85+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#attribute_list
86+
const DASHED_HTML_ATTRS = ["accept_charset", "http_equiv"];

src/idom/_option.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from __future__ import annotations
22

33
import os
4-
from inspect import currentframe
54
from logging import getLogger
6-
from types import FrameType
75
from typing import Any, Callable, Generic, Iterator, TypeVar, cast
86
from warnings import warn
97

8+
from idom._warnings import warn
9+
1010

1111
_O = TypeVar("_O")
1212
logger = getLogger(__name__)
@@ -129,25 +129,5 @@ def current(self) -> _O:
129129
warn(
130130
self._deprecation_message,
131131
DeprecationWarning,
132-
stacklevel=_frame_depth_in_module() + 1,
133132
)
134133
return super().current
135-
136-
137-
def _frame_depth_in_module() -> int:
138-
depth = 0
139-
for frame in _iter_frames(2):
140-
if frame.f_globals.get("__name__") != __name__:
141-
break
142-
depth += 1
143-
return depth
144-
145-
146-
def _iter_frames(index: int = 1) -> Iterator[FrameType]:
147-
frame = currentframe()
148-
while frame is not None:
149-
if index == 0:
150-
yield frame
151-
else:
152-
index -= 1
153-
frame = frame.f_back

src/idom/_warnings.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from functools import wraps
2+
from inspect import currentframe
3+
from types import FrameType
4+
from typing import Any, Iterator
5+
from warnings import warn as _warn
6+
7+
8+
@wraps(_warn)
9+
def warn(*args: Any, **kwargs: Any) -> Any:
10+
# warn at call site outside of IDOM
11+
_warn(*args, stacklevel=_frame_depth_in_module() + 1, **kwargs)
12+
13+
14+
def _frame_depth_in_module() -> int:
15+
depth = 0
16+
for frame in _iter_frames(2):
17+
module_name = frame.f_globals.get("__name__")
18+
if not module_name or not module_name.startswith("idom."):
19+
break
20+
depth += 1
21+
return depth
22+
23+
24+
def _iter_frames(index: int = 1) -> Iterator[FrameType]:
25+
frame = currentframe()
26+
while frame is not None:
27+
if index == 0:
28+
yield frame
29+
else:
30+
index -= 1
31+
frame = frame.f_back

src/idom/core/vdom.py

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
import logging
44
from typing import Any, Mapping, cast
5-
from warnings import warn
65

76
from fastjsonschema import compile as compile_json_schema
87

8+
from idom._warnings import warn
99
from idom.config import IDOM_DEBUG_MODE
1010
from idom.core.events import (
1111
EventHandler,
@@ -15,6 +15,7 @@
1515
from idom.core.types import (
1616
ComponentType,
1717
EventHandlerDict,
18+
EventHandlerMapping,
1819
EventHandlerType,
1920
ImportSourceDict,
2021
Key,
@@ -159,11 +160,13 @@ def vdom(
159160
if isinstance(child, dict) and "tagName" not in child:
160161
warn(
161162
(
162-
"Element constructor signatures have changed! A CLI tool for "
163-
"automatically updating code to the latest API has been provided "
164-
"with this release of IDOM (e.g. 'idom update-html-usages'). For "
165-
"start a discussion if you need help transitioning to this new "
166-
"interface: https://github.com/idom-team/idom/discussions/new?category=question"
163+
"Element constructor signatures have changed! This will be an "
164+
"error in a future release. A CLI tool for automatically updating "
165+
"code to the latest API has been provided with this release of "
166+
"IDOM (e.g. 'idom update-html-usages'). However, it may not "
167+
"resolve all issues arrising from this change. Start a discussion "
168+
"if you need help transitioning to this new interface: "
169+
"https://github.com/idom-team/idom/discussions/new?category=question"
167170
),
168171
DeprecationWarning,
169172
)
@@ -194,19 +197,62 @@ def with_import_source(element: VdomDict, import_source: ImportSourceDict) -> Vd
194197
return {**element, "importSource": import_source}
195198

196199

197-
def make_vdom_constructor(tag: str, allow_children: bool = True) -> VdomDictConstructor:
200+
def with_event_handlers(
201+
element: VdomDict, event_handlers: EventHandlerMapping
202+
) -> VdomDict:
203+
if "eventHandlers" in element:
204+
old_handlers = element["eventHandlers"]
205+
new_handlers = {
206+
merge_event_handlers((old_handlers[k], event_handlers[h]))
207+
if k in old_handlers
208+
else h
209+
for k, h in event_handlers
210+
}
211+
return {**element, "eventHandlers": new_handlers}
212+
else:
213+
return {**element, "eventHandlers": dict(event_handlers)}
214+
215+
216+
def make_vdom_constructor(
217+
tag: str,
218+
allow_children: bool = True,
219+
import_source: ImportSourceDict | None = None,
220+
event_handlers: EventHandlerMapping | None = None,
221+
) -> VdomDictConstructor:
198222
"""Return a constructor for VDOM dictionaries with the given tag name.
199223
200224
The resulting callable will have the same interface as :func:`vdom` but without its
201225
first ``tag`` argument.
202226
"""
203227

204-
def constructor(
205-
*children: VdomChild, key: Key | None = None, **attributes: Any
206-
) -> VdomDict:
207-
if not allow_children and children:
208-
raise TypeError(f"{tag!r} nodes cannot have children.")
209-
return vdom(tag, *children, key=key, **attributes)
228+
if import_source is not None:
229+
230+
def constructor(
231+
*children: VdomChild, key: Key | None = None, **attributes: Any
232+
) -> VdomDict:
233+
if not allow_children and children:
234+
raise TypeError(f"{tag!r} nodes cannot have children.")
235+
return with_import_source(
236+
vdom(tag, *children, key=key, **attributes), import_source
237+
)
238+
239+
else:
240+
241+
def constructor(
242+
*children: VdomChild, key: Key | None = None, **attributes: Any
243+
) -> VdomDict:
244+
if not allow_children and children:
245+
raise TypeError(f"{tag!r} nodes cannot have children.")
246+
return vdom(tag, *children, key=key, **attributes)
247+
248+
if event_handlers:
249+
_constructor = constructor
250+
251+
def constructor(
252+
*children: VdomChild, key: Key | None = None, **attributes: Any
253+
) -> VdomDict:
254+
model = _constructor(*children, key=key, **attributes)
255+
return with_event_handlers(model, event_handlers)
210256

211257
# replicate common function attributes
212258
constructor.__name__ = tag

0 commit comments

Comments
 (0)