Repository navigation
Releases
Releases · Opus-Perpetuus/flexablelib
3.7.0
Added
ScrollViewfollows the focus (follow_focus=True, the default):
when a component inside it takes the focus, its rows are scrolled into
view; scrolling by hand afterwards is left alone.focus_rows(width)
gives the rows of the focused component.MenuandSidebarkeep to their height: with more items than fit,
a window around the current item with▲ n más/▼ n máslines (click
them to page); PgUp/PgDn move a page and the wheel scrolls. The sidebar
title stays on top.- Responsive
Formgrid:min_column_widthdrops to fewer columns when
they would be narrower;FormCell(field, span=, min_width=)and
Form.set_layout()give a field several columns, more when it would be
narrower than its minimum;grid_columns(width). DataTable(fill=True)takes its whole slot with the status line at
the bottom;visible_rowsis how many rows the last frame showed.GridView: aflexablelib.Gridas a component with an accessible
name (title/a11y_label) and role, andaudit()for itself and
every component inside.StatusLine: a one-line status bar with rolestatus, a symbol per
kind besides the colour, and screen-reader announcements on change.
Changed
VStackwithoutweightsgives weight 1 to children that fill their
slot (expand:DataTable(fill=True),ScrollView,Sidebar,Tabs),
so they share the rows left over; before, every child kept its own
height.Menuwithmax_visible(or a height) now shows the▲/▼lines.
v3.6.0
Added
SignatureInput: a signature pad drawn with the mouse (press and
drag) or the keyboard (arrows move the pen, Space puts it down and lifts
it,xerases, Backspace undoes,cclears).valueis the list of
strokes;to_text(),to_bitmap(scale)andto_png(scale)export it.Stopwatch: a stopwatch input for forms -- start / stop (Space or
Enter), laps (l), reset (r);valueis the elapsed
datetime.timedelta,lapsthe split times,on_lap(split).VStack: children one below the other sharing the stack's height by
weights, withinmin_heights/max_heights; when they do not fit it
scrolls and follows the focus (the child holding the focused component
comes into view; Tab reaches the ones out of view). Wheel and PgUp/PgDn
scroll it, with an optional scroll bar.CatalogGridpictures: items take animage(path, URL, bytes or
bitmap) andimage_alt;image_height,image_methodand
image_headerscontrol them. Enter or a click on the current card sets
selected/value.- Image downloads with headers:
Image(headers=),
ImageViewer(headers=),CatalogGrid(image_headers=)and
_images.load(url, headers=)send e.g. anAuthorizationbearer token.
Authorization,Proxy-AuthorizationandCookieare not sent on to
redirects, and no header value appears in errors. ValidationSummaryfrom a list: messages,(field, message)pairs,
dicts withfield/messageor exceptions, besides the
{field: message}dict. Withfields(aFormor inputs) or
on_selectit takes the focus and Enter moves the focus to the field.
entriesandmessageslist them.EditableTable(name=)and itsvalue(a copy of the rows), so a
Formcollects it.
Changed
Form.values()andForm.fields()reach nested fields: inputs inside
containers (Stack,VStack,Tabs-- hidden tabs too --,Wizard
steps,Accordionsections, grids, cards) and namedEditableTables,
not only the top-level ones. Validation and "Enter moves to the next
field" reach them too.ScanInputkeeps the code it read (keep_value=True, the new
default):valueand aFormstill have it after the read, the next
read replaces it as soon as it starts typing, and Enter on the shown code
does not read it twice.keep_value=Falserestores the old behaviour of
clearing the field after every read.last_codeis the latest code.- Focus without colour: a focused empty
DataTable, anImagedrawn as
text (alt text,[alt], the warning) and theImageViewerinfo line now
show a▸marker (>without colour or in ASCII mode) and reverse
video, not only a colour. A focusedCatalogGridcard always has the
▸marker besides its heavy border. - Image download errors give the HTTP status or the reason
(no se pudo descargar (HTTP 401)) instead of the exception text.
v3.5.5
Fixed
- Line breaks in Markdown, reStructuredText, AsciiDoc and LaTeX exports:
every breakcompose()and the readers honour (\r\n, a lone\r,
\u2028,\u2029, vertical tab, form feed,\x85,\x1c-\x1e) now
becomes a space, as\nalready did. A cell with a Windows line ending
split its Markdown row in two, sofrom_markdown()read back extra rows
and shifted every column after it; the RST grid came out ragged. - Fitting a float column to
max_widthno longer pads its shorter
numbers with zeros:-0.5printed as-0.50000000when another number
in the column set the decimal budget. - A number written with an exponent (
6.01e+16) counts whole towards
how narrow its column can go. Only its integer digits were counted, so
the reduction was booked against a column that could not give it back
and the other columns kept their decimals while the table stayed too
wide.
3.5.4
Fixed
- Kitty keyboard reports with out-of-range code points (
CSI 97;1;99999999u,
a shifted key above U+10FFFF) no longer raiseValueErrorfrom
KeyParser.feed(): the invalid text or shifted code is ignored and the
key is reported as usual. - Escape followed by a bracketed paste in the same read: the paste text
no longer starts with\x1b[200~. - Input split across reads parses like the whole input:
ESC ESCwaits
for the next byte, soESC ESC [Aread in pieces is stillalt+up
(a lone double Escape still gives twoescapekeys after the pause). MoneyInputclicks put the cursor under the clicked character (the
currency symbol was counted as text, so the cursor landed one place to
the right); clicking an empty field and then pressingctrl+leftno
longer raisesIndexError.TextInput(and every input built on it) keeps acursor_posset
out of range from outside within the text instead of raising on word
moves.CoordinatesInputrenders at widths 1 and 2 (latitude above
longitude) instead of raisingValueError.- An empty
Tablewithshow_index=Truerenders like without the index
instead of raisingTypeError.
Changed
KeyandMouseEventkeep all their fields throughcopy,deepcopy
andpickle(aMouseEventcould not be copied at all).
3.5.3
Fixed
- Index labels with a
row_filter(orsort_by) and hidden empty rows
(show_empty_rows=False): the visible rows are numbered 0, 1, 2 as
without a filter, instead of 0, 2, 4 (the hidden empty rows used to take
a number).to_records,to_csv,paginateandstreamagree. stream()index column is as wide as incompose()when rows are
hidden byrow_filterorshow_empty_rows=False: it was sized for every
row, so the streamed table came out one column wider.- Contrast checks (
parse_color,contrast_ratio,Theme.contrast())
understand every colour the core draws:colour:N, hex without#
(ff8800), andgreyNNas the xterm grey really shown. A theme using
colour:Nreported no ratio, or 1:1 forblack on colour:226. - Colour tokens with non-ASCII digits (
'²','٣') raise
ColourErrorlike any unknown colour, instead of a bareValueErroror
being read as a palette index.
Changed
- Hiding empty rows no longer re-scans every row once per row while
numbering the index (quadratic in the row count).
PR #80.
3.5.2
Fixed
- Dialogs shown with
app.push()(Modal,ConfirmDialog,
PromptDialog,Popover) now close with Escape, their buttons and
close(), as when shown withopen(app).close()looks at the app's
layers instead of a flag onlyopen()set. - A
Forminside a modal closes with Escape from any field, with or
withouton_cancel. When the form'son_cancel(or any code) calls
app.pop(), the dialog'sis_opengoes back to False andon_closeruns
once. Textwith\r\nor\rline endings (for example the output of
Table.to_csv()): every line ending counts as a new line, so no\r
reaches the terminal and frames, grids and cards keep their borders.
3.5.1
Added
- Linux aarch64 (arm64) wheels for
flexableliband
flexablelib-speedups, glibc (manylinux) and musl (musllinux/Alpine),
CPython 3.8–3.14, built and tested on native arm64 runners. - macOS Intel (x86_64) wheels for both projects, CPython 3.8–3.14.
- Every wheel is checked on its own architecture by
tools/wheel_check.py:
the C extension loads and matches the pure Python code (text measurement,
frame primitives, picture resize/quantize/sixel/blocks) on random input.
Changed
- 49 binary wheels per extension project (was 28): manylinux and musllinux
for x86_64 and aarch64, Windows x64, macOS arm64 and x86_64.
3.5.0 — Pictures in the terminal
Added
- Pictures in the terminal (
flexablelib-components, see
docs/IMAGES.md):ImageandImageViewer, andFilePreviewdraws
image files (and the first page of PDFs and SVGs whenpdftoppm,
PyMuPDF,rsvg-convertor cairosvg is available). Automatic fallback
chain: kitty graphics protocol (Unicode placeholders on kitty 0.28+,
Ghostty and through tmux passthrough), iTerm2 inline images,
sixel, Unicode blocks (half blocks, quadrants, sextants, braille in
truecolor / 256 / 16 colours or mono), ASCII, then an OSC 8 link that
opens the picture in the browser (BROWSER,xdg-open,gio,open,
start,wslview), and with no browser and no display a warning
(⚠/!) with the file name and the reason -- nothing is opened.
fit(contain,cover,fill,none), proportions from the cell
size in pixels,alt,caption,background,animate,focusable
(Enter /o/ click open it). - Graphics detection (
flexablelib_tui.graphics,detect_graphics,
GraphicsInfo): environment first (kitty, Ghostty, WezTerm, iTerm2, VS
Code, Konsole, mintty, Warp, rio, foot, mlterm, contour, Windows
Terminal, Terminal.app, tmux client features and passthrough, GNU
screen), then one short query of the terminal (kitty APC query,
CSI 16 t/CSI 14 tcell and window pixels,TIOCGWINSZ,
XTSMGRAPHICS, XTVERSION, DA1), cached;Appasks through its terminal
and replays keys typed meanwhile.FLEXABLELIB_IMAGE=kitty|iterm|sixel| blocks|half|quadrant|sextant|braille|ascii|link|noneforces a method,
FLEXABLELIB_NO_BROWSER=1says there is no browser. - Image decoding without dependencies (
flexablelib._images): PNG
(every colour type and depth, transparency, Adam7), GIF (frames,
disposal, interlace), BMP (1–32 bit, bit fields), PPM/PGM/PBM; Pillow
(flexablelib[images]) adds JPEG, WebP, TIFF and the rest. URLs with a
timeout and a size cap. - C acceleration in
flexablelib-speedupsfor resizing (area
average), median-cut quantization, the sixel encoder, PNG unfiltering
and the block/braille conversion, byte-identical to the Python fallback
(29–87× faster;tools/bench_images.py).FLEXABLELIB_IMAGES=python
forces Python. - Extras
images(Pillow) -- included inall-- andsvg(cairosvg).
Changed
- Frames carry pictures as an invisible zero-width mark that becomes the
picture sequence when the frame is written (str(),print,Live,
App): widths, layouts and the frame diff are unchanged.Liveredraws a
picture when a line it covers changes and deletes kitty pictures that
left the screen. CardandGridwithout colour keep the invisible component and picture
marks (clicks and pictures inside layouts work withNO_COLOR).Appreaches components inside aCardbody (focus, keys, clicks).- The accessibility audit reports
no alt textfor images.
flexablelib 3.4.0
Added
- Keyboard input, complete (
flexablelib-tui, seedocs/INPUT.md):
one key name whatever the terminal sends -- xterm/VT100/VT220 (CSI, SS3,
8-bit CSI), rxvt/urxvt, the Linux console, Alt as an ESC prefix, F1–F24
(F35 with kitty) with any modifier, Ctrl/Alt/Shift/Meta/Super/Hyper in a
fixed order (ctrl+alt+shift+f12), the kitty keyboard protocol
(Ctrl+I vs Tab, Ctrl+Enter, keypad, press/repeat/release), xterm
modifyOtherKeys, bracketed paste (even split across reads), terminal
focus in/out and terminal answers (DA, DECRQM, XTVERSION, kitty flags).
Keycarrieschar,event,mouse,dataandraw;
normalize_key,key_label. - Windows Console API input (
wincon):ReadConsoleInputWrecords
with virtual-key codes and modifiers (AltGr, F13–F24, surrogate pairs,
mouse, wheel, resize, focus), virtual-terminal input and themsvcrt
fallback (Terminal(windows='records' | 'vt' | 'msvcrt')). CI injects
records into a real console onwindows-latest. - Capability detection (
detect_capabilities,capabilities.probe):
colour level, Unicode, size and terminal from the environment, then a
probe of the terminal itself;Terminal(keyboard='auto')turns on the
kitty protocol or modifyOtherKeys when available and restores everything
on exit. - Key map (
KeyMap): remap keys, name actions (focus_next,quit,
help,read_screen...),describe,conflicts, save/load JSON;
App(keymap=...). - Mouse in every component:
App(mouse=True)(or'hover') knows
which component drew each cell and focuses and passes clicks to it --
buttons, checkboxes, switches, radios, tabs, menus, sidebar, pagination,
sort controls, calendars and date pickers, selects, autocomplete, file
entries, trees, accordions, carousels, links, alerts,DataTablerows,
checkbox column and headers, catalog cards. The wheel scrolls what is
under the pointer; drags moveSplitdividers and scroll bars, with
capture until release.Component.on_mouse(event)in local coordinates;
_Themed.hot()registers clickable spots. - Accessibility (
flexablelib_tui.accessibility, see
docs/ACCESSIBILITY.md): settings from the environment
(FLEXABLELIB_SCREEN_READER,_REDUCED_MOTION,_ASCII,
_FOCUS_MARKER,_THEME,_LANG,_A11Y) orApp(...)arguments;
screen-reader mode (linear text with role, label, value, state and
description; announcements of focus, changes, dialogs and notifications
to stdout, stderr, a file or a callback; Ctrl+R reads the screen);
roles, accessible names, values and states for every component;
focus visible without colour (text markers); themeshigh-contrast,
high-contrast-light,deuteranopia,protanopia,tritanopia,
monochromewith WCAG contrast (Theme.contrast(),contrast_ratio)
and colour-blindness simulation (simulate_cvd,delta_e);
App(theme=...); static spinners and skeletons with reduced motion;
status with symbol and word (status_symbol), chart markers per series;
ASCII fallback for frames;App(min_size=...); F1 help screen built from
the bindings;tab_index;audit()checks role, label and visible focus. - Folios (see
docs/FOLIOS.md):Table.id_columns('auto', a list,
orNoneas before) andTable.id_namesprint identifiers -- folios,
IDs, codes, SKUs, postal codes, years -- without thousands separators
while quantities and money keep them;flexablelib.is_id_columnand
ID_COLUMN_NAMES;to_excelfollows.DataTablecolumntype
'id'/'number'/'money',id_columns,id_names. - C:
ascii_fold(8× faster) andextract_marks(click zones, 2× faster)
inflexablelib-speedups, with Python fallbacks and parity tests. examples/keys.py: live key and mouse detector.examples/admin.py
takes--theme,--screen-reader,--ascii,--reduced-motion,
--focus-markerandclick:X:Ykeys.
Changed
DataTableno longer puts thousands separators in identifier columns
by name (id_columns=Falserestores 3.3).- The default selection style is bold as well as coloured; without colour,
focus and selection use text markers ([>Guardar<],>before the
current item). - On
TERM=dumbthe app prints linear text and switches no terminal
modes (no paste, focus or mouse escape sequences). FORCE_COLOR=0turns colour off. Colour specs accept attributes after
the background (black on cyan underline).
flexablelib 3.3.1
Fixed
- Tabs no longer push tables and cards past their width. A tab measures
nothing, so a cell holding one was sized and wrapped as narrower than the
spaces it became: the table came out wider thanmax_width(or
render(width)), and in card mode the raw tab displaced the frame.
Cells are expanded before they are measured, headers are trimmed on their
expanded width withoverflow='truncate', andwrap_to_widthexpands
tabs itself, so cards, grids, widgets and components get it too. - A newline in a card title, or in a title set into a border
(title_position='border'), split the frame in two; the title now
goes on one line. Multi-line table titles and captions are aligned line
by line instead of only the first line. max_widthnow counts thepanel(two columns) andshadow
(one): squeezing,expand_to_windowandtoo_narrow_messagesized
the columns for the full width and then drew the panel outside it.from_csvandfrom_markdowndrop a leading UTF-8 byte-order mark
(Excel's "CSV UTF-8"): it was kept as the first character of the first
header, and a Markdown table gained an extra empty column.- A brace format template (
custom_format={'price': '{:,.2f}'},
float_format='$ {:,.2f}') no longer aborts the whole render on a text
cell in the column; the cell prints as it is, as it already did with a
plain spec. A template that needs more than one value raises a
ValueErrorthat says so.
Added
flexablelib.text_width.expand_tabs(text, tabsize=8): tab expansion
that counts terminal columns (wide characters two, escape sequences
none).
pip install -U flexablelib==3.3.1 (extras [tui,components,speed] in lockstep).