diff --git a/CHANGELOG.md b/CHANGELOG.md index 440cb162c8..58377cf257 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [0.4.0] - Unreleased +## [0.4.0] - 2022-11-08 ### Changed diff --git a/docs/blog/images/faster-updates.excalidraw.svg b/docs/blog/images/faster-updates.excalidraw.svg new file mode 100644 index 0000000000..18340ee26a --- /dev/null +++ b/docs/blog/images/faster-updates.excalidraw.svg @@ -0,0 +1,16 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nN2ca3Oa3Fx1MDAxNsff91NkPG8r3fdLZ86cybW5t401SXPmmVx1MDAwZUFUXCKK4WIunX73Z0FsXHUwMDAwI2pcdTAwMTKDTPLCKlx1MDAxYvZebNaP/1prQ39/WFurhXdDu/Z5rWbfWqbrtHzzpvYx3j6y/cDxXHUwMDA20ESS34FcdTAwMTf5VrJnN1xmh8HnT5/6pt+zw6FrWrYxcoLIdIMwajmeYXn9T05o94P/xZ/HZt/+79Drt0LfSFx1MDAwN6nbLSf0/IexbNfu24MwgN7/XHUwMDBmv9fWfiefXHUwMDE563zbXG7NQce1k1x1MDAwM5Km1ECK1eTWY2+QXHUwMDE4SzDDVFx1MDAxMk7Q41x1MDAxZU6wXHUwMDA144V2XHUwMDBimttgs522xJtq55fW8dVgOzo971xuWd857UaDzct02Lbjuo3wzn2YXG7T6kZ+xqgg9L2efea0wi6044ntj8dcdTAwMDVcdTAwMWXMQnqU70Wd7sBcdTAwMGWC3DHe0LSc8C7ehlLzXHUwMDFmZuHzWrrlXHUwMDE2filuKClcdTAwMTVcdTAwMTVCYc6kXHUwMDE0j63J8ZxcdTAwMWGEU41cdTAwMDThXGL+Ju3a9FxcuFx1MDAxNGDXf6hgbUumll2aVq9cdTAwMDPmXHJa6T6EqEtbKJXudfP3fJkyiJSUUclcdTAwMWZcdTAwMWK7ttPphtDKkKGlXCJgI5KYXHUwMDExRVMr7ORqxC2USMZcdTAwMWVcdTAwMWLioYd7rcQx/pmczK7pXHUwMDBmx5NWXHUwMDBi4lx1MDAxZlx1MDAxObNji7cnvSrrWZlcdTAwMGJ+2T5qXHUwMDFjOMdcciFcdTAwMWPinp9uXHUwMDFmXHUwMDA218HPx75yblx1MDAxONq3Ye2x4c/H6d3m9v646IBpt+Nv6Vx0R8OW+eCwWFxiqWGKJaY09Vx1MDAwMNdcdTAwMTn0oHFcdTAwMTC5brrNs3qpj3/I2PtMuDQthotKXHUwMDA03pa5YPPgut9ccr5aR0PyvVlf92+PLbp/9l1UXHUwMDFkrjp4q0GRXHUwMDE2XHUwMDA0cy01opzk8FwiXGJcdTAwMWKEUnBuJqTChFx1MDAxN+LF27Rlsdl42YJphabhRVxiM4RmkjMmgFx1MDAxZq5ewFx1MDAxONxcdTAwMGaVwHBcdTAwMDaqXFzIml/I/p55MrpAw9b1tT/sbl37J29cdNn0XHUwMDAxn1x1MDAwM1x1MDAxOUwkUrxcdTAwMTTIXHUwMDE4xkWQYSm4RIhxsTBkw1x1MDAxZt++7l1cdTAwMWW1aGRcdTAwMWTgId9wej/vulWHjFx0XHUwMDBljGFcdTAwMDJcdTAwMTOviKSgXCJcdTAwMTNcdTAwMTImXGbMlVx1MDAxNFx1MDAxOCeuzYohW6mGYaQg2lx1MDAxMFx1MDAxNJNy+dq17qXd22t2b2lvyLqX9uHoXHUwMDFifku+plx1MDAwZlhRXHUwMDExY1pcdTAwMTbxJZhcIkhgtLiG3e2qKPq1dVx1MDAxZlx1MDAxYzXNkfn91t05cdpVx4tQaVx1MDAwMFVcdTAwMTju/pJzzSfo0spA0FwiXHUwMDE555RLnLnZVE/CXGLinCnKsChcdTAwMTexg63v6Ng+6nxcdTAwMGbCbvO62d7mqH/2lohNXHUwMDFmcHWI5ezMJoikXGIuTFx1MDAxOIeQnujFxWt2oFBRuupCXHUwMDE4TIBzM1xuai2QyONFkDZcYokjyPiCKKqXXHUwMDExIT6FKyOZjzRlg9ExPlx1MDAwMJVcdTAwMTBYv4VCLTOaSi+5N1xiXHUwMDFizn2ScaDc1lx1MDAxZLPvuHe5q5b4aOxGyfjZeVxmbFx1MDAxODNxSpXbe911OrFcdTAwMTfXLDhcdTAwMGLbzzl46Fim+7hD32m1svpigVx0JvTp7y2S23i+03FcdTAwMDam+yNv4YuIK6x3MKmpQGRxMZud/FZcdTAwMTQ3TJmBsODgUFxcQFx1MDAwMqry+Vx1MDAxOFx1MDAxNpCPMVxu07BENXuKWyZcdTAwMGKcgVx1MDAxYqaEXHUwMDBirbF8XHUwMDAztVrmnf91uJ35Tsm0zSnTTdL2YOCLYCvOzTjHXHUwMDFhJluphXGbXHUwMDFkQ1RcdTAwMTQ3iqnBXHUwMDE1Y5prXHUwMDA0mZGarH5cYlx1MDAwM0muYFx1MDAxZYA1ls18ViFuXHUwMDEwNCrMdbniVjJtK1x1MDAxMLc5SU8p4iYgZ6BU4cWDydlZcUVx44BcdTAwMWKjWsPpclx1MDAxOVdCJsSNXHUwMDE5XHUwMDE4JE/qh1xmSqo3wW1BcVx1MDAwMyvB0pJDyXevbXNcbngv0LbZ1ZHMZE4gJ1x0QpqpZ1x1MDAwNJT7I3SAdjZa/kE/XHUwMDFhnUdHfp1wXXXkMKKGXHUwMDAy5WJcYkI1hjjOIcewNFx1MDAwNChcdTAwMWZCY5ErJG7FpUfQZ1x1MDAwMVx1MDAwMW/JdVx1MDAxMeF87TaO2DpB9+bJSe8wwvhm9Jq6yFx1MDAxYnU7r9wyfcC02/G3alQ0OS1cXJbjRGhCsmvAc2Wy8+XQPJDfnOZF65c2zZsrc++u6szWMUlcdTAwMTa9OTi8oFwiXHUwMDBlTfPUXG6QUak4pH/JqncxtasvaWKCQEhFdpGnXHUwMDE0dCN2u3s9ijbcXHUwMDAzT9zwweHVcc/uvVx1MDAxZd2ldztcdTAwMGbd6Vx1MDAwM1ZcdTAwMTVdrYvQJZpoXHIh7uJye9A7adCGa91ftK9+7Gy2T5v3vdOqo0spMTAnXHUwMDAwLlx1MDAxMVxmXCJZzfLkYmFcYlx1MDAxZcdcdTAwMWRcdTAwMGbAZG51lVx1MDAxMlxcolC85l82tPvWyW5k4u0uP6xcdTAwMWaMblx1MDAwNlx1MDAwM1Cr6PXQLr3bedBOXHUwMDFmsKLQSsSLoMVcdTAwMWHFSal+XHUwMDA2tdH2VXR4tyt/ycPG9lx1MDAxNW9IsnfxperUYsRcZsqFwpJSXHUwMDExL2boPLWgt5CfYyrwPGorILiSY1x1MDAxNa9Olczu1sXXy0NN7ky457Gj4O6871xmL1/P7tK7ncfu9Fx1MDAwMVfHbmHtVlx1MDAxND9YoyA4XHUwMDA0aJ+R286OayqKbZ0jXHUwMDAzUYRcdTAwMTVcdTAwMDI448WSiYdDmcRcdTAwMDZcdTAwMTNSUPqQ3L7Rasli9du4sqWIxO+7orSC+u2cXHUwMDE0b5n1W4xcdTAwMGLjWy21ZOCKiyM3u1xuUFHkMMeGjlx1MDAxN/0gxGVxOWmCOEhcXLlcdTAwMDYh1VgnXG62yvXJeMVcdTAwMDRcdKrouyau/Fx1MDAxYe6cOuhcdTAwMTLXJ8lcZt5cdTAwMTSDm756xuM3syOJqvKmkEFcdTAwMTDDXHUwMDFh4jnIx8hEOlx0XHUwMDAyJyghT+PF8vVNQ85cdTAwMGKRqX7XXHUwMDBmXHUwMDAzrEDe5iRUS5U3XZxcdFIpiFr8VaPZKXdFYaMxbCBtTGGqp1x1MDAxNG/i7IwhJMRY2+Sb4Lbg+iRcdTAwMDfkJc247jvErXxtm1N0XFyitlx1MDAxNT5cdTAwMGKAXHUwMDA1XCKCaJEpy8yj7eJLdK+Q02tcXHX3XHUwMDFhO1dnW0PvdLfqtGFFXGZcdTAwMTRnZVx1MDAwNCdcdTAwMGZcdTAwMDPofCippVx1MDAwMUmdYip+qlx1MDAxM9LZV7FWXFwoXHUwMDE1U2osT2mjXHUwMDA0bn/wUX4kSXRptG3Ybc9/XHUwMDFlbq7dXHUwMDBlZ8BcdTAwMTZ6w1wi0nJnMYnV2JJcdTAwMTdxVfg6XHUwMDA0ZkzHIUqmejePK9usb1x1MDAwNH3xrd+MzlG9j++3tjevK8+VIIZcdTAwMDBqXG64ojxeoVx1MDAxMFxuKVx1MDAxND9BOut1o9eRlcn9ZpAlKKVSKVa+jpVI1no7J0qrXHUwMDAz68GQmVxcmb7v3UxNxlDhujxcdTAwMDQjSHKK9OJoscb53k7n+HJ9py72/P3dU7y19cKHaSafynzDV424QWAvTjWjkIzhiXSMXCJlcFx1MDAwMOLvXHUwMDAzbK9Lx4rJgsFccqD872NymE5J0LChMFx1MDAwNKtiSuSIOFFcdTAwMWGJXHUwMDE3vIueWFg2cUFo+uGGM2g5g87kIfagVdDimkG46fX7TlxiZnzznEE4uUfS73rs7V3bfEJcdTAwMGX0nG2rhb4zsYI2jDvNL4uk39ZSz0l+PH7/5+PUvVx0llx1MDAwNlI4juhxPreI/+rI0EhcdTAwMDGAmPB5PVx1MDAxNTtH0lPqXHUwMDE3aUdcdTAwMWay/z5Xb0XxS/SIKU3gfNLLPrdGc/Szuf+r88VcdTAwMTXO6c9r+/asqe2rqt9cdTAwMTXqXFxcdTAwMTlcdTAwMTBcdTAwMWRcblx1MDAxZf+PXHUwMDFjQiOevytAKG9gzcZcdTAwMDXRV69CzLgtLCS4mFx0grR8529t/HD6lYhkXHUwMDEzO1x1MDAxZbj6MEa2Zlx1MDAwZYeNMC7SfFx1MDAxZVNcdTAwMDZcdTAwMTfAaY1PMe2tNnLsm40pXHUwMDFl0E7+4l5cdTAwMTNWYyrsePp///nw51+TJY25In0= + + + + UpdateWriteUpdateWriteUpdateWriteUpdateWriteBeforeAfterTime \ No newline at end of file diff --git a/docs/blog/index.md b/docs/blog/index.md index 5ae47bcdbe..210ffd3f9b 100644 --- a/docs/blog/index.md +++ b/docs/blog/index.md @@ -1,3 +1,2 @@ # Textual Blog -Welcome to the Textual blog, where we post about the latest releases and developments in the Textual world. diff --git a/docs/blog/posts/release0-4-0.md b/docs/blog/posts/release0-4-0.md new file mode 100644 index 0000000000..fb55cc4936 --- /dev/null +++ b/docs/blog/posts/release0-4-0.md @@ -0,0 +1,58 @@ +--- +draft: true +date: 2022-11-08 +categories: + - Release +authors: + - willmcgugan +--- + +# Version 0.4.0 + +We've released version 0.4.0 of [Textual](https://pypi.org/search/?q=textual). + +As this is the first post tagged with `release` let me first explain where the blog fits in with releases. We plan on doing a post for every note-worthy release. Which likely means all but the most trivial updates (typos just aren't that interesting). Blog posts will be supplementary to release notes which you will find on the [Textual repository](https://github.com/Textualize/textual). + +Blog posts will give a little more background for the highlights in a release, and a rationale for changes and new additions. We embrace *building in public*, which means that we would like you to be as up-to-date with new developments as if you were sitting in our office. It's a small office, and you might not be a fan of the Scottish weather (it's [dreich](https://www.bbc.co.uk/news/uk-scotland-50476008)), but you can be here virtually. + + + +Release 0.4.0 follows 0.3.0, released on October 31st. Here are the highlights of the update. + +## Updated Mount Method + +The [mount](/api/widget/#textual.widget.Widget.mount) method has seen some work. We've dropped the ability to assign an `id` via keyword attributes, which wasn't terribly useful. Now, an `id` must be assigned via the constructor. + +The mount method has also grown `before` and `after` parameters which tell Textual where to add a new Widget (the default was to add it to the end). Here are a few examples: + +```python + +# Mount at the start +self.mount(Button(id="Buy Coffee"), before=0) + +# Mount after a selector +self.mount(Static("Password is incorrect"), after="Dialog Input.-error") + +tweet = self.query_one("Tweet") +self.mount(Static("Consider switching to Mastodon"), after=tweet) + +``` + +Textual needs much of the same kind of operations as the [JS API](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild) exposed by the browser. But we are determined to make this way more intuitive. The new mount method is a step towards that. + +## Faster Updates + +Textual now writes to stdout in a thread. The upshot of this is that Textual can work on the next update before the terminal has displayed the previous frame. + +This means smoother updates all round! You may notice this when scrolling and animating, but even if you don't you will have more CPU cycles to play with. + +
+--8<-- "docs/blog/images/faster-updates.excalidraw.svg" +
+ + +## Multiple CSS Paths + +Up to version 0.3.0, Textual would only read a single CSS file set in the `CSS_PATH` class variable. You can now supply a list of paths if you have more than one CSS file. + +This change was prompted by [tuilwindcss](https://github.com/koaning/tuilwindcss/) which brings a TailwindCSS like approach to building Textual Widgets. Also checkout [calmcode.io](https://calmcode.io/) by the same author, which is an amazing resource. diff --git a/docs/custom_theme/main.html b/docs/custom_theme/main.html index eaf7085836..2f490a4837 100644 --- a/docs/custom_theme/main.html +++ b/docs/custom_theme/main.html @@ -15,7 +15,6 @@ - {% endblock %} diff --git a/docs/stylesheets/custom.css b/docs/stylesheets/custom.css index d333036012..ea1639ef10 100644 --- a/docs/stylesheets/custom.css +++ b/docs/stylesheets/custom.css @@ -13,11 +13,11 @@ h3 .doc-heading code { monospace; } -body[data-md-color-primary="indigo"] .excalidraw svg { +body[data-md-color-primary="black"] .excalidraw svg { filter: invert(100%) hue-rotate(180deg); } -body[data-md-color-primary="indigo"] .excalidraw svg rect { +body[data-md-color-primary="black"] .excalidraw svg rect { fill: transparent; } diff --git a/mkdocs.yml b/mkdocs.yml index 46f51a2d1e..4677863ad3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -175,7 +175,7 @@ theme: name: Switch to dark mode - media: "(prefers-color-scheme: dark)" scheme: slate - primary: indigo + primary: black toggle: icon: material/weather-night name: Switch to light mode @@ -189,6 +189,7 @@ plugins: as_creation: date categories: - categories + - release - tags - search: - autorefs: diff --git a/pyproject.toml b/pyproject.toml index 85a3502330..71b9335a25 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "textual" -version = "0.4.0a3" +version = "0.4.0" homepage = "https://github.com/Textualize/textual" description = "Modern Text User Interface framework" authors = ["Will McGugan "] diff --git a/src/textual/pilot.py b/src/textual/pilot.py index 6f3f046a40..fee51539d3 100644 --- a/src/textual/pilot.py +++ b/src/textual/pilot.py @@ -32,7 +32,7 @@ async def press(self, *keys: str) -> None: """Simulate key-presses. Args: - *key: Keys to press. + *keys: Keys to press. """ if keys: diff --git a/src/textual/reactive.py b/src/textual/reactive.py index 36fd5b736c..2ee3ba5dfd 100644 --- a/src/textual/reactive.py +++ b/src/textual/reactive.py @@ -68,6 +68,7 @@ def init( layout (bool, optional): Perform a layout on change. Defaults to False. repaint (bool, optional): Perform a repaint on change. Defaults to True. always_update(bool, optional): Call watchers even when the new value equals the old value. Defaults to False. + Returns: Reactive: A Reactive instance which calls watchers or initialize. """