treestoneit/text-wrap
A PHP text-wrapping utility for Laravel that breaks long strings into fixed-width lines. Wrap plain text or HTML safely, preserve whole words, and control line length for emails, reports, consoles, and any output where clean, readable formatting matters.
Resolve the scope mismatch before anything else. The package description and the package code describe two different products. The README pitches a zero-dependency, multibyte-safe PHP string-wrapping utility for console output, plain-text email, and PDFs. The repository and all three prior assessments describe a Laravel Nova field — a Text subclass, a service provider calling Nova::script()/Nova::style(), and a compiled Vue component that renders long values wrapped instead of truncated in index and detail views. That is a discovery and documentation-integrity finding in its own right: we cannot size, staff, or accept risk against a package whose stated purpose does not match its shipped artifact. Any evaluation has to be run twice, and both runs end in the same place.
Architecture fit — utility reading. If the README is accurate, this is a pure function with no framework surface: no routes, no migrations, no queue or HTTP interface, no domain logic. The ceiling is "formatting helper." PHP already ships wordwrap(), and multibyte-safe wrapping is a solved problem in maintained libraries. The architectural fit is total but the value is near-zero, because the capability is already in the standard library and every competent PHP developer writes this in ten minutes.
Architecture fit — Nova field reading. If the code is authoritative, blast radius is confined entirely to the admin panel: a provider registration, one published asset, one field class extending core Text. It touches no business logic, no persistence, no API surface. That is a genuinely small footprint — and also a genuinely small payoff. The delivered value is line wrapping in a table cell, which is a CSS/displayUsing() concern.
Integration feasibility. Low effort, gated by a hard compatibility wall. The last release is 2018-08-31, predating Nova 3/4/5, Vue 3, Inertia, Vite, and PHP 8. Composer will very likely refuse to resolve against a modern laravel/nova constraint, and forcing the resolution does not make the Vue 2 asset bundle run in a modern Nova toolchain. There is no path where this is a drop-in on a current stack.
Technical risk.
v-html or innerHTML appears in resources/js/field.js, user-controlled content is interpolated as raw HTML inside an authenticated surface. This must be grepped and remediated before any use — it is a security decision, not a styling decision.Key questions for the team.
composer.json in src/ constrain to ^1.0/^2.0?v-html/innerHTML?Decision posture. No-go on adoption under either reading of the package. If the need is CSS-level wrapping, a Text::make(...)->displayUsing(fn ($v) => $v) plus a theme override likely closes it. If that fails, a ~30-line in-repo field via php artisan nova:field costs less to build than a 2018 fork costs to carry.
Stack fit. The package fits exactly one stack: Nova 1.x/2.x, PHP 7.x, Vue 2, Laravel Mix. If that is our stack and the upgrade horizon is 12–18 months out, it is a plausible stopgap. On Nova 3+, PHP 8, Inertia, or Vite it is out of scope by construction — do not attempt to force it.
Compatibility gating criteria. Treat as viable only if all hold: legacy Nova 1.x/2.x in the target app; a confirmed, specific need for wrapped (not truncated) rendering in index or detail view; no capacity to write the field ourselves; and explicit acceptance that we are vendoring unmaintained code as first-party. Any one of Nova 3+, PHP 8, a maintained-upstream dependency policy, or a support/SLA requirement kills it outright.
Preferred path — spike, then build. Sequence in this order and stop at the first step that satisfies the UX requirement:
Text field with displayUsing(), plus a CSS override in the Nova theme for column width and wrapping. If this passes, close the ticket and add no dependency.php artisan nova:field, 1–2 engineer-days including a resource-resolution test and a browser smoke test asserting wrapped rendering. Register in the shared Nova field kit so other resources reuse it.path repository, pin the commit, rebuild the Vue component against our installed Nova toolchain rather than shipping the 2018 bundle, audit and fix v-html, and add a CI smoke test.Migration path if we consume it. Never require it from Packagist — a future composer update can pull the abandoned release back in. Fork to nova-components/text-wrap under our namespace, register via a path repository, and treat the directory as first-party code subject to our review standards. If auto-discovery is inactive, register the provider manually in config/app.php, then run the package's publish tag (php artisan vendor:publish --tag=text-wrap) and clear Nova/Laravel caches.
Usage pattern. Display only. Pair a normal Textarea on forms with the wrapped field on index/detail (onlyOnIndex()->exceptOnForms() and onlyOnDetail()), and funnel field construction through a single private helper so swapping implementations later is a one-line change in one place. Keep the PHP call shape (TextWrap::make(...) plus standard Nova modifiers) stable regardless of whether the backing class is the fork or our in-house field — resource classes should never need to change when we replace it.
Sequencing and rollback. The spike and the in-repo build are both reversible in under a day and carry no dependency surface. The fork is the only step that creates a standing obligation, so it goes last and only with a named owner. Rollback from the fork is deleting the path repository and repointing the helper to the in-house class.
Maintenance. Adoption transfers 100% of maintenance to us, permanently, with no upstream to defer to. The concrete carrying cost is a 2018 Vue 2 component on a paid, closed-source host framework, with no community of scale to absorb upgrades. Every future Nova major — which we must take, since Nova is commercially licensed and security-relevant — becomes our migration work. That ongoing cost exceeds the 1–2 engineer-days to write the field fresh, and it recurs.
Support. There is no security contact, no issue triage, no release cadence, and no SLA. Under a dependency policy requiring a maintained upstream, this fails on all three counts. If it is adopted anyway, it must be explicitly reclassified as first-party code in our inventory, with an owner in the team's maintenance roster and a documented exemption on file — otherwise it becomes orphaned code that nobody knows they own.
Scaling. Runtime scaling is a non-issue in either reading. As a Nova field it executes once per rendered row in the admin panel, with payloads bounded by operators and pagination; as a utility it is a string operation. There is no load, throughput, or cost dimension here. The scaling exposure is organizational, not technical: the fork's maintenance burden stays flat forever while the number of Nova upgrades it has to survive grows.
Failure modes to instrument for.
laravel/nova constraint — caught at install, harmless.v-html in the component. One-time audit at fork time; re-check on any rebuild.composer update because it was required by name rather than path-pinned.Ramp-up. Effectively zero for any Laravel developer, and near-zero for anyone else because there is nothing to learn. A Text subclass plus a provider is idiomatic Nova and familiar to the team. That low ramp-up is also the strongest argument against adoption: the package's entire value proposition is a thing a Nova developer reproduces in a day, so there is no expertise, no abstraction, and no capability being purchased — only a maintenance obligation.
Recommendation. Decline adoption. Capture the underlying signal — operators want long-text legibility in admin tables for notes, addresses, descriptions, and error payloads — as a line in the internal-tooling polish backlog. Assign the ≤1-day theme/displayUsing() spike against the next admin-panel ticket. If it misses, fund the 1–2 day in-repo field. Reserve the fork for the narrow legacy case: still on Nova 1.x/2.x with no upgrade inside 12–18 months, and a leader willing to name an owner.
How can I help you explore Laravel packages today?