## 7.3.0
This release is additions, new names for the two looks, and one change to when slots shown in a panel are drawn. Nothing was removed, and mods built for 7.2.0 work as before.
### Added
- Lists that change while the screen is open. `ListView` shows one row per item of a list your mod owns and follows it every frame: a new item gets its row at once, a removed one loses it, and every other row stays as it is, so a rename in progress keeps its text and the keyboard while the list refreshes. Rows are kept by a key you give, in your list's order. An optional selection, held by your mod, is set by clicking a row and moved with the arrow keys, and a row your code selects scrolls into view. A list in the middle of a page pushes what is below it down as rows are added or grow, and back up as they go, in the same frame: place what follows it as if it took no room, as after a closed `Section`. [Recipe](https://github.com/trevorschoeny/menukit/blob/main/docs/recipes.md#a-list-that-changes-while-the-screen-is-open).
- Editing a list. `ListView` takes optional builder calls, and a list that uses none of them is unchanged. `add(label, action)` puts an add button per kind in the list's toolbar, and the new row is scrolled into view; `add(label, tooltip, action)` gives the button a hover tooltip saying what the kind is, fixed or read while hovered, and `remove(label, tooltip, ...)` does the same for the remove button. `remove(...)` adds a "- Remove item" button and `move(...)` up and down arrows, both acting on the selected row and gray where they can't act; `pinned(...)` rows can't be removed or moved, and `confirmRemove(...)` asks first, naming the item. After a remove the next row is selected, and Alt+Up and Alt+Down move the selected row. `search(...)` adds a search field and `sort(...)` a sort picker with a direction button. `controlsInRows()` puts up, down and a remove cross in each row instead, for short lists like a config list of text fields. `addDisabledWhen(...)` grays the add buttons and `removeDisabledWhen(...)` the remove, the toolbar's and each row's cross, for a list at its longest or shortest. `disabledReason(...)` explains a grayed list. The toolbar is `list.toolbar()`, placed above the scroll area so it stays put; it is as wide as its container gives it, so its right end is the scroll area's outer edge, while a toolbar the list draws at its own top lines up with the rows. `title(...)` puts the list's heading on the toolbar's line, at its left edge, so the heading and the buttons share one line; read every frame when given a supplier, so it can show a live count, and cut with "..." before the buttons. `title(title, tooltip)` gives the heading a hover tooltip, such as a config option's description, fixed or read while hovered; it shows instead of the whole heading when the heading is cut. The selected row is now a lighter card in the Panel look, and keeps its outline in the Default look. [Recipes](https://github.com/trevorschoeny/menukit/blob/main/docs/recipes.md#a-list-the-player-adds-to-removes-from-and-reorders).
- A dialog that edits a copy. `EditDialog` shows a title, your controls and Cancel and Save, laid out like every MenuKit dialog. The controls edit a draft, so nothing changes until Save, and Cancel or Escape drops it. Open it from any button of your own, such as an Edit button in a list row. [Recipe](https://github.com/trevorschoeny/menukit/blob/main/docs/recipes.md#edit-a-row-in-a-dialog-from-its-own-button).
- `Section.builder(...)` and `Section.Builder.swatch(...)` also take a supplier, read every frame, so a section built once, such as a `ListView` row, shows a renamed title or a new swatch color without being rebuilt. A title too long for its header is cut with "..." before a list row's controls, and shown whole when you hover it.
- `ConfirmDialog.Builder.title(...)` and `body(...)` also take a supplier, read while the dialog shows, so one dialog can name whichever item it's about.
- `Flow.Builder.crossAlign(CrossAlign.CENTER)` centers a row's children on its line, and `END` sets them on its bottom, for a label beside a taller control.
- A button with a menu of actions. `MenuButton` opens a small menu whose rows run actions, for a row's Duplicate and Delete. An action that destroys something is drawn red. The menu is never cut off by a scroll area around it.
- A list that scrolls under a fixed header. `ScrollContainer.Builder.fillHeight()` takes the height it is given: the rest of a screen's main panel, of a vertical `Flow` under a title and buttons, or of a `Tabs` page. A `Tabs` page whose body fills hands the page to it instead of scrolling the whole body, so the header stays put and only the list moves, and the page looks the same as before.
- Text fields that can be canceled and started from code. Escape on a focused `TextField` puts back the text from before the edit, lets go of the keyboard and runs `onCancel`, without closing the screen. `focus()` gives a field the keyboard, for a rename field that appears with its button.
- `Dropdown` and `DropdownMulti` can take their options from a supplier, for options that change while the screen is open.
- `ScreenMatcher.where(test)` puts a panel on the container screens a test accepts, asked as each screen opens, for a panel that belongs where a slot group's slots are. [Recipe](https://github.com/trevorschoeny/menukit/blob/main/docs/recipes.md#show-a-panel-on-the-screens-that-hold-your-slots).
- Item rules that leave chosen components out. `ItemMatch.ignoring(DataComponents.DAMAGE)` makes an `EXACT` or `CONTAINS` rule look past those component types on both sides, so a rule for one exact sword still matches it once it is worn. `ignoringCount()` leaves the count out of `EXACT`. `ItemPicker.Builder.ignoring(...)` and `ignoringCount()` declare the same once for every rule the picker writes, and with `ignoringCount()` the Edit tab has no count. `ItemMatch.CODEC` saves both, and rules saved before load ignoring nothing. [Item picker](https://github.com/trevorschoeny/menukit/blob/main/docs/concepts.md#item-picker).
- `Attachment`, the one way a container attaches a child added after it was built, for mods that write their own containers.
- For slot libraries, `SlotClip.panelShowing(slot)` says whether the panel that last showed a slot is on screen this frame, so a vanilla slot whose panel is hidden can go back to its own place while one scrolled out of view parks.
- `Panel.placedBounds()` returns a panel's own rectangle on the current screen, or `null` when it isn't placed right now. Use it to put something against a panel of your own, such as a close button in its corner, with `PanelPosition.pixel(...)`. It needs no `Anchor` declaration; it's read fresh each call.
- `HudCycleStrip.begin()` and the new `slideProgress(SlideStart)` and `slideDone(SlideStart)` time a mod's own slide against the strip's. `SlideStart` carries its own clock, so there is no raw millis value left to stamp with the wrong one.
- A HUD status column. `HudPanel.Builder.statusColumn()` puts a HUD panel in the 20 px gap between the hearts and the hunger bar, just above the XP level number, or just above the hotbar where the game mode shows no status bars. Panels there stack upward by priority, 2 px apart, and a hidden one takes no room. While anything shows in the column, the chat, vanilla's held-item name, and the action bar message move up only as far as the column reaches them. `HudPanel.SlotBuilder.scale(...)` draws a HUD slot smaller, so a slot at 0.8 fits the column.
### Changed
- The two looks are now called the Default look and the Panel look. `ScreenKind.OPTIONS` is now `ScreenKind.DEFAULT`, `ScreenKind.CONTAINER` is now `ScreenKind.PANEL`, and `ScrollContainer.OPTIONS_INSET_X` and `OPTIONS_INSET_Y` are now `DEFAULT_INSET_X` and `DEFAULT_INSET_Y`. The old names still work and mean the same looks, but are deprecated and go in 8.0.0. `ScreenKind.values()` lists only the two new names, and a `switch` over `ScreenKind` must name them. A mod that lets the player switch look offers a toggle labeled "Look: Default" or "Look: Panel".
- A `ScrollContainer` draws its scrollbar only while its content is taller than it, in both looks; before, the Panel look showed an empty track with a grayed handle. One built with `fitWidth()` gives its children the scrollbar's width while it is hidden, so they reach its right edge. Children you place yourself keep the width you gave them.
- A `ScrollContainer` pushes the children below one that grows (a `ListView` a row is added to, an open `Section`, a wrapped label) down by its growth, and back up as it shrinks, as a panel does, and its scroll range follows in the same frame. Place what follows a list as if it took no room. Scrolled down, a child above the view that grows or shrinks moves the scroll by as much, so what is on screen stays put. A `ScrollContainer` built with `fitHeight()` is as tall as its content up to its declared height, and now pushes what is below it the same way as it grows and shrinks: place what follows it as if it took no room.
- A slot a panel shows draws right after that panel, on top of it. Before, a vanilla slot shown in a panel was drawn before the panel, so the panel covered its item. A panel above another now covers the slots shown in the one below it, and a slot in a dialog draws on the dialog in the same frame. Slots no panel shows draw as before. Mods that mark slots by hooking vanilla's `extractSlot` still see every slot. A mod that hooks the whole slot pass (`extractSlots`) sees the slots shown in panels drawn after it.
- A panel placed by an adapter whose elements are all hidden or empty is no longer drawn as an empty frame, and no longer blocks clicks. A panel with a pinned size keeps its room as before.
- The cycle strip's slide and MK's HUD notifications time themselves off vanilla's own clock (`Util.getMillis()`) instead of the wall clock, so a client gametest that pins and steps the clock can record an animation frame by frame. `HudCycleStrip.slideProgress(long)` and `slideDone(long)` still read `Util.getMillis()` as before, but are deprecated: a `startMillis` from any other clock, `System.currentTimeMillis()` included, silently never reports done, since the two clocks don't share a zero. Use `begin()` and the new overloads instead.
### Fixed
- An element removed from a screen lets go of the keyboard if it had it, and an open dropdown in it closes.
- A button whose click opens another screen no longer looks pressed the next time its panel is shown. Leaving a screen now ends every element's press, drag and keyboard focus, even when the mouse release never arrives (vanilla drops input while it leaves and loads a world).
- A `Tabs` sidebar whose tabs scroll no longer cuts labels that fit when they don't ("List..."). The scrollbar's lane now widens the column instead of narrowing the tabs, so the body is that much narrower while the tabs scroll, in both looks. The sidebar header sits over the tabs, right of the lane. Labels are cut only when the widest is wider than a third of the `Tabs`, as before.
- A side-scroll `Tabs` tab wider than the room between the arrows is narrowed to it and its label shortened with "...", instead of being clipped at the arrows.
Developer information
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle.
maven { name = "Modrinth"; url = "https://api.modrinth.com/maven" }