diff --git a/README.md b/README.md index f267912..f4d9e07 100644 --- a/README.md +++ b/README.md @@ -44,14 +44,16 @@ print(page.render(pretty=True)) pip install nitro-ui ``` -### Claude Code Skill +### AI Assistant Integration -Add NitroUI as a skill in [Claude Code](https://claude.ai/code) for AI-assisted HTML generation: +Add NitroUI knowledge to your AI coding assistant: ```bash npx skills add nitrosh/nitro-ui ``` +This enables AI assistants like Claude Code to understand NitroUI and generate correct HTML code. + ## Quick Examples ### Dynamic Content @@ -421,11 +423,11 @@ black src/ tests/ ## Ecosystem -- **[nitro-cli](https://github.com/nitrosh/nitro-cli)** - Static site generator -- **[nitro-ui](https://github.com/nitrosh/nitro-ui)** - Programmatic HTML generation -- **[nitro-datastore](https://github.com/nitrosh/nitro-datastore)** - Data loading with dot notation access -- **[nitro-dispatch](https://github.com/nitrosh/nitro-dispatch)** - Plugin system -- **[nitro-validate](https://github.com/nitrosh/nitro-validate)** - Data validation +- **[nitro-cli](https://github.com/nitrosh/nitro-cli)** - Python-powered static site generator +- **[nitro-datastore](https://github.com/nitrosh/nitro-datastore)** - Schema-free JSON data store with dot notation access +- **[nitro-dispatch](https://github.com/nitrosh/nitro-dispatch)** - Framework-agnostic plugin system +- **[nitro-image](https://github.com/nitrosh/nitro-image)** - Fast, friendly image processing for the web +- **[nitro-validate](https://github.com/nitrosh/nitro-validate)** - Dependency-free data validation ## License diff --git a/SKILL.md b/SKILL.md index 20df8c8..69109c0 100644 --- a/SKILL.md +++ b/SKILL.md @@ -850,10 +850,12 @@ form = Form( ) ``` +All `Field.*` methods accept an optional `id` parameter (defaults to `name` when omitted) and forward any additional keyword arguments (including `hx_*`) to the underlying input via `**attrs`. + ### Text Fields ```python -Field.text(name, label=None, required=False, min_length=None, max_length=None, pattern=None, placeholder=None, value=None, wrapper=None, **attrs) +Field.text(name, label=None, required=False, min_length=None, max_length=None, pattern=None, placeholder=None, value=None, id=None, wrapper=None, **attrs) Field.email(name, label=None, required=False, placeholder=None, value=None, wrapper=None, **attrs) Field.password(name, label=None, required=False, min_length=None, max_length=None, placeholder=None, wrapper=None, **attrs) Field.url(name, label=None, required=False, placeholder=None, value=None, wrapper=None, **attrs) @@ -883,8 +885,8 @@ Field.select("priority", [{"value": "1", "label": "Low", "disabled": True}]) # # Pre-selected value Field.select("country", ["USA", "Canada"], value="Canada", label="Country") -# Checkbox (label wraps input) -Field.checkbox("terms", label="I agree to the Terms", required=True) +# Checkbox (label wraps input, accepts checked=True and value="on") +Field.checkbox("terms", label="I agree to the Terms", required=True, checked=False) # Radio buttons (wrapped in fieldset) Field.radio("plan", [("free", "Free"), ("pro", "Pro")], label="Select Plan", value="free") diff --git a/examples/attributes_and_styles.py b/examples/attributes_and_styles.py index d4f446c..361593f 100644 --- a/examples/attributes_and_styles.py +++ b/examples/attributes_and_styles.py @@ -39,7 +39,7 @@ def constructor_attributes(): print() # Link with target and rel - link = Link( + link = Anchor( "External Link", href="https://example.com", target="_blank", @@ -216,8 +216,8 @@ def aria_attributes(): # Navigation with ARIA landmark nav = Nav( - Link("Home", href="/"), - Link("About", href="/about"), + Anchor("Home", href="/"), + Anchor("About", href="/about"), aria_label="Main navigation", role="navigation", ) diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 21fa7b6..7ea7611 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -32,16 +32,16 @@ def document_structure(): Meta(charset="utf-8"), Meta(name="viewport", content="width=device-width, initial-scale=1.0"), Meta(name="description", content="A website built with NitroUI"), - HtmlLink(rel="stylesheet", href="/css/styles.css"), - HtmlLink(rel="icon", href="/favicon.ico"), + Link(rel="stylesheet", href="/css/styles.css"), + Link(rel="icon", href="/favicon.ico"), Script(src="/js/main.js", defer="true"), ), Body( Header( Nav( - Link("Home", href="/"), - Link("About", href="/about"), - Link("Contact", href="/contact"), + Anchor("Home", href="/"), + Anchor("About", href="/about"), + Anchor("Contact", href="/contact"), ) ), Main(H1("Welcome"), Paragraph("This is the main content area.")), @@ -77,7 +77,7 @@ def text_elements(): ", ", Ins("inserted text"), ", and ", - Link("hyperlinks", href="https://example.com"), + Anchor("hyperlinks", href="https://example.com"), ".", ), Blockquote( @@ -106,9 +106,9 @@ def layout_elements(): Header( H1("Site Title"), Nav( - Link("Home", href="/"), - Link("Products", href="/products"), - Link("About", href="/about"), + Anchor("Home", href="/"), + Anchor("Products", href="/products"), + Anchor("About", href="/about"), ), ), Main( @@ -129,9 +129,9 @@ def layout_elements(): Aside( H3("Related Links"), UnorderedList( - ListItem(Link("Link 1", href="#")), - ListItem(Link("Link 2", href="#")), - ListItem(Link("Link 3", href="#")), + ListItem(Anchor("Link 1", href="#")), + ListItem(Anchor("Link 2", href="#")), + ListItem(Anchor("Link 3", href="#")), ), ), ), @@ -230,9 +230,9 @@ def conditional_rendering(): if user["is_admin"]: header.append( Nav( - Link("Dashboard", href="/dashboard"), - Link("Users", href="/users"), - Link("Settings", href="/settings"), + Anchor("Dashboard", href="/dashboard"), + Anchor("Users", href="/users"), + Anchor("Settings", href="/settings"), class_name="admin-nav", ) ) diff --git a/examples/context_managers.py b/examples/context_managers.py index f25509f..1d3388d 100644 --- a/examples/context_managers.py +++ b/examples/context_managers.py @@ -33,9 +33,9 @@ def nested_context_managers(): with Header(class_name="site-header") as header: header.append(H1("My Website")) with Nav(class_name="main-nav") as nav: - nav.append(Link("Home", href="/")) - nav.append(Link("About", href="/about")) - nav.append(Link("Contact", href="/contact")) + nav.append(Anchor("Home", href="/")) + nav.append(Anchor("About", href="/about")) + nav.append(Anchor("Contact", href="/contact")) header.append(nav) page.append(header) @@ -60,7 +60,7 @@ def comparison_with_regular(): # Regular nesting (constructor-based) regular = Div( - Header(H1("Title"), Nav(Link("Home", href="/"), Link("About", href="/about"))), + Header(H1("Title"), Nav(Anchor("Home", href="/"), Anchor("About", href="/about"))), Main(Article(H2("Article"), Paragraph("Content"))), Footer(Paragraph("Footer")), id="regular", @@ -74,8 +74,8 @@ def comparison_with_regular(): with Header() as header: header.append(H1("Title")) with Nav() as nav: - nav.append(Link("Home", href="/")) - nav.append(Link("About", href="/about")) + nav.append(Anchor("Home", href="/")) + nav.append(Anchor("About", href="/about")) header.append(nav) context.append(header) @@ -139,16 +139,16 @@ def conditional_with_context(): with Nav(class_name="user-nav") as nav: if is_logged_in: - nav.append(Link("Profile", href="/profile")) - nav.append(Link("Settings", href="/settings")) + nav.append(Anchor("Profile", href="/profile")) + nav.append(Anchor("Settings", href="/settings")) if is_admin: - nav.append(Link("Admin Panel", href="/admin")) + nav.append(Anchor("Admin Panel", href="/admin")) - nav.append(Link("Logout", href="/logout")) + nav.append(Anchor("Logout", href="/logout")) else: - nav.append(Link("Login", href="/login")) - nav.append(Link("Sign Up", href="/signup")) + nav.append(Anchor("Login", href="/login")) + nav.append(Anchor("Sign Up", href="/signup")) header.append(nav) @@ -273,7 +273,7 @@ def complex_layout_with_context(): with UnorderedList() as menu: for item in sidebar_items: with ListItem() as li: - li.append(Link(item, href=f"/{item.lower()}")) + li.append(Anchor(item, href=f"/{item.lower()}")) menu.append(li) nav.append(menu) sidebar.append(nav) @@ -331,7 +331,7 @@ def mixing_styles_in_context(): # Regular nesting for simple structures container.append( Header( - H1("Title"), Nav(Link("Link 1", href="#1"), Link("Link 2", href="#2")) + H1("Title"), Nav(Anchor("Link 1", href="#1"), Anchor("Link 2", href="#2")) ) ) diff --git a/examples/custom_components.py b/examples/custom_components.py index e51c34d..2258a3d 100644 --- a/examples/custom_components.py +++ b/examples/custom_components.py @@ -281,7 +281,7 @@ def __init__(self, text, href="#", active=False, **kwargs): self.add_attribute("class", "nav-item") - link = Link(text, href=href, class_name="nav-link") + link = Anchor(text, href=href, class_name="nav-link") if active: link.add_attribute("class", "nav-link active") link.add_style("font-weight", "600") @@ -308,7 +308,7 @@ def __init__(self, brand, *items, **kwargs): # Brand self.append( - Link(brand, href="/", class_name="navbar-brand").add_styles( + Anchor(brand, href="/", class_name="navbar-brand").add_styles( { "font-size": "20px", "font-weight": "700", diff --git a/examples/framework_integration.py b/examples/framework_integration.py index 938d604..f1d04f7 100644 --- a/examples/framework_integration.py +++ b/examples/framework_integration.py @@ -23,7 +23,7 @@ def base_layout(title, *content): Title(title), Meta(charset="utf-8"), Meta(name="viewport", content="width=device-width, initial-scale=1.0"), - HtmlLink(rel="stylesheet", href="/static/styles.css"), + Link(rel="stylesheet", href="/static/styles.css"), Style( """ body { font-family: system-ui, sans-serif; margin: 0; padding: 0; } @@ -36,9 +36,9 @@ def base_layout(title, *content): ), Body( Nav( - Link("Home", href="/", class_name="nav-link"), - Link("Users", href="/users", class_name="nav-link"), - Link("API", href="/api/status", class_name="nav-link"), + Anchor("Home", href="/", class_name="nav-link"), + Anchor("Users", href="/users", class_name="nav-link"), + Anchor("API", href="/api/status", class_name="nav-link"), class_name="nav", ), Main(Div(*content, class_name="container")), @@ -53,7 +53,7 @@ def user_card(user): H3(user["name"]), Paragraph(f"Email: {user['email']}"), Paragraph(f"Role: {user['role']}"), - Link("View Profile", href=f"/users/{user['id']}"), + Anchor("View Profile", href=f"/users/{user['id']}"), class_name="card", ) @@ -65,7 +65,7 @@ def error_page(code, message): Div( H1(f"Error {code}"), Paragraph(message), - Link("Go Home", href="/"), + Anchor("Go Home", href="/"), class_name="error-page", ), ) @@ -101,7 +101,7 @@ async def home(): Body( H1("Welcome to FastAPI + NitroUI"), Paragraph("Build HTML with Python, not templates."), - Link("View Users", href="/users") + Anchor("View Users", href="/users") ) ) return page.render() @@ -119,7 +119,7 @@ async def list_users(): Div( H3(user["name"]), Paragraph(f"Email: {user['email']}"), - Link("View", href=f"/users/{user['id']}"), + Anchor("View", href=f"/users/{user['id']}"), class_name="card" ) for user in users_db @@ -150,7 +150,7 @@ async def get_user(user_id: int): H1(user["name"]), Paragraph(f"Email: {user['email']}"), Paragraph(f"Role: {user['role']}"), - Link("Back to Users", href="/users") + Anchor("Back to Users", href="/users") ) ) return page.render() @@ -197,14 +197,14 @@ def layout(title, *content): Head( Title(title), Meta(charset="utf-8"), - HtmlLink(rel="stylesheet", href="/static/style.css") + Link(rel="stylesheet", href="/static/style.css") ), Body( Header( Nav( - Link("Home", href="/"), - Link("Products", href="/products"), - Link("About", href="/about") + Anchor("Home", href="/"), + Anchor("Products", href="/products"), + Anchor("About", href="/about") ) ), Main(*content), @@ -240,7 +240,7 @@ def list_products(): TableRow( TableDataCell(p["name"]), TableDataCell(f"${p['price']:.2f}"), - TableDataCell(Link("View", href=f"/products/{p['id']}")) + TableDataCell(Anchor("View", href=f"/products/{p['id']}")) ) for p in products ] @@ -260,7 +260,7 @@ def get_product(product_id): product["name"], H1(product["name"]), Paragraph(f"Price: ${product['price']:.2f}"), - Link("Back to Products", href="/products") + Anchor("Back to Products", href="/products") ) @@ -270,7 +270,7 @@ def not_found(error): "Not Found", H1("404 - Page Not Found"), Paragraph("The page you requested could not be found."), - Link("Go Home", href="/") + Anchor("Go Home", href="/") ), 404 @@ -305,14 +305,14 @@ def layout(title, *content): Meta(charset="utf-8"), Meta(name="viewport", content="width=device-width, initial-scale=1.0"), # Django static files - HtmlLink(rel="stylesheet", href="/static/css/styles.css") + Link(rel="stylesheet", href="/static/css/styles.css") ), Body( Header( Nav( - Link("Home", href="/"), - Link("Articles", href="/articles/"), - Link("Contact", href="/contact/") + Anchor("Home", href="/"), + Anchor("Articles", href="/articles/"), + Anchor("Contact", href="/contact/") ) ), Main(Div(*content, class_name="container")), @@ -343,7 +343,7 @@ def article_list(request): Div( *[ Article( - H2(Link(a.title, href=f"/articles/{a.id}/")), + H2(Anchor(a.title, href=f"/articles/{a.id}/")), Paragraph(a.excerpt), Small(f"Published: {a.published_date}") ) @@ -369,7 +369,7 @@ def get(self, request, article_id): H1(article.title), Paragraph(article.content), Small(f"By {article.author} on {article.published_date}"), - Link("Back to Articles", href="/articles/") + Anchor("Back to Articles", href="/articles/") ) ) return HttpResponse(page.render()) @@ -469,7 +469,7 @@ async def user_page(request): html = layout( f"User {user_id}", H1(f"User Profile: {user_id}"), - Link("Back", href="/") + Anchor("Back", href="/") ) return HTMLResponse(html) @@ -479,7 +479,7 @@ async def not_found(request, exc): "Not Found", H1("404 - Not Found"), Paragraph("Page does not exist."), - Link("Home", href="/") + Anchor("Home", href="/") ) return HTMLResponse(html, status_code=404) @@ -682,7 +682,7 @@ async def embed_product(product_id: int): widget = Div( H3(product["name"]), Paragraph(f"${product['price']:.2f}"), - Link("Buy Now", href=f"https://yoursite.com/products/{product_id}"), + Anchor("Buy Now", href=f"https://yoursite.com/products/{product_id}"), class_name="product-widget" ).add_styles({ "border": "1px solid #ddd", @@ -712,7 +712,7 @@ async def welcome_email(user_id: int): H1("Welcome, " + user["name"] + "!"), Paragraph("Thanks for signing up."), Paragraph("Click below to get started:"), - Link( + Anchor( "Get Started", href="https://yoursite.com/onboard" ).add_styles({ diff --git a/examples/html_parsing.py b/examples/html_parsing.py index 1e29a27..f9ef245 100644 --- a/examples/html_parsing.py +++ b/examples/html_parsing.py @@ -319,12 +319,12 @@ def register(self, name, html_string): """Register an HTML template.""" self.templates[name] = html_string - def get(self, name, **replacements): + def get(self, template_name, **replacements): """Get a template instance with optional text replacements.""" - if name not in self.templates: - raise ValueError(f"Template '{name}' not found") + if template_name not in self.templates: + raise ValueError(f"Template '{template_name}' not found") - element = from_html(self.templates[name]) + element = from_html(self.templates[template_name]) # Simple text replacement for attr_value, new_text in replacements.items(): @@ -397,13 +397,13 @@ def external_html_import(): Head( Title("Our Service"), Meta(charset="utf-8"), - HtmlLink(rel="stylesheet", href="/styles.css"), + Link(rel="stylesheet", href="/styles.css"), ), Body( Header( Nav( - Link("Home", href="/"), - Link("Services", href="/services"), + Anchor("Home", href="/"), + Anchor("Services", href="/services"), class_name="main-nav", ) ), diff --git a/examples/json_serialization.py b/examples/json_serialization.py index a1ab473..74c8e52 100644 --- a/examples/json_serialization.py +++ b/examples/json_serialization.py @@ -37,8 +37,8 @@ def serialize_complex_structure(): page = Div( Header( Nav( - Link("Home", href="/", class_name="nav-link"), - Link("About", href="/about", class_name="nav-link"), + Anchor("Home", href="/", class_name="nav-link"), + Anchor("About", href="/about", class_name="nav-link"), class_name="main-nav", ) ), diff --git a/examples/media_elements.py b/examples/media_elements.py index 0dae435..1765271 100644 --- a/examples/media_elements.py +++ b/examples/media_elements.py @@ -236,7 +236,7 @@ def embed_and_object(): Param(name="quality", value="high"), Paragraph( "Flash content not supported. ", - Link("Download instead", href="/files/animation.swf"), + Anchor("Download instead", href="/files/animation.swf"), ), data="/flash/animation.swf", type="application/x-shockwave-flash", diff --git a/examples/method_chaining.py b/examples/method_chaining.py index 5d63d99..8f0e86f 100644 --- a/examples/method_chaining.py +++ b/examples/method_chaining.py @@ -90,11 +90,11 @@ def chaining_children(): nav = ( Nav() .add_attribute("class", "main-nav") - .append(Link("Home", href="/")) - .append(Link("Products", href="/products")) - .append(Link("Services", href="/services")) - .append(Link("About", href="/about")) - .append(Link("Contact", href="/contact")) + .append(Anchor("Home", href="/")) + .append(Anchor("Products", href="/products")) + .append(Anchor("Services", href="/services")) + .append(Anchor("About", href="/about")) + .append(Anchor("Contact", href="/contact")) ) print("Navigation built with chained appends:") @@ -212,8 +212,8 @@ def conditional_chaining(): if is_admin: header.append( Nav( - Link("Users", href="/admin/users"), - Link("Settings", href="/admin/settings"), + Anchor("Users", href="/admin/users"), + Anchor("Settings", href="/admin/settings"), class_name="admin-nav", ) ) diff --git a/examples/tables.py b/examples/tables.py index 0d193b4..248c0d8 100644 --- a/examples/tables.py +++ b/examples/tables.py @@ -362,7 +362,7 @@ def sortable_table(): def sortable_header(text, column): """Create a sortable header cell.""" return TableHeaderCell( - Link( + Anchor( text, Span(" ↕", class_name="sort-icon"), href=f"?sort={column}", diff --git a/pyproject.toml b/pyproject.toml index 32540f5..cb07716 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta" [project] name = "nitro-ui" -version = "1.0.8" +version = "1.0.9" description = "Build HTML with Python, not strings. Zero-dependency library with type-safe elements, method chaining, and JSON serialization." readme = "README.md" requires-python = ">=3.8" license-files = ["LICEN[CS]E*"] authors = [ - { name = "Sean Nieuwoudt", email = "sean@underwulf.com" } + { name = "Sean Nieuwoudt", email = "sean@nitro.sh" } ] classifiers = [ "Operating System :: OS Independent", @@ -29,16 +29,28 @@ classifiers = [ "Topic :: Utilities", "Natural Language :: English" ] -keywords = ["json", "ui", "framework", "html", "components", "frontend"] +keywords = [ + "html", + "html-generation", + "ui", + "components", + "frontend", + "templating", + "htmx", + "ssr", + "nitro", + "static-site", + "json-serialization", +] dependencies = [ ] [project.urls] -Homepage = "https://github.com/nitro-sh/nitro-ui" -Documentation = "https://github.com/nitro-sh/nitro-ui#readme" -Repository = "https://github.com/nitro-sh/nitro-ui" -Issues = "https://github.com/nitro-sh/nitro-ui/issues" +Homepage = "https://github.com/nitrosh/nitro-ui" +Documentation = "https://github.com/nitrosh/nitro-ui#readme" +Repository = "https://github.com/nitrosh/nitro-ui" +Issues = "https://github.com/nitrosh/nitro-ui/issues" [tool.setuptools] package-dir = { "" = "src" } diff --git a/src/nitro_ui/core/component.py b/src/nitro_ui/core/component.py index e9da17c..76b26e9 100644 --- a/src/nitro_ui/core/component.py +++ b/src/nitro_ui/core/component.py @@ -1,5 +1,5 @@ import inspect -from typing import Union, List, Any, Dict, Set +from typing import List, Any, Dict, Set from nitro_ui.core.element import HTMLElement from nitro_ui.core.slot import Slot diff --git a/src/nitro_ui/py.typed b/src/nitro_ui/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/src/nitro_ui/styles/theme.py b/src/nitro_ui/styles/theme.py index a819507..812bf4c 100644 --- a/src/nitro_ui/styles/theme.py +++ b/src/nitro_ui/styles/theme.py @@ -367,8 +367,14 @@ def minimal(cls) -> "Theme": "black": "#000000", }, typography={ - "body": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif", - "heading": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif", + "body": ( + "-apple-system, BlinkMacSystemFont, 'Segoe UI', " + "Helvetica, Arial, sans-serif" + ), + "heading": ( + "-apple-system, BlinkMacSystemFont, 'Segoe UI', " + "Helvetica, Arial, sans-serif" + ), "mono": "'SF Mono', Monaco, 'Cascadia Code', monospace", "sizes": { "xs": "12px", diff --git a/tests/test_component.py b/tests/test_component.py index 7ac9f60..f5fd00e 100644 --- a/tests/test_component.py +++ b/tests/test_component.py @@ -56,7 +56,8 @@ def template(self, title: str): result = Card("My Title", Paragraph("Content")) self.assertEqual( str(result), - '

