blog post new release (#2712)

* blog post new release

* update words

* Update docs/blog/posts/release0-27-0.md

Co-authored-by: Dave Pearson <davep@davep.org>

---------

Co-authored-by: Dave Pearson <davep@davep.org>
This commit is contained in:
Will McGugan
2023-06-01 11:33:54 +01:00
committed by GitHub
parent 78db024c01
commit 58a9cb1909
15 changed files with 2057 additions and 346 deletions

View File

@@ -5,8 +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/) The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/). and this project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased ## [0.27.0] - 2023-06-01
### Fixed ### Fixed

1
docs/api/suggester.md Normal file
View File

@@ -0,0 +1 @@
::: textual.suggester

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 33 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 182 KiB

View File

@@ -0,0 +1,138 @@
<svg class="rich-terminal" viewBox="0 0 860 538.0" xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@font-face {
font-family: "Fira Code";
src: local("FiraCode-Regular"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
font-style: normal;
font-weight: 400;
}
@font-face {
font-family: "Fira Code";
src: local("FiraCode-Bold"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
font-style: bold;
font-weight: 700;
}
.terminal-1356838233-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
.terminal-1356838233-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
.terminal-1356838233-r1 { fill: #1e1e1e }
.terminal-1356838233-r2 { fill: #0178d4 }
.terminal-1356838233-r3 { fill: #c5c8c6 }
.terminal-1356838233-r4 { fill: #e2e2e2 }
.terminal-1356838233-r5 { fill: #787878;font-weight: bold }
.terminal-1356838233-r6 { fill: #e1e1e1 }
</style>
<defs>
<clipPath id="terminal-1356838233-clip-terminal">
<rect x="0" y="0" width="840.8" height="487.0" />
</clipPath>
<clipPath id="terminal-1356838233-line-0">
<rect x="0" y="1.5" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-1">
<rect x="0" y="25.9" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-2">
<rect x="0" y="50.3" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-3">
<rect x="0" y="74.7" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-4">
<rect x="0" y="99.1" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-5">
<rect x="0" y="123.5" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-6">
<rect x="0" y="147.9" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-7">
<rect x="0" y="172.3" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-8">
<rect x="0" y="196.7" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-9">
<rect x="0" y="221.1" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-10">
<rect x="0" y="245.5" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-11">
<rect x="0" y="269.9" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-12">
<rect x="0" y="294.3" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-13">
<rect x="0" y="318.7" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-14">
<rect x="0" y="343.1" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-15">
<rect x="0" y="367.5" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-16">
<rect x="0" y="391.9" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-17">
<rect x="0" y="416.3" width="841.8" height="24.65"/>
</clipPath>
<clipPath id="terminal-1356838233-line-18">
<rect x="0" y="440.7" width="841.8" height="24.65"/>
</clipPath>
</defs>
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="858" height="536" rx="8"/><text class="terminal-1356838233-title" fill="#c5c8c6" text-anchor="middle" x="429" y="27">FruitsApp</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
<circle cx="44" cy="0" r="7" fill="#28c840"/>
</g>
<g transform="translate(9, 41)" clip-path="url(#terminal-1356838233-clip-terminal)">
<rect fill="#0178d4" x="0" y="1.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="12.2" y="1.5" width="817.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="829.6" y="1.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#0178d4" x="0" y="25.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="12.2" y="25.9" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="36.6" y="25.9" width="61" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="97.6" y="25.9" width="61" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="158.6" y="25.9" width="646.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="805.2" y="25.9" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="829.6" y="25.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#0178d4" x="0" y="50.3" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="12.2" y="50.3" width="817.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="829.6" y="50.3" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="74.7" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="99.1" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="123.5" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="147.9" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="172.3" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="196.7" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="221.1" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="245.5" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="269.9" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="294.3" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="318.7" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="343.1" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="367.5" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="391.9" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="416.3" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="440.7" width="841.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="465.1" width="841.8" height="24.65" shape-rendering="crispEdges"/>
<g class="terminal-1356838233-matrix">
<text class="terminal-1356838233-r1" x="0" y="20" textLength="12.2" clip-path="url(#terminal-1356838233-line-0)"></text><text class="terminal-1356838233-r2" x="12.2" y="20" textLength="817.4" clip-path="url(#terminal-1356838233-line-0)">▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔</text><text class="terminal-1356838233-r2" x="829.6" y="20" textLength="12.2" clip-path="url(#terminal-1356838233-line-0)"></text><text class="terminal-1356838233-r3" x="841.8" y="20" textLength="12.2" clip-path="url(#terminal-1356838233-line-0)">
</text><text class="terminal-1356838233-r1" x="0" y="44.4" textLength="12.2" clip-path="url(#terminal-1356838233-line-1)"></text><text class="terminal-1356838233-r4" x="36.6" y="44.4" textLength="61" clip-path="url(#terminal-1356838233-line-1)">straw</text><text class="terminal-1356838233-r5" x="97.6" y="44.4" textLength="61" clip-path="url(#terminal-1356838233-line-1)">berry</text><text class="terminal-1356838233-r2" x="829.6" y="44.4" textLength="12.2" clip-path="url(#terminal-1356838233-line-1)"></text><text class="terminal-1356838233-r3" x="841.8" y="44.4" textLength="12.2" clip-path="url(#terminal-1356838233-line-1)">
</text><text class="terminal-1356838233-r1" x="0" y="68.8" textLength="12.2" clip-path="url(#terminal-1356838233-line-2)"></text><text class="terminal-1356838233-r2" x="12.2" y="68.8" textLength="817.4" clip-path="url(#terminal-1356838233-line-2)">▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁</text><text class="terminal-1356838233-r2" x="829.6" y="68.8" textLength="12.2" clip-path="url(#terminal-1356838233-line-2)"></text><text class="terminal-1356838233-r3" x="841.8" y="68.8" textLength="12.2" clip-path="url(#terminal-1356838233-line-2)">
</text><text class="terminal-1356838233-r3" x="841.8" y="93.2" textLength="12.2" clip-path="url(#terminal-1356838233-line-3)">
</text><text class="terminal-1356838233-r3" x="841.8" y="117.6" textLength="12.2" clip-path="url(#terminal-1356838233-line-4)">
</text><text class="terminal-1356838233-r3" x="841.8" y="142" textLength="12.2" clip-path="url(#terminal-1356838233-line-5)">
</text><text class="terminal-1356838233-r3" x="841.8" y="166.4" textLength="12.2" clip-path="url(#terminal-1356838233-line-6)">
</text><text class="terminal-1356838233-r3" x="841.8" y="190.8" textLength="12.2" clip-path="url(#terminal-1356838233-line-7)">
</text><text class="terminal-1356838233-r3" x="841.8" y="215.2" textLength="12.2" clip-path="url(#terminal-1356838233-line-8)">
</text><text class="terminal-1356838233-r3" x="841.8" y="239.6" textLength="12.2" clip-path="url(#terminal-1356838233-line-9)">
</text><text class="terminal-1356838233-r3" x="841.8" y="264" textLength="12.2" clip-path="url(#terminal-1356838233-line-10)">
</text><text class="terminal-1356838233-r3" x="841.8" y="288.4" textLength="12.2" clip-path="url(#terminal-1356838233-line-11)">
</text><text class="terminal-1356838233-r3" x="841.8" y="312.8" textLength="12.2" clip-path="url(#terminal-1356838233-line-12)">
</text><text class="terminal-1356838233-r3" x="841.8" y="337.2" textLength="12.2" clip-path="url(#terminal-1356838233-line-13)">
</text><text class="terminal-1356838233-r3" x="841.8" y="361.6" textLength="12.2" clip-path="url(#terminal-1356838233-line-14)">
</text><text class="terminal-1356838233-r3" x="841.8" y="386" textLength="12.2" clip-path="url(#terminal-1356838233-line-15)">
</text><text class="terminal-1356838233-r3" x="841.8" y="410.4" textLength="12.2" clip-path="url(#terminal-1356838233-line-16)">
</text><text class="terminal-1356838233-r3" x="841.8" y="434.8" textLength="12.2" clip-path="url(#terminal-1356838233-line-17)">
</text><text class="terminal-1356838233-r3" x="841.8" y="459.2" textLength="12.2" clip-path="url(#terminal-1356838233-line-18)">
</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,155 @@
<svg class="rich-terminal" viewBox="0 0 1116 635.5999999999999" xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@font-face {
font-family: "Fira Code";
src: local("FiraCode-Regular"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
font-style: normal;
font-weight: 400;
}
@font-face {
font-family: "Fira Code";
src: local("FiraCode-Bold"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
font-style: bold;
font-weight: 700;
}
.terminal-369012557-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
.terminal-369012557-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
.terminal-369012557-r1 { fill: #e1e1e1 }
.terminal-369012557-r2 { fill: #c5c8c6 }
.terminal-369012557-r3 { fill: #1e1e1e }
.terminal-369012557-r4 { fill: #b93c5b }
.terminal-369012557-r5 { fill: #e2e2e2 }
.terminal-369012557-r6 { fill: #e1e1e1;font-weight: bold }
.terminal-369012557-r7 { fill: #98a84b }
</style>
<defs>
<clipPath id="terminal-369012557-clip-terminal">
<rect x="0" y="0" width="1097.0" height="584.5999999999999" />
</clipPath>
<clipPath id="terminal-369012557-line-0">
<rect x="0" y="1.5" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-1">
<rect x="0" y="25.9" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-2">
<rect x="0" y="50.3" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-3">
<rect x="0" y="74.7" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-4">
<rect x="0" y="99.1" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-5">
<rect x="0" y="123.5" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-6">
<rect x="0" y="147.9" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-7">
<rect x="0" y="172.3" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-8">
<rect x="0" y="196.7" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-9">
<rect x="0" y="221.1" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-10">
<rect x="0" y="245.5" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-11">
<rect x="0" y="269.9" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-12">
<rect x="0" y="294.3" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-13">
<rect x="0" y="318.7" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-14">
<rect x="0" y="343.1" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-15">
<rect x="0" y="367.5" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-16">
<rect x="0" y="391.9" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-17">
<rect x="0" y="416.3" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-18">
<rect x="0" y="440.7" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-19">
<rect x="0" y="465.1" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-20">
<rect x="0" y="489.5" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-21">
<rect x="0" y="513.9" width="1098" height="24.65"/>
</clipPath>
<clipPath id="terminal-369012557-line-22">
<rect x="0" y="538.3" width="1098" height="24.65"/>
</clipPath>
</defs>
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1114" height="633.6" rx="8"/><text class="terminal-369012557-title" fill="#c5c8c6" text-anchor="middle" x="557" y="27">InputApp</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
<circle cx="44" cy="0" r="7" fill="#28c840"/>
</g>
<g transform="translate(9, 41)" clip-path="url(#terminal-369012557-clip-terminal)">
<rect fill="#1e1e1e" x="0" y="1.5" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="25.9" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="24.4" y="25.9" width="793" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="817.4" y="25.9" width="280.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="50.3" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="74.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#b93c5b" x="12.2" y="74.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="24.4" y="74.7" width="1049.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="1073.6" y="74.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="1085.8" y="74.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="99.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#b93c5b" x="12.2" y="99.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="24.4" y="99.1" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="48.8" y="99.1" width="36.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="85.4" y="99.1" width="963.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="1049.2" y="99.1" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="1073.6" y="99.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="1085.8" y="99.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="123.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#b93c5b" x="12.2" y="123.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#262626" x="24.4" y="123.5" width="1049.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="1073.6" y="123.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="1085.8" y="123.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="147.9" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="172.3" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="24.4" y="172.3" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="36.6" y="172.3" width="305" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="341.6" y="172.3" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="366" y="172.3" width="244" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="610" y="172.3" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="634.4" y="172.3" width="341.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="976" y="172.3" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="988.2" y="172.3" width="85.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="1073.6" y="172.3" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="196.7" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="221.1" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="245.5" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="269.9" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="294.3" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="318.7" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="343.1" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="367.5" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="391.9" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="416.3" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="440.7" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="465.1" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="489.5" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="513.9" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="538.3" width="1098" height="24.65" shape-rendering="crispEdges"/><rect fill="#1e1e1e" x="0" y="562.7" width="1098" height="24.65" shape-rendering="crispEdges"/>
<g class="terminal-369012557-matrix">
<text class="terminal-369012557-r2" x="1098" y="20" textLength="12.2" clip-path="url(#terminal-369012557-line-0)">
</text><text class="terminal-369012557-r1" x="24.4" y="44.4" textLength="793" clip-path="url(#terminal-369012557-line-1)">Enter&#160;an&#160;even&#160;number&#160;between&#160;1&#160;and&#160;100&#160;that&#160;is&#160;also&#160;a&#160;palindrome.</text><text class="terminal-369012557-r2" x="1098" y="44.4" textLength="12.2" clip-path="url(#terminal-369012557-line-1)">
</text><text class="terminal-369012557-r2" x="1098" y="68.8" textLength="12.2" clip-path="url(#terminal-369012557-line-2)">
</text><text class="terminal-369012557-r3" x="12.2" y="93.2" textLength="12.2" clip-path="url(#terminal-369012557-line-3)"></text><text class="terminal-369012557-r4" x="24.4" y="93.2" textLength="1049.2" clip-path="url(#terminal-369012557-line-3)">▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔</text><text class="terminal-369012557-r4" x="1073.6" y="93.2" textLength="12.2" clip-path="url(#terminal-369012557-line-3)"></text><text class="terminal-369012557-r2" x="1098" y="93.2" textLength="12.2" clip-path="url(#terminal-369012557-line-3)">
</text><text class="terminal-369012557-r3" x="12.2" y="117.6" textLength="12.2" clip-path="url(#terminal-369012557-line-4)"></text><text class="terminal-369012557-r5" x="48.8" y="117.6" textLength="36.6" clip-path="url(#terminal-369012557-line-4)">foo</text><text class="terminal-369012557-r4" x="1073.6" y="117.6" textLength="12.2" clip-path="url(#terminal-369012557-line-4)"></text><text class="terminal-369012557-r2" x="1098" y="117.6" textLength="12.2" clip-path="url(#terminal-369012557-line-4)">
</text><text class="terminal-369012557-r3" x="12.2" y="142" textLength="12.2" clip-path="url(#terminal-369012557-line-5)"></text><text class="terminal-369012557-r4" x="24.4" y="142" textLength="1049.2" clip-path="url(#terminal-369012557-line-5)">▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁</text><text class="terminal-369012557-r4" x="1073.6" y="142" textLength="12.2" clip-path="url(#terminal-369012557-line-5)"></text><text class="terminal-369012557-r2" x="1098" y="142" textLength="12.2" clip-path="url(#terminal-369012557-line-5)">
</text><text class="terminal-369012557-r2" x="1098" y="166.4" textLength="12.2" clip-path="url(#terminal-369012557-line-6)">
</text><text class="terminal-369012557-r6" x="24.4" y="190.8" textLength="12.2" clip-path="url(#terminal-369012557-line-7)">[</text><text class="terminal-369012557-r7" x="36.6" y="190.8" textLength="305" clip-path="url(#terminal-369012557-line-7)">&#x27;Must&#160;be&#160;a&#160;valid&#160;number.&#x27;</text><text class="terminal-369012557-r1" x="341.6" y="190.8" textLength="24.4" clip-path="url(#terminal-369012557-line-7)">,&#160;</text><text class="terminal-369012557-r7" x="366" y="190.8" textLength="244" clip-path="url(#terminal-369012557-line-7)">&#x27;Value&#160;is&#160;not&#160;even.&#x27;</text><text class="terminal-369012557-r1" x="610" y="190.8" textLength="24.4" clip-path="url(#terminal-369012557-line-7)">,&#160;</text><text class="terminal-369012557-r7" x="634.4" y="190.8" textLength="341.6" clip-path="url(#terminal-369012557-line-7)">&quot;That&#x27;s&#160;not&#160;a&#160;palindrome&#160;:/&quot;</text><text class="terminal-369012557-r6" x="976" y="190.8" textLength="12.2" clip-path="url(#terminal-369012557-line-7)">]</text><text class="terminal-369012557-r2" x="1098" y="190.8" textLength="12.2" clip-path="url(#terminal-369012557-line-7)">
</text><text class="terminal-369012557-r2" x="1098" y="215.2" textLength="12.2" clip-path="url(#terminal-369012557-line-8)">
</text><text class="terminal-369012557-r2" x="1098" y="239.6" textLength="12.2" clip-path="url(#terminal-369012557-line-9)">
</text><text class="terminal-369012557-r2" x="1098" y="264" textLength="12.2" clip-path="url(#terminal-369012557-line-10)">
</text><text class="terminal-369012557-r2" x="1098" y="288.4" textLength="12.2" clip-path="url(#terminal-369012557-line-11)">
</text><text class="terminal-369012557-r2" x="1098" y="312.8" textLength="12.2" clip-path="url(#terminal-369012557-line-12)">
</text><text class="terminal-369012557-r2" x="1098" y="337.2" textLength="12.2" clip-path="url(#terminal-369012557-line-13)">
</text><text class="terminal-369012557-r2" x="1098" y="361.6" textLength="12.2" clip-path="url(#terminal-369012557-line-14)">
</text><text class="terminal-369012557-r2" x="1098" y="386" textLength="12.2" clip-path="url(#terminal-369012557-line-15)">
</text><text class="terminal-369012557-r2" x="1098" y="410.4" textLength="12.2" clip-path="url(#terminal-369012557-line-16)">
</text><text class="terminal-369012557-r2" x="1098" y="434.8" textLength="12.2" clip-path="url(#terminal-369012557-line-17)">
</text><text class="terminal-369012557-r2" x="1098" y="459.2" textLength="12.2" clip-path="url(#terminal-369012557-line-18)">
</text><text class="terminal-369012557-r2" x="1098" y="483.6" textLength="12.2" clip-path="url(#terminal-369012557-line-19)">
</text><text class="terminal-369012557-r2" x="1098" y="508" textLength="12.2" clip-path="url(#terminal-369012557-line-20)">
</text><text class="terminal-369012557-r2" x="1098" y="532.4" textLength="12.2" clip-path="url(#terminal-369012557-line-21)">
</text><text class="terminal-369012557-r2" x="1098" y="556.8" textLength="12.2" clip-path="url(#terminal-369012557-line-22)">
</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,77 @@
---
draft: false
date: 2023-06-01
categories:
- Release
title: "Textual adds Sparklines, Selection list, Input validation, and tool tips"
authors:
- willmcgugan
---
# Textual adds Sparklines, Selection list, Input validation, and tool tips
It's been 12 days since the last Textual release, which is longer than our usual release cycle of a week.
We've been a little distracted with our "dogfood" projects: [Frogmouth](https://github.com/Textualize/frogmouth) and [Trogon](https://github.com/Textualize/trogon). Both of which hit 1000 Github stars in 24 hours. We will be maintaining / updating those, but it is business as usual for this Textual release (and it's a big one). We have such sights to show you.
<!-- more -->
## Sparkline widget
A [Sparkline](../../widget_gallery.md#selectionlist) is essentially a mini-plot. Just detailed enough to keep an eye on time-series data.
<div>
--8<-- "docs/blog/images/sparkline.svg"
</div>
Colors are configurable, and all it takes is a call to [`set_interval`](https://textual.textualize.io/api/message_pump/#textual.message_pump.MessagePump.set_interval) to make it animate.
## Selection list
Next up is the [SelectionList](../../widget_gallery.md#selectionlist) widget. Essentially a scrolling list of checkboxes. Lots of use cases for this one.
<div>
--8<-- "docs/blog/images/selection-list.svg"
</div>
## Tooltips
We've added [tooltips](../../guide/widgets.md#tooltips) to Textual widgets.
The API couldn't be simpler: simply assign a string to the `tooltip` property on any widget.
This string will be displayed after 300ms when you hover over the widget.
<div>
--8<-- "docs/blog/images/tooltips.svg"
</div>
As always, you can configure how the tooltips will be displayed with CSS.
## Input updates
We have some quality of life improvements for the [Input](../../widget_gallery.md#input) widget.
You can now use a simple declarative API to [validating input](http://127.0.0.1:8000/widgets/input/#validating-input).
<div>
--8<-- "docs/blog/images/validation.svg"
</div>
Also in this release is a suggestion API, which will *suggest* auto completions as you type.
Hit <kbd>right</kbd> to accept the suggestion.
Here's a screenshot:
<div>
--8<-- "docs/blog/images/suggest.svg"
</div>
You could use this API to offer suggestions from a fixed list, or even pull the data from a network request.
## Join us
Development on Textual is *fast*.
We're very responsive to issues and feature requests.
If you have any suggestions, jump on our [Discord server](https://discord.gg/Enf6Z3qhVr) and you may see your feature in the next release!

View File

@@ -1,3 +1,5 @@
from math import sin
from textual.app import App, ComposeResult from textual.app import App, ComposeResult
from textual.widgets._sparkline import Sparkline from textual.widgets._sparkline import Sparkline
@@ -6,7 +8,7 @@ class SparklineColorsApp(App[None]):
CSS_PATH = "sparkline_colors.css" CSS_PATH = "sparkline_colors.css"
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
nums = [10, 2, 30, 60, 45, 20, 7, 8, 9, 10, 50, 13, 10, 6, 5, 4, 3, 7, 20] nums = [abs(sin(x / 3.14)) for x in range(0, 360 * 6, 20)]
yield Sparkline(nums, summary_function=max, id="fst") yield Sparkline(nums, summary_function=max, id="fst")
yield Sparkline(nums, summary_function=max, id="snd") yield Sparkline(nums, summary_function=max, id="snd")
yield Sparkline(nums, summary_function=max, id="trd") yield Sparkline(nums, summary_function=max, id="trd")

View File

@@ -186,6 +186,7 @@ nav:
- "api/scrollbar.md" - "api/scrollbar.md"
- "api/scroll_view.md" - "api/scroll_view.md"
- "api/strip.md" - "api/strip.md"
- "api/suggester.md"
- "api/timer.md" - "api/timer.md"
- "api/types.md" - "api/types.md"
- "api/walk.md" - "api/walk.md"

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "textual" name = "textual"
version = "0.26.0" version = "0.27.0"
homepage = "https://github.com/Textualize/textual" homepage = "https://github.com/Textualize/textual"
description = "Modern Text User Interface framework" description = "Modern Text User Interface framework"
authors = ["Will McGugan <will@textualize.io>"] authors = ["Will McGugan <will@textualize.io>"]

View File

@@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import statistics import statistics
from fractions import Fraction
from typing import Callable, Generic, Iterable, Sequence, TypeVar from typing import Callable, Generic, Iterable, Sequence, TypeVar
from rich.color import Color from rich.color import Color
@@ -52,10 +53,10 @@ class Sparkline(Generic[T]):
data: The data to partition. data: The data to partition.
num_buckets: The number of buckets to partition the data into. num_buckets: The number of buckets to partition the data into.
""" """
num_steps, remainder = divmod(len(data), num_buckets) bucket_step = Fraction(len(data), num_buckets)
for i in range(num_buckets): for bucket_no in range(num_buckets):
start = i * num_steps + min(i, remainder) start = int(bucket_step * bucket_no)
end = (i + 1) * num_steps + min(i + 1, remainder) end = int(bucket_step * (bucket_no + 1))
partition = data[start:end] partition = data[start:end]
if partition: if partition:
yield partition yield partition

View File

@@ -16,6 +16,7 @@ def test_sparkline_single_datapoint():
def test_sparkline_two_values_min_max(): def test_sparkline_two_values_min_max():
print(repr(render(Sparkline([2, 4], width=2))))
assert render(Sparkline([2, 4], width=2)) == f"{GREEN}{STOP}{RED}{STOP}" assert render(Sparkline([2, 4], width=2)) == f"{GREEN}{STOP}{RED}{STOP}"
@@ -40,13 +41,6 @@ def test_sparkline_shrink_data_to_width():
) )
def test_sparkline_shrink_data_to_width_non_divisible():
assert (
render(Sparkline([1, 2, 3, 4, 5], width=3, summary_function=min))
== f"{GREEN}{STOP}{BLENDED}{STOP}{RED}{STOP}"
)
def test_sparkline_color_blend(): def test_sparkline_color_blend():
assert ( assert (
render(Sparkline([1, 2, 3], width=3)) render(Sparkline([1, 2, 3], width=3))

File diff suppressed because one or more lines are too long