beartropy/tables
Beartropy Tables is a Livewire table component for the TALL stack with search, sorting, filters, bulk actions, and column toggling. It includes inline editing and boolean toggles with per-field authorization hooks to control writes.
editable() now owns persistence. Previously setColumns() nulled out every closure so Livewire could serialize the column objects, which left a closure editableCallback silently unreachable: the callback never ran, and updateField() fell through to the default write and saved the field anyway. The callback now runs, and — matching how a string callback has always behaved — it replaces the default write rather than running alongside it. A table using editable('input', [], fn ($id, $field, $value, $table) => ...) that relied on the field still being saved must now persist it from inside the closure.updateField() dispatched table-field-updated before doing any work, so a denied or failed update announced itself as a successful one. It is now dispatched only once the write has actually happened — after a callback runs, after a successful model save, or after the array row is updated. A write refused by authorizeFieldUpdate()/authorizeFieldUpdateRaw(), or aimed at a record that does not exist, no longer dispatches it.updateField() resolves the column through getFreshColumns() instead of the serialized $this->columns, which is what makes closure callbacks reachable at all. This matches how Sort, Search and Data already resolve columns when they need callbacks intact.Neither change is reachable through the package's own views: the inline editor only renders for columns marked ->editable(), and toggles only render for toggle columns. Both guards reject input the UI never produces, so the affected surface is programmatic calls and hand-crafted Livewire requests.
updateField() now refuses to write a column that was not marked with ->editable(). Previously any declared column could be written through the inline-edit action, including display-only ones. Tables that call updateField() programmatically on a non-editable column must add ->editable() to that column's definition.toggleBoolean() now refuses a column key that is not part of the table's columns(). A key absent from both columns() and the row data previously raised Undefined array key and now returns quietly. The genuine behaviour change is the other case: a key present in the row data but never declared as a column — for example a data() row carrying is_admin with no matching column — used to flip successfully and is now refused.authorizeFieldUpdate() was only consulted on the Eloquent write path. A column with a string editableCallback, and every array/stdClass backed table, wrote with no authorization check at all. Both paths are now gated by the new authorizeFieldUpdateRaw() hook.authorizeFieldUpdateRaw($id, string $field, mixed $value): bool on Editable, defaulting to true. It is the counterpart of authorizeFieldUpdate() for the write paths that have no resolved Eloquent model — a column with a custom update callback, and array/stdClass backed tables — which receive the raw row id instead of a record. authorizeFieldUpdate()'s own signature is unchanged, so existing overrides typed Model $record keep working; override the new hook as well to cover the non-model paths.authorizeToggle($id, string $column): bool on RowManipulators, defaulting to true. Override it to gate boolean toggles the way authorizeFieldUpdate() gates field writes.__PHP_Incomplete_Class under Laravel 13's hardened cache unserialization — which broke rendering with htmlspecialchars(): Argument #1 ($string) must be of type string, __PHP_Incomplete_Class given. Stringable values (Carbon, etc.) are cached as their string form, preserving rendered output.getCachedData() now self-heals — a non-array cache hit (a legacy cached TableCollection or an incomplete-class artifact from a pre-upgrade entry) is discarded and rebuilt from source instead of rendering garbage.TableCollection object, and re-wrapped into a TableCollection on read. This keeps the cache compatible with Laravel 13's hardened unserialization (cache.serializable_classes) without consumers having to allow-list TableCollection. Legacy cached collections are tolerated for the remaining TTL window after upgrading.pestphp/pest: ^4.0, pestphp/pest-plugin-laravel: ^4.0).livewire/livewire: ^3.7|^4.0).orchestra/testbench: ^9.0|^10.0|^11.0)._original, _disabled, _hidden, _card_title) no longer leak into exported data. Previously only _original was stripped.Collection subclass that carries column label metadata from processCollection() through to GenericExport, enabling automatic label resolution without requiring changes to existing export methods.key() helper function instead of key: named argument in [@livewire](https://github.com/livewire)() directive for inline expanded row components. The named argument syntax isn't handled by Livewire's Blade compiler regex, causing a closure parameter error when expanding task rows.isHtml as a class property (public $isHtml = false) so property_exists() returns true on PHP 8.2+. Previously, isHtml was set dynamically in the toHtml() trait method, causing the raw-HTML branch in Blade templates to never trigger.secondaryHeader(callable $callback) method to display a secondary header row below the main header with computed content (e.g., subtotals, averages). The callback receives the current page's rows as a Collection and supports HTML output.query() method — scope table data by tenant, permissions, or any custom condition without global scopes.newQuery() wrapper that applies $with eager loading automatically on top of query().soft to glass.outline to soft (light tinted background with colored text) for a consistent, subtle look across all header buttons.$yat_button_variant instead of a hardcoded outline attribute, ensuring all buttons match.ArrayObject instead of plain arrays, preserving both $row->key and $row['key'] access in user callbacks (fixes "Attempt to read property on array" regression from v2.9.2).processCollection() and addRowToTable(), preventing "Cannot use object of type stdClass as array" errors when data() returns stdClass objects (e.g. from json_decode() or API responses).setTheme() not propagating to header components.YATBaseTable to BeartropyTable. The old name continues to work via class_alias — no changes needed in existing user code.YATProvider to BeartropyTableServiceProvider. The old name extends the new one for backward compatibility.make:btable now generates extends BeartropyTable instead of extends YATBaseTable.BeartropyTable throughout. Doc files renamed from yat-base-table to bear-table.bt-tables-setup updated with correct artisan command (make:btable) and BeartropyTable references.bt-tables-docs-maintenance updated with correct service provider path.ComponentDocs schema example updated from yat-base-table to bear-table.setComponentSize() method to uniformly resize all header UI components.mixed type from $model property to restore child class compatibility. Typed parent properties cannot be overridden without matching the type exactly in PHP 8.down() method to properly reverse migration.queryCallback failing when no matching database column exists.->query() without a real column) now work correctly by generating a virtual key instead of requiring a column match.triggerCardInfoModal(bool) method to Column class to optionally disable opening the info modal when clicking the card title on mobile.cardTitle() method to allow dynamic content generation for mobile card titles.Data trait and Column serialization logic to support passing closures to views, enabling more dynamic UI definitions.centered() method to Column class for easy content and header alignment.DateColumn class for displaying formatted date values:
inputFormat(string) - specify expected input date format.outputFormat(string) - define display format (default: Y-m-d).emptyValue(string) - fallback value for null/empty dates.Data::transformRow() for automatic date parsing and formatting.DateColumn class.Column logic (instantiation, unique keys, modifiers) and Options logic.TestCase setup with SQLite in-memory database and Pest configuration.yat-table.blade.php:
yat-table.blade.php for better readability and performance.YATableComponent.stub with improved code styling and type hints.pushLeft() and pushRight() by adding flex utilities to header wrappers.Column class (parameter type hints and return types).sortable(bool) and searchable(bool) modifiers to Column class to explicitly enable/disable these features.Undefined array key error when updateField is not in columns.wire:key and cache invalidation).setUpdateField() method to Column to support updating relationship IDs while displaying names.hover:bg-amber-200 type effect).updateField return a boolean status for UI feedback..agent folder from repository and added it to .gitignore.setButtonThemeOverride(?string $theme) and setInputThemeOverride(?string $theme) to View trait to allow overriding themes for specific components.useGlobalSearch(bool) method to Search trait to toggle global search input visibility.showOnlyTable(bool) method to YATBaseTable to quickly disable global search, pagination, and column toggle.pushLeft() and pushRight() methods to Column class for easy content and header alignment using Tailwind CSS.text-left, pl-2) for the row counter column in yat-table.blade.php.inputThemeOverride to beartropy in View trait.View trait to fallback to gray theme.buttonThemeOverride.getThemeConfig helper method to View trait.How can I help you explore Laravel packages today?