diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 54ba8f4..a068490 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -10,7 +10,7 @@ default_stages:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.5.0
+ rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -21,18 +21,14 @@ repos:
- id: detect-private-key
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.4.5
+ rev: v0.14.4
hooks:
- id: ruff-format
-
- - repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.4.5
- hooks:
- id: ruff
args: ["--fix", "--exit-non-zero-on-fix", "--config", "pyproject.toml"]
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.10.1
+ rev: v1.18.2
hooks:
- id: mypy
args: ["--ignore-missing-imports"]
diff --git a/pyproject.toml b/pyproject.toml
index 6b7820b..a6d14ae 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -44,6 +44,9 @@ dev = [
line-length = 88
target-version = "py312"
+[tool.ruff.format]
+quote-style = "double"
+
[tool.ruff.lint]
select = [
"E", # flake8 rules
diff --git a/web/components.py b/web/components.py
index f7e955b..9abe042 100644
--- a/web/components.py
+++ b/web/components.py
@@ -260,11 +260,11 @@ class Footer(Component[NoChildren, NoAttrs]):
@override
def render(self) -> Box:
return Box(
- f"Made with {b(Link("Ludic", to=config.GITHUB_REPO_URL))} "
- f"and {b(Link("HTMX", to="https://htmx.org"))} and 🐍 "
- f"• {b(Link("Discord", to=config.DISCORD_INVITE_URL))} "
- f"• {b(Link("GitHub", to=config.GITHUB_REPO_URL))} "
- f"• Running on {b(Link("Leapcell", to="https://leapcell.io"))} "
+ f"Made with {b(Link('Ludic', to=config.GITHUB_REPO_URL))} "
+ f"and {b(Link('HTMX', to='https://htmx.org'))} and 🐍 "
+ f"• {b(Link('Discord', to=config.DISCORD_INVITE_URL))} "
+ f"• {b(Link('GitHub', to=config.GITHUB_REPO_URL))} "
+ f"• Running on {b(Link('Leapcell', to='https://leapcell.io'))} "
)
@@ -365,9 +365,9 @@ class EditOnGithub(Component[AnyChildren, EditOnGithubAttrs]):
@override
def render(self) -> div:
file_path = (
- f"{self.attrs["base_url"].replace("-", "_")}index.py"
+ f"{self.attrs['base_url'].replace('-', '_')}index.py"
if self.attrs["base_url"].endswith("/")
- else f"{self.attrs["base_url"].replace("-", "_")}.py"
+ else f"{self.attrs['base_url'].replace('-', '_')}.py"
)
url = f"{config.GITHUB_REPO_WEB_URL}/blob/main/web/endpoints{file_path}"
return div(
@@ -407,6 +407,6 @@ def render(self) -> blockquote:
return blockquote(
div(
p(i('"', *self.children, '"')),
- p(b(f"– {self.attrs["source"]}")),
+ p(b(f"– {self.attrs['source']}")),
),
)
diff --git a/web/endpoints/catalog/buttons.py b/web/endpoints/catalog/buttons.py
index b207cc0..20da99f 100644
--- a/web/endpoints/catalog/buttons.py
+++ b/web/endpoints/catalog/buttons.py
@@ -20,7 +20,7 @@ def buttons(request: Request) -> Page:
return Page(
H1("Buttons"),
Paragraph(
- f"The module {Code("ludic.catalog.buttons")} contains the following "
+ f"The module {Code('ludic.catalog.buttons')} contains the following "
"buttons:"
),
Box(
@@ -61,8 +61,8 @@ def buttons(request: Request) -> Page:
language="python",
),
Paragraph(
- f"The {Code("ButtonLink")} component can be styled like any other "
- f"button using the {Code("classes")} attribute:"
+ f"The {Code('ButtonLink')} component can be styled like any other "
+ f"button using the {Code('classes')} attribute:"
),
CodeBlock(
"""
@@ -72,7 +72,7 @@ def buttons(request: Request) -> Page:
""",
language="python",
),
- Paragraph(f"You can disable a button using the {Code("disabled")} attribute:"),
+ Paragraph(f"You can disable a button using the {Code('disabled')} attribute:"),
Box(
Cluster(
Button("Button", disabled=True),
@@ -96,7 +96,7 @@ def buttons(request: Request) -> Page:
H2("Button Sizes"),
Paragraph(
"You can also change the size of the button appending the "
- f"{Code("small")} or {Code("large")} class:"
+ f"{Code('small')} or {Code('large')} class:"
),
Box(
Cluster(
diff --git a/web/endpoints/catalog/forms.py b/web/endpoints/catalog/forms.py
index 8482001..cee76ef 100644
--- a/web/endpoints/catalog/forms.py
+++ b/web/endpoints/catalog/forms.py
@@ -29,15 +29,15 @@ def forms(request: Request) -> Page:
return Page(
H1("Forms"),
Paragraph(
- f"These components located in {Code("ludic.catalog.forms")} are in an "
+ f"These components located in {Code('ludic.catalog.forms')} are in an "
"experimental mode. There is the possibility to automatically create form "
- f"{Link("fields from annotations", to="#generating-form-fields")}, but it "
+ f"{Link('fields from annotations', to='#generating-form-fields')}, but it "
"is far from production-ready."
),
H2("Input Field"),
Paragraph(
- f"The {Code("InputField")} component is the most basic form field. It "
- f"is a wrapper around the {Code("input")} HTML element which also "
+ f"The {Code('InputField')} component is the most basic form field. It "
+ f"is a wrapper around the {Code('input')} HTML element which also "
"generates a label if not disabled. Here is what it looks like:"
),
InputField(
@@ -59,7 +59,7 @@ def forms(request: Request) -> Page:
),
Paragraph(
"You can also create the input field without the label by not passing "
- f"the {Code("label")} attribute:"
+ f"the {Code('label')} attribute:"
),
InputField(name="sample-input-field"),
CodeBlock(
@@ -74,8 +74,8 @@ def forms(request: Request) -> Page:
),
H2("Select Field"),
Paragraph(
- f"The {Code("SelectField")} component is a wrapper around the "
- f"{Code("select")} HTML element. It also generates a label if not "
+ f"The {Code('SelectField')} component is a wrapper around the "
+ f"{Code('select')} HTML element. It also generates a label if not "
"disabled. Here is what it looks like:"
),
SelectField(
@@ -101,8 +101,8 @@ def forms(request: Request) -> Page:
),
H2("Text Area"),
Paragraph(
- f"The {Code("TextAreaField")} component is a wrapper around the "
- f"{Code("textarea")} HTML element. It also generates a label if not "
+ f"The {Code('TextAreaField')} component is a wrapper around the "
+ f"{Code('textarea')} HTML element. It also generates a label if not "
"disabled. Here is what it looks like:"
),
TextAreaField(
@@ -126,7 +126,7 @@ def forms(request: Request) -> Page:
),
H2("Choices"),
Paragraph(
- f"The {Code("ChoiceField")} component is a wrapper around the "
+ f"The {Code('ChoiceField')} component is a wrapper around the "
f"{Code("")} HTML element. It also generates a label "
"if not disabled. Here is what it looks like:"
),
@@ -151,7 +151,7 @@ def forms(request: Request) -> Page:
),
H2("Form"),
Paragraph(
- f"The {Code("Form")} component is a wrapper around the {Code("form")} "
+ f"The {Code('Form')} component is a wrapper around the {Code('form')} "
"HTML element. Here is a sample form:"
),
Form(
@@ -188,9 +188,10 @@ def forms(request: Request) -> Page:
language="python",
),
Paragraph(
- f"We use the {Code("Cluster")} component to create a form with multiple "
- f"input fields and buttons. this component is described in the {Link(
- "Layouts section", to=request.url_for("catalog:layouts").path)}. "
+ f"We use the {Code('Cluster')} component to create a form with multiple "
+ f"input fields and buttons. this component is described in the {
+ Link('Layouts section', to=request.url_for('catalog:layouts').path)
+ }. "
"You can also have the input field and the button aligned horizontally "
"using this layout component:"
),
@@ -229,7 +230,7 @@ def forms(request: Request) -> Page:
Paragraph(
"In some cases, the attributes of a component or class-based endpoint "
"can be used to create form fields automatically using the "
- f"{Code("create_fields")} function. Here is an example:"
+ f"{Code('create_fields')} function. Here is an example:"
),
Form(
*create_fields(
@@ -253,9 +254,9 @@ class PersonAttrs(Attrs):
language="python",
),
Paragraph(
- f"The {Code("create_fields")} function generates form fields from "
+ f"The {Code('create_fields')} function generates form fields from "
"annotations. It generates only fields that are annotated with the "
- f"{Code("FieldMeta")} dataclass, which looks like this:"
+ f"{Code('FieldMeta')} dataclass, which looks like this:"
),
CodeBlock(
"""
@@ -270,7 +271,7 @@ class FieldMeta:
language="python",
),
Paragraph(
- f"The {Code("parser")} attribute validates and parses the field. Here is "
+ f"The {Code('parser')} attribute validates and parses the field. Here is "
"how you would use it:"
),
CodeBlock(
@@ -296,10 +297,13 @@ class CustomerAttrs(Attrs):
language="python",
),
Paragraph(
- f"Fields created with the {Code("create_fields")} function can be than "
- f"extracted from submitted form data using the {Link(
- "Parser class",
- to=f"{request.url_for("docs:web_framework").path}#parsers")}."
+ f"Fields created with the {Code('create_fields')} function can be than "
+ f"extracted from submitted form data using the {
+ Link(
+ 'Parser class',
+ to=f'{request.url_for("docs:web_framework").path}#parsers',
+ )
+ }."
),
request=request,
active_item="forms",
diff --git a/web/endpoints/catalog/index.py b/web/endpoints/catalog/index.py
index e7eeea1..bf6ffb1 100644
--- a/web/endpoints/catalog/index.py
+++ b/web/endpoints/catalog/index.py
@@ -15,7 +15,7 @@ def index(request: Request) -> Page:
return Page(
H1("Catalog"),
Paragraph(
- f"The {Code("ludic.catalog")} module is a collection of components "
+ f"The {Code('ludic.catalog')} module is a collection of components "
"designed to help build applications using the Ludic framework. It "
"serves as both a resource for building new web applications and also "
"as a showcase of ways to implement components."
@@ -23,14 +23,14 @@ def index(request: Request) -> Page:
Paragraph(
"Each item in the catalog is a reusable component that generates HTML "
"code and registers its own CSS styles.. The registered CSS are loaded "
- f"using the {Code("style.load()")} method, as detailed in the "
- f"{Link("Styles and Themes", to=request.url_path_for("docs:styles"))} "
+ f"using the {Code('style.load()')} method, as detailed in the "
+ f"{Link('Styles and Themes', to=request.url_path_for('docs:styles'))} "
"section of the documentation."
),
Paragraph(
- f"The catalog components are like {b("Lego pieces")} you can assemble "
- f"together to build interactive and beautiful {b("HTML documents")} "
- f"with {b("minimalistic")} approach:"
+ f"The catalog components are like {b('Lego pieces')} you can assemble "
+ f"together to build interactive and beautiful {b('HTML documents')} "
+ f"with {b('minimalistic')} approach:"
),
List(
Item(
@@ -41,13 +41,13 @@ def index(request: Request) -> Page:
"The generated CSS is simple, extensible, and easy to understand. "
"The layouts you can use for building your pages are responsive, "
"reusable, and robust. They are based on the amazing "
- f"{Link("Every Layout Book", to="https://every-layout.dev/")}."
+ f"{Link('Every Layout Book', to='https://every-layout.dev/')}."
),
),
H2("How Do You Use The Catalog?"),
Paragraph(
f"In order for everything to work correctly, the first thing you usually "
- f"need to do is to create a {Code("Page")} component. This component is "
+ f"need to do is to create a {Code('Page')} component. This component is "
"important for two reasons:"
),
List(
@@ -62,37 +62,37 @@ def index(request: Request) -> Page:
Message(
Title("How does CSS loading work?"),
f"The CSS styles for components are loaded when the component is imported "
- f"anywhere in your application. The {Code("style.load()")} method iterates "
+ f"anywhere in your application. The {Code('style.load()')} method iterates "
"over all imported components and checks if the components have any styles "
"defined.",
),
Paragraph(
"All rendered HTML documents will have this component as a base similar to "
- f"how all HTML pages in template engines like Jinja2 use the {i("base")} "
+ f"how all HTML pages in template engines like Jinja2 use the {i('base')} "
"template."
),
Message(
Title(
- f"How does a {Code("Page")} component differ from a regular component?"
+ f"How does a {Code('Page')} component differ from a regular component?"
),
"The only difference is that it renders as a valid HTML5 document starting "
- f"with the {Code("")} declaration. You usually need only "
- f"one {Code("Page")} component in the whole application.",
+ f"with the {Code('')} declaration. You usually need only "
+ f"one {Code('Page')} component in the whole application.",
),
Paragraph(
- f"After you are done with setting up your {Code("Page")} component, you "
+ f"After you are done with setting up your {Code('Page')} component, you "
"can use it along with all the other components in the catalog."
),
H3("HtmlPage Component"),
Paragraph(
"This component has already been mentioned throughout the documentation "
- f"and can be used to create your {Code("Page")} component. The "
- f"{Code("HtmlPage")} component is just for convenience so that you can "
+ f"and can be used to create your {Code('Page')} component. The "
+ f"{Code('HtmlPage')} component is just for convenience so that you can "
"quickly start and not worry about how to load e.g. CSS styles or HTMX. "
),
Paragraph(
- f"Here is how you would use the {Code("HtmlPage")} component to "
- f"create your own {Code("Page")} component:"
+ f"Here is how you would use the {Code('HtmlPage')} component to "
+ f"create your own {Code('Page')} component:"
),
CodeBlock(
"""
@@ -143,7 +143,7 @@ def render(self) -> HtmlPage:
Item(Code('htmx_version="latest"')),
),
Paragraph(
- f"Now that you prepared your {Code("Page")} component, you can use it in "
+ f"Now that you prepared your {Code('Page')} component, you can use it in "
"your code like here:"
),
CodeBlock(
@@ -171,9 +171,9 @@ def clicked(request: Request) -> Paragraph:
language="python",
),
Paragraph(
- f"The {Code("HtmlPage")} component comes also with default "
- f"{Code("styles")}. In fact, the following list of styles are "
- f"auto-loaded whenever you import anything from the {Code("ludic.catalog")}"
+ f"The {Code('HtmlPage')} component comes also with default "
+ f"{Code('styles')}. In fact, the following list of styles are "
+ f"auto-loaded whenever you import anything from the {Code('ludic.catalog')}"
" module:"
),
List(
diff --git a/web/endpoints/catalog/layouts.py b/web/endpoints/catalog/layouts.py
index ef2bfbf..305441e 100644
--- a/web/endpoints/catalog/layouts.py
+++ b/web/endpoints/catalog/layouts.py
@@ -27,7 +27,7 @@ def layouts(request: Request) -> Page:
H1("Layouts"),
Paragraph(
"Layouts create a flexible structure for your user interface. "
- f"The layouts in this module are based on the {b("Every Layout Book")}. "
+ f"The layouts in this module are based on the {b('Every Layout Book')}. "
"If you haven't read the book, go read it now: "
),
List(Item(Link("Every Layout Book", to="https://every-layout.dev/"))),
@@ -37,7 +37,7 @@ def layouts(request: Request) -> Page:
"The layouts can be combined together."
),
Paragraph(
- f"All layouts are located in the {Code("ludic.catalog.layouts")} module."
+ f"All layouts are located in the {Code('ludic.catalog.layouts')} module."
),
Message(
Title("Viewing this page on mobile devices"),
@@ -51,7 +51,7 @@ def layouts(request: Request) -> Page:
"you can easily combine to create responsive, readable, and maintainable "
"user interfaces. Instead of starting from scratch with basic HTML "
"elements and manually writing CSS, you use these layouts as your "
- f"{b("foundational building blocks")}. This approach allows you to compose "
+ f"{b('foundational building blocks')}. This approach allows you to compose "
"and arrange them in various ways to design your desired user interface, "
"making your code more organized and easier to manage."
),
@@ -59,7 +59,7 @@ def layouts(request: Request) -> Page:
Paragraph(
"When writing CSS, you might be tempted to apply e.g. specific spacing, "
"colors, or font styles to an HTML element like a button. The idea of "
- f"using the layout classes here is to define {b("context")} which "
+ f"using the layout classes here is to define {b('context')} which "
"determines how an HTML element should be displayed. So for example, we "
"might want to have a couple of buttons on one line, so we wrap them in "
"a Cluster class which inserts a margin between all its children and puts "
diff --git a/web/endpoints/catalog/messages.py b/web/endpoints/catalog/messages.py
index 4df8ae8..6daf84c 100644
--- a/web/endpoints/catalog/messages.py
+++ b/web/endpoints/catalog/messages.py
@@ -17,7 +17,7 @@ def messages(request: Request) -> Page:
return Page(
H1("Messages"),
Paragraph(
- f"The module {Code("ludic.catalog.messages")} contains the following "
+ f"The module {Code('ludic.catalog.messages')} contains the following "
"components:"
),
Message(
@@ -70,7 +70,7 @@ def messages(request: Request) -> Page:
language="python",
),
Paragraph(
- f"Note that you don't need to specify the {Code("Title")} component. "
+ f"Note that you don't need to specify the {Code('Title')} component. "
"Here is how the message renders without the title:"
),
Message(
diff --git a/web/endpoints/catalog/tables.py b/web/endpoints/catalog/tables.py
index 8da16d5..9580c7b 100644
--- a/web/endpoints/catalog/tables.py
+++ b/web/endpoints/catalog/tables.py
@@ -38,15 +38,15 @@ def tables(request: Request) -> Page:
return Page(
H1("Tables"),
Paragraph(
- f"These components located in {Code("ludic.catalog.tables")} are in an "
+ f"These components located in {Code('ludic.catalog.tables')} are in an "
"experimental mode. There is the possibility to automatically create "
"tables even containing form fields and actions from annotations, but "
"it is far from production-ready."
),
H2("Creating a Table"),
Paragraph(
- f"The {Code("Table")} component accepts a {Code("TableHead")} as the first "
- f"item and any number of {Code("TableRow")} items."
+ f"The {Code('Table')} component accepts a {Code('TableHead')} as the first "
+ f"item and any number of {Code('TableRow')} items."
),
Table(
TableHead("First Name", "Last Name", "Age"),
@@ -91,7 +91,7 @@ def tables(request: Request) -> Page:
),
H2("Generating Table Rows"),
Paragraph(
- f"The {Code("create_rows")} function can be used to generate rows in the "
+ f"The {Code('create_rows')} function can be used to generate rows in the "
"table based on given specification. Here is an example:"
),
CodeBlock(
@@ -125,7 +125,7 @@ class PersonAttrs(Attrs):
Paragraph(
"There is also an experimental support for tables containing form fields."
"The way it works is that you wrap your table in a form and use the "
- f"{Code("create_rows")} function to generate the rows. Here is an example:"
+ f"{Code('create_rows')} function to generate the rows. Here is an example:"
),
Form(
Table(*create_rows(contacts_attrs_list, spec=SampleContactAttrs)),
@@ -161,10 +161,12 @@ class ContactAttrs(Attrs):
),
Paragraph(
"The role of the identifier column is to be able to parse the form data "
- f"using the {Code("ListParser")} function as documented in the {Link(
- "Parsers section",
- to=f"{request.url_for("docs:web_framework").path}#parsing-collections"
- )} of the documentation."
+ f"using the {Code('ListParser')} function as documented in the {
+ Link(
+ 'Parsers section',
+ to=f'{request.url_for("docs:web_framework").path}#parsing-collections',
+ )
+ } of the documentation."
),
request=request,
active_item="tables",
diff --git a/web/endpoints/catalog/typography.py b/web/endpoints/catalog/typography.py
index 32f2d4e..b691b18 100644
--- a/web/endpoints/catalog/typography.py
+++ b/web/endpoints/catalog/typography.py
@@ -11,13 +11,14 @@ def typography(request: Request) -> Page:
return Page(
H1("Typography"),
Paragraph(
- f"The module {Code("ludic.catalog.typography")} contains the following "
+ f"The module {Code('ludic.catalog.typography')} contains the following "
"components:"
),
H4("Link"),
Paragraph(
- f"This text contains a {Link(
- "link", to=str(request.url_for("catalog:index")))}.",
+ f"This text contains a {
+ Link('link', to=str(request.url_for('catalog:index')))
+ }.",
),
CodeBlock(
"""
@@ -39,7 +40,7 @@ def typography(request: Request) -> Page:
language="python",
),
H4("Code"),
- Paragraph(f"This text contains code: {Code("let mut x = 0;")}"),
+ Paragraph(f"This text contains code: {Code('let mut x = 0;')}"),
CodeBlock(
"""
from ludic.catalog.typography import Code
@@ -134,7 +135,7 @@ def typography(request: Request) -> Page:
),
H2("Headers"),
Paragraph(
- f"The module {Code("ludic.catalog.headers")} contains components "
+ f"The module {Code('ludic.catalog.headers')} contains components "
"rendering as HTML headers (h1-h4)."
),
H1("H1", anchor=False),
@@ -153,7 +154,7 @@ def typography(request: Request) -> Page:
language="python",
),
Paragraph(
- f"The module also contains the {Code("Anchor")} component, which can be "
+ f"The module also contains the {Code('Anchor')} component, which can be "
"used to create an anchor link next to the header."
),
H4("H4 With Anchor", anchor=Anchor("#", target="h4-with-anchor")),
@@ -167,7 +168,7 @@ def typography(request: Request) -> Page:
),
Paragraph(
"It is possible to generate the anchor automatically using the "
- f"{Code("anchor=True")} attribute:"
+ f"{Code('anchor=True')} attribute:"
),
H3("H3 With Anchor", anchor=True),
CodeBlock(
diff --git a/web/endpoints/docs/components.py b/web/endpoints/docs/components.py
index 370b142..756d012 100644
--- a/web/endpoints/docs/components.py
+++ b/web/endpoints/docs/components.py
@@ -19,26 +19,26 @@ def components(request: Request) -> Page:
H2("Key Concepts"),
List(
Item(
- f"{b("Components")}: a component is a reusable chunk of code that "
+ f"{b('Components')}: a component is a reusable chunk of code that "
"defines a piece of your user interface. Think of it like a blueprint "
"for an HTML element, but more powerful."
),
Item(
- f"{b("Elements")}: these represent the individual HTML tags (like "
- f"{Code("")}, {Code("
')}, etc.) that make up "
"the structure of your page."
),
Item(
- f"{b("Attributes")}: These help define the properties on your "
+ f"{b('Attributes')}: These help define the properties on your "
"components and elements. They let you modify things like a link's "
"destination, text color, or an element's size."
),
Item(
- f"{b("Hierarchy")}: Components can contain other components or "
+ f"{b('Hierarchy')}: Components can contain other components or "
"elements, creating a tree-like structure."
),
Item(
- f"{b("Types")}: A safety net to help you write correct code, "
+ f"{b('Types')}: A safety net to help you write correct code, "
"preventing errors just like making sure LEGO pieces fit together "
"properly."
),
@@ -46,18 +46,18 @@ def components(request: Request) -> Page:
H2("Types of Components"),
List(
Item(
- f"{b("Regular")}: These are flexible, letting you have multiple "
+ f"{b('Regular')}: These are flexible, letting you have multiple "
"children of any type."
),
Item(
- f"{b("Strict")}: Perfect for when you need precise control over the "
+ f"{b('Strict')}: Perfect for when you need precise control over the "
"structure of your component – like a table where you must have a head "
"and a body."
),
),
H2("Regular Components"),
Paragraph(
- f"Let's break down a simplified version of the {Code("Link")} component:"
+ f"Let's break down a simplified version of the {Code('Link')} component:"
),
CodeBlock(
"""
@@ -80,27 +80,27 @@ def render(self):
),
List(
Item(
- f"{i("HTML Rendering")}: This component renders as the following HTML "
+ f"{i('HTML Rendering')}: This component renders as the following HTML "
f"element:",
List(Item(Code('...'))),
),
Item(
- f"{i("Type Hints")}: {Code("Component[str, LinkAttrs]")} provides type "
+ f"{i('Type Hints')}: {Code('Component[str, LinkAttrs]')} provides type "
f"safety:",
List(
Item(
- f"{i("str")}: Enforces that all children of the component "
+ f"{i('str')}: Enforces that all children of the component "
"must be strings"
),
Item(
- f"{i("LinkAttrs")}: Ensures the required to attribute is "
+ f"{i('LinkAttrs')}: Ensures the required to attribute is "
"present"
),
),
),
Item(
- f"{i("Attributes")}: {Code("LinkAttrs")} inherits from "
- f"{Code("Attrs")}, which is a {Code("TypedDict")} "
+ f"{i('Attributes')}: {Code('LinkAttrs')} inherits from "
+ f"{Code('Attrs')}, which is a {Code('TypedDict')} "
f"(a dictionary with defined types for its keys)",
),
),
@@ -115,14 +115,14 @@ def render(self):
"The current definition doesn't strictly enforce a single child. "
"This means you could technically pass multiple strings "
f"({Code('Link("a", "b")')}). To create a stricter component, inherit "
- f"from {Code("ComponentStrict")}: This subclass of Component allows for "
+ f"from {Code('ComponentStrict')}: This subclass of Component allows for "
"finer control over children. More about this in the next section."
),
H2("Strict Components"),
Paragraph(
"Strict components offer more precise control over the types and "
"structures of their children compared to regular components. Let's "
- f"illustrate this with a simplified {Code("Table")} component:"
+ f"illustrate this with a simplified {Code('Table')} component:"
),
CodeBlock(
"""
@@ -153,29 +153,29 @@ def render(self) -> table:
b("Explanation"),
List(
Item(
- f"{i("Strictness")}: The {Code("ComponentStrict")} class allows you to "
+ f"{i('Strictness')}: The {Code('ComponentStrict')} class allows you to "
"enforce the exact types and order of children."
),
Item(
- f"{i("Table Structure")}:",
+ f"{i('Table Structure')}:",
List(
Item(
- f"{Code("Table")}: Expects precisely two children: a "
- f"{Code("TableHead")} followed by a {Code("TableBody")}."
+ f"{Code('Table')}: Expects precisely two children: a "
+ f"{Code('TableHead')} followed by a {Code('TableBody')}."
),
Item(
- f"{Code("TableHead")}: Accepts only a single {Code("tr")} "
+ f"{Code('TableHead')}: Accepts only a single {Code('tr')} "
"(table row) element as its child."
),
Item(
- f"{Code("TableBody")}: Accepts a variable number of "
- f"{Code("tr")} elements as children."
+ f"{Code('TableBody')}: Accepts a variable number of "
+ f"{Code('tr')} elements as children."
),
),
),
Item(
- f"{i("Type Hints")}: The {Code("*tuple[tr, ...]")} syntax indicates "
- f"that {Code("TableBody")} accepts zero or more tr elements."
+ f"{i('Type Hints')}: The {Code('*tuple[tr, ...]')} syntax indicates "
+ f"that {Code('TableBody')} accepts zero or more tr elements."
),
),
b("Valid Usage (Passes Type Checking)"),
@@ -191,18 +191,18 @@ def render(self) -> table:
b("Key Benefits"),
List(
Item(
- f"{i("Enforce Structure")}: Prevent incorrect usage that could break "
+ f"{i('Enforce Structure')}: Prevent incorrect usage that could break "
"your component's layout or functionality."
),
Item(
- f"{i("Type Safety")}: Static type checkers ensure you're building "
+ f"{i('Type Safety')}: Static type checkers ensure you're building "
"valid component hierarchies."
),
),
H2("Attributes"),
Paragraph(
"To ensure type safety and clarity, define your component attributes using "
- f"a subclass of the {Code("Attrs")} class. Here's how:"
+ f"a subclass of the {Code('Attrs')} class. Here's how:"
),
CodeBlock(
"""
@@ -216,13 +216,13 @@ class PersonAttrs(Attrs):
""",
language="python",
),
- b(f"Understanding {Code("Attrs")} and {Code("TypedDict")}"),
+ b(f"Understanding {Code('Attrs')} and {Code('TypedDict')}"),
List(
Item(
- f"The {Code("Attrs")} class is built upon Python's {Code("TypedDict")} "
- f"concept (see {Link(
- "PEP-589", to="https://peps.python.org/pep-0589/"
- )}) for details). This provides type hints for dictionary-like data "
+ f"The {Code('Attrs')} class is built upon Python's {Code('TypedDict')} "
+ f"concept (see {
+ Link('PEP-589', to='https://peps.python.org/pep-0589/')
+ }) for details). This provides type hints for dictionary-like data "
"structures."
),
),
@@ -230,7 +230,7 @@ class PersonAttrs(Attrs):
Paragraph(
"In the above case, all attributes except for {Code('is_active')} are "
"required. If you want to make all attributes NOT required by default, "
- f"you can pass the {Code("total=False")} keyword argument to the class "
+ f"you can pass the {Code('total=False')} keyword argument to the class "
"definition:"
),
CodeBlock(
@@ -246,20 +246,20 @@ class PersonAttrs(Attrs, total=False):
language="python",
),
Paragraph(
- f"In this case, all attributes are optional except for the {Code("id")} "
+ f"In this case, all attributes are optional except for the {Code('id')} "
"attribute."
),
Message(
Title(
- f"The {Code("Attrs")} declaration is an information for type checkers"
+ f"The {Code('Attrs')} declaration is an information for type checkers"
),
- f"The {Code("Attrs")} class just provides typing information for static "
+ f"The {Code('Attrs')} class just provides typing information for static "
"type checkers. Your code will work even if you pass key-word arguments to "
"components without declaring them first.",
),
Paragraph(
"All attributes can also subclass from other classes, for example, you can "
- f"extend the attributes for the {Code("