mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
docs update
This commit is contained in:
@@ -100,7 +100,7 @@ With a header and a footer widget the DOM looks like this:
|
||||
--8<-- "docs/images/dom2.excalidraw.svg"
|
||||
</div>
|
||||
|
||||
!!! note
|
||||
!!! note "What we didn't show"
|
||||
|
||||
We've simplified the above example somewhat. Both the Header and Footer widgets contain children of their own. When building an app with pre-built widgets you rarely need to know how they are constructed unless you plan on changing the styles of individual components.
|
||||
|
||||
@@ -108,17 +108,17 @@ Both Header and Footer are children of the Screen object.
|
||||
|
||||
To further explore the DOM, we're going to build a simple dialog with a question and two buttons. To do this we're going to import and use a few more builtin widgets:
|
||||
|
||||
- `textual.layout.Container` For our top-level dialog.
|
||||
- `textual.layout.Horizontal` To arrange widgets left to right.
|
||||
- `textual.widgets.Static` For simple content.
|
||||
- `textual.widgets.Button` For a clickable button.
|
||||
- [`textual.containers.Container`][textual.containers.Container] For our top-level dialog.
|
||||
- [`textual.containers.Horizontal`][textual.containers.Horizontal] To arrange widgets left to right.
|
||||
- [`textual.widgets.Static`][textual.widgets.Static] For simple content.
|
||||
- [`textual.widgets.Button`][textual.widgets.Button] For a clickable button.
|
||||
|
||||
|
||||
```python hl_lines="12 13 14 15 16 17 18 19 20" title="dom3.py"
|
||||
--8<-- "docs/examples/guide/dom3.py"
|
||||
```
|
||||
|
||||
We've added a Container to our DOM which (as the name suggests) is a container for other widgets. The container has a number of other widgets passed as positional arguments which will be added as the children of the container. Not all widgets accept child widgets in this way. A Button widget doesn't require any children, for example.
|
||||
We've added a Container to our DOM which (as the name suggests) contains other widgets. The container has a number of other widgets passed as positional arguments which will be added as the children of the container. Not all widgets accept child widgets in this way. A Button widget doesn't require any children, for example.
|
||||
|
||||
Here's the DOM created by the above code:
|
||||
|
||||
@@ -139,7 +139,7 @@ You may recognize some elements in the above screenshot, but it doesn't quite lo
|
||||
To add a stylesheet set the `CSS_PATH` classvar to a relative path:
|
||||
|
||||
|
||||
!!! note
|
||||
!!! note "What are TCSS files?"
|
||||
|
||||
Textual CSS files are typically given the extension `.tcss` to differentiate them from browser CSS (`.css`).
|
||||
|
||||
@@ -223,7 +223,7 @@ Static {
|
||||
}
|
||||
```
|
||||
|
||||
!!! note
|
||||
!!! note "This is different to browser CSS"
|
||||
|
||||
The fact that the type selector matches base classes is a departure from browser CSS which doesn't have the same concept.
|
||||
|
||||
@@ -312,6 +312,18 @@ For example, the following will draw a red outline around all widgets:
|
||||
}
|
||||
```
|
||||
|
||||
While it is rare to need to style all widgets, you can combine the universal selector with a parent, to select all children of that parent.
|
||||
|
||||
For instance, here's how we would make all children of a `VerticalScroll` have a red background:
|
||||
|
||||
```css
|
||||
VerticalScroll * {
|
||||
background: red;
|
||||
}
|
||||
```
|
||||
|
||||
See [Combinators](#combinators) for more details on combining selectors like this.
|
||||
|
||||
### Pseudo classes
|
||||
|
||||
Pseudo classes can be used to match widgets in a particular state. Pseudo classes are set automatically by Textual. For instance, you might want a button to have a green background when the mouse cursor moves over it. We can do this with the `:hover` pseudo selector.
|
||||
@@ -403,7 +415,7 @@ It is possible that several selectors match a given widget. If the same style is
|
||||
|
||||
The specificity rules are usually enough to fix any conflicts in your stylesheets. There is one last way of resolving conflicting selectors which applies to individual rules. If you add the text `!important` to the end of a rule then it will "win" regardless of the specificity.
|
||||
|
||||
!!! warning
|
||||
!!! warning "If everything is Important, nothing is Important"
|
||||
|
||||
Use `!important` sparingly (if at all) as it can make it difficult to modify your CSS in the future.
|
||||
|
||||
@@ -445,7 +457,7 @@ This will be translated into:
|
||||
Variables allow us to define reusable styling in a single place.
|
||||
If we decide we want to change some aspect of our design in the future, we only have to update a single variable.
|
||||
|
||||
!!! note
|
||||
!!! note "Where can variables be used?"
|
||||
|
||||
Variables can only be used in the _values_ of a CSS declaration. You cannot, for example, refer to a variable inside a selector.
|
||||
|
||||
@@ -576,3 +588,6 @@ If we were to add other selectors for additional screens or widgets, it would be
|
||||
### Why use nesting?
|
||||
|
||||
There is no requirement to use nested CSS, but it can help to group related rule sets together (which makes it easier to edit). Nested CSS can also help you avoid some repetition in your selectors, i.e. in the nested CSS we only need to type `#questions` once, rather than four times in the non-nested CSS.
|
||||
|
||||
Nesting CSS will also make rules that are *more* specific.
|
||||
This is useful if you find your rules are applying to widgets that you didn't intend.
|
||||
|
||||
@@ -34,9 +34,6 @@ When you call [App.run()][textual.app.App.run] Textual puts the terminal into a
|
||||
|
||||
If you hit ++ctrl+q++ Textual will exit application mode and return you to the command prompt. Any content you had in the terminal prior to application mode will be restored.
|
||||
|
||||
!!! tip
|
||||
|
||||
A side effect of application mode is that you may no longer be able to select and copy text in the usual way. Terminals typically offer a way to bypass this limit with a key modifier. On iTerm you can select text if you hold the ++option++ key. See the documentation for your terminal software for how to select text in application mode.
|
||||
|
||||
#### Run inline
|
||||
|
||||
@@ -65,14 +62,10 @@ We recommend the default behavior for full-screen apps, but you may want to pres
|
||||
|
||||
## Events
|
||||
|
||||
Textual has an event system you can use to respond to key presses, mouse actions, and internal state changes. Event handlers are methods prefixed with `on_` followed by the name of the event.
|
||||
Textual has an [event system](./events.md) you can use to respond to key presses, mouse actions, and internal state changes. Event handlers are methods prefixed with `on_` followed by the name of the event.
|
||||
|
||||
One such event is the *mount* event which is sent to an application after it enters application mode. You can respond to this event by defining a method called `on_mount`.
|
||||
|
||||
!!! info
|
||||
|
||||
You may have noticed we use the term "send" and "sent" in relation to event handler methods in preference to "calling". This is because Textual uses a message passing system where events are passed (or *sent*) between components. See [events](./events.md) for details.
|
||||
|
||||
Another such event is the *key* event which is sent when the user presses a key. The following example contains handlers for both those events:
|
||||
|
||||
```python title="event01.py"
|
||||
@@ -84,13 +77,12 @@ The `on_mount` handler sets the `self.screen.styles.background` attribute to `"d
|
||||
```{.textual path="docs/examples/app/event01.py" hl_lines="23-25"}
|
||||
```
|
||||
|
||||
The key event handler (`on_key`) has an `event` parameter which will receive a [Key][textual.events.Key] instance. Every event has an associated event object which will be passed to the handler method if it is present in the method's parameter list.
|
||||
When you press a key, the key event handler (`on_key`) which will receive a [Key][textual.events.Key] instance.
|
||||
If you don't require the event in your handler, you can omit it.
|
||||
|
||||
!!! note
|
||||
|
||||
It is unusual (but not unprecedented) for a method's parameters to affect how it is called. Textual accomplishes this by inspecting the method prior to calling it.
|
||||
|
||||
Some events contain additional information you can inspect in the handler. The [Key][textual.events.Key] event has a `key` attribute which is the name of the key that was pressed. The `on_key` method above uses this attribute to change the background color if any of the keys from ++0++ to ++9++ are pressed.
|
||||
Events may contain additional information which you can inspect in the handler.
|
||||
In the case of the [Key][textual.events.Key] event, there is a `key` attribute which is the name of the key that was pressed.
|
||||
The `on_key` method above uses this attribute to change the background color if any of the keys from ++0++ to ++9++ are pressed.
|
||||
|
||||
### Async events
|
||||
|
||||
@@ -224,7 +216,7 @@ You may have noticed that we subclassed `App[str]` rather than the usual `App`.
|
||||
|
||||
The addition of `[str]` tells mypy that `run()` is expected to return a string. It may also return `None` if [App.exit()][textual.app.App.exit] is called without a return value, so the return type of `run` will be `str | None`. Replace the `str` in `[str]` with the type of the value you intend to call the exit method with.
|
||||
|
||||
!!! note
|
||||
!!! note "Typing in Textual"
|
||||
|
||||
Type annotations are entirely optional (but recommended) with Textual.
|
||||
|
||||
@@ -317,7 +309,7 @@ For example:
|
||||
|
||||
## CSS
|
||||
|
||||
Textual apps can reference [CSS](CSS.md) files which define how your app and widgets will look, while keeping your Python code free of display related code (which tends to be messy).
|
||||
Textual apps can reference [CSS](CSS.md) files which define how your app and widgets will look, while keeping your project free of messy display related code.
|
||||
|
||||
!!! info
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ This code produces the following result.
|
||||
```{.textual path="docs/examples/guide/styles/dimensions01.py"}
|
||||
```
|
||||
|
||||
Note how the text wraps in the widget, and is cropped because it doesn't fit in the space provided.
|
||||
Note how the text wraps, but doesn't fit in the 10 lines provided, resulting in the last line being omitted entirely.
|
||||
|
||||
#### Auto dimensions
|
||||
|
||||
@@ -189,7 +189,7 @@ With the width set to `"50%"` and the height set to `"80%"`, the widget will kee
|
||||
|
||||
Percentage units can be problematic for some relative values. For instance, if we want to divide the screen into thirds, we would have to set a dimension to `33.3333333333%` which is awkward. Textual supports `fr` units which are often better than percentage-based units for these situations.
|
||||
|
||||
When specifying `fr` units for a given dimension, Textual will divide the available space by the sum of the `fr` units on that dimension. That space will then be divided amongst the widgets as a proportion of their individual `fr` values.
|
||||
When specifying `fr` units for a given dimension, Textual will divide the available space by the sum of the `fr` units for that dimension. That space is then assigned according to each widget's `fr` values.
|
||||
|
||||
Let's look at an example. We will create two widgets, one with a height of `"2fr"` and one with a height of `"1fr"`.
|
||||
|
||||
@@ -197,14 +197,18 @@ Let's look at an example. We will create two widgets, one with a height of `"2fr
|
||||
--8<-- "docs/examples/guide/styles/dimensions04.py"
|
||||
```
|
||||
|
||||
The total `fr` units for height is 3. The first widget will have a screen height of two thirds because its height style is set to `2fr`. The second widget's height style is `1fr` so its screen height will be one third. Here's what that looks like.
|
||||
The total `fr` units for height is 3.
|
||||
The first widget has a height ot `2fr`, which results in the height being two thirds of the total height.
|
||||
The second widget has a height of `1fr` which makes it take up the remaining third of the height.
|
||||
Here's what that looks like.
|
||||
|
||||
```{.textual path="docs/examples/guide/styles/dimensions04.py"}
|
||||
```
|
||||
|
||||
### Maximum and minimums
|
||||
|
||||
The same units may also be used to set limits on a dimension. The following styles set minimum and maximum sizes and can accept any of the values used in width and height.
|
||||
The same units may also be used to set limits on a dimension.
|
||||
The following styles set minimum and maximum sizes and can accept any of the values used in width and height.
|
||||
|
||||
- [min-width](../styles/min_width.md) sets a minimum width.
|
||||
- [max-width](../styles/max_width.md) sets a maximum width.
|
||||
@@ -345,12 +349,12 @@ Notice how each widget has an additional two rows and columns around the border.
|
||||
```{.textual path="docs/examples/guide/styles/margin01.py"}
|
||||
```
|
||||
|
||||
!!! note
|
||||
!!! note "Margins overlap"
|
||||
|
||||
In the above example both widgets have a margin of 2, but there are only 2 lines of space between the widgets. This is because margins of consecutive widgets *overlap*. In other words when there are two widgets next to each other Textual picks the greater of the two margins.
|
||||
|
||||
## More styles
|
||||
|
||||
We've covered the most fundamental styles used by Textual apps, but there are many more which you can use to customize many aspects of how your app looks. See the [Styles reference](../styles/index.md) for a comprehensive list.
|
||||
We've covered some fundamental styles used by Textual apps, but there are many more which you can use to customize all aspects of how your app looks. See the [Styles reference](../styles/index.md) for a comprehensive list.
|
||||
|
||||
In the next chapter we will discuss Textual CSS which is a powerful way of applying styles to widgets that keeps your code free of style attributes.
|
||||
|
||||
@@ -10,13 +10,13 @@ nav:
|
||||
- "guide/app.md"
|
||||
- "guide/styles.md"
|
||||
- "guide/CSS.md"
|
||||
- "guide/design.md"
|
||||
- "guide/queries.md"
|
||||
- "guide/layout.md"
|
||||
- "guide/events.md"
|
||||
- "guide/input.md"
|
||||
- "guide/actions.md"
|
||||
- "guide/reactivity.md"
|
||||
- "guide/design.md"
|
||||
- "guide/widgets.md"
|
||||
- "guide/content.md"
|
||||
- "guide/animation.md"
|
||||
|
||||
@@ -85,6 +85,7 @@ class ScrollableContainer(Widget, can_focus=True, inherit_bindings=False):
|
||||
can_maximize: bool | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Construct a scrollable container.
|
||||
|
||||
Args:
|
||||
*children: Child widgets.
|
||||
@@ -242,7 +243,7 @@ class Grid(Widget, inherit_bindings=False):
|
||||
|
||||
|
||||
class ItemGrid(Widget, inherit_bindings=False):
|
||||
"""A container with grid layout."""
|
||||
"""A container with grid layout and automatic columns."""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
ItemGrid {
|
||||
@@ -268,6 +269,7 @@ class ItemGrid(Widget, inherit_bindings=False):
|
||||
regular: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
Construct a ItemGrid.
|
||||
|
||||
Args:
|
||||
*children: Child widgets.
|
||||
|
||||
Reference in New Issue
Block a user