My Title

Content

', + '

My Title

' + "

Content

", ) def test_component_prop_with_default(self): diff --git a/tests/test_element.py b/tests/test_element.py index 98c7bc6..1bffba0 100644 --- a/tests/test_element.py +++ b/tests/test_element.py @@ -368,7 +368,10 @@ def test_from_dict_missing_tag(self): def test_from_json_simple_element(self): """Test reconstruction from JSON string.""" - json_str = '{"tag": "p", "self_closing": false, "attributes": {"id": "test"}, "text": "Hello", "children": []}' + json_str = ( + '{"tag": "p", "self_closing": false, ' + '"attributes": {"id": "test"}, "text": "Hello", "children": []}' + ) element = HTMLElement.from_json(json_str) self.assertEqual(element.tag, "p") diff --git a/tests/test_form.py b/tests/test_form.py index a2cf6d0..93de19d 100644 --- a/tests/test_form.py +++ b/tests/test_form.py @@ -38,7 +38,9 @@ def test_select_with_items(self): self.assertEqual(select.tag, "select") self.assertEqual( str(select), - "", + "", ) def test_option(self): @@ -73,7 +75,11 @@ def test_form_with_fields(self): Button("Submit"), ) self.assertEqual(form.tag, "form") - expected = '
' + expected = ( + '
' + '' + "
" + ) self.assertEqual(str(form), expected) def test_input(self): @@ -97,7 +103,8 @@ def test_optgroup(self): self.assertEqual(optgroup.tag, "optgroup") self.assertEqual( str(optgroup), - '', + '' + "", ) def test_legend(self): @@ -112,7 +119,10 @@ def test_fieldset_with_legend(self): Legend("Contact Details"), Input(type="email", name="email"), ) - expected = '
Contact Details
' + expected = ( + "
Contact Details" + '
' + ) self.assertEqual(str(fieldset), expected) def test_output(self): diff --git a/tests/test_forms.py b/tests/test_forms.py index 0955d4d..11fdf92 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -1,8 +1,6 @@ import unittest from nitro_ui import Field, Form, Button -from nitro_ui.core.fragment import Fragment -from nitro_ui.tags.layout import Div class TestFieldText(unittest.TestCase): diff --git a/tests/test_fragment.py b/tests/test_fragment.py index b057b1e..dd25171 100644 --- a/tests/test_fragment.py +++ b/tests/test_fragment.py @@ -40,7 +40,10 @@ def test_fragment_multiple_children(self): ) rendered = str(fragment) - expected = "

Header

Paragraph 1

Paragraph 2

Inline text" + expected = ( + "

Header

Paragraph 1

" + "

Paragraph 2

Inline text" + ) self.assertEqual(rendered, expected) def test_fragment_nested_elements(self): diff --git a/tests/test_htmx.py b/tests/test_htmx.py index f6a214c..f9f90f7 100644 --- a/tests/test_htmx.py +++ b/tests/test_htmx.py @@ -1,6 +1,6 @@ import unittest -from nitro_ui import Button, Div, Form, Input, Span +from nitro_ui import Button, Div, Form, Input from nitro_ui.tags.text import Href diff --git a/tests/test_layout.py b/tests/test_layout.py index 38095f3..853aa92 100644 --- a/tests/test_layout.py +++ b/tests/test_layout.py @@ -118,7 +118,10 @@ def test_details_with_summary(self): details = Details( Summary("More information"), Paragraph("This is the hidden content") ) - expected = "
More information

This is the hidden content

" + expected = ( + "
More information" + "

This is the hidden content

" + ) self.assertEqual(str(details), expected) def test_dialog(self):