Skip to content

Changelog

All notable changes to FilamentCraft are documented here.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

[Unreleased]

[1.33.0]

Added

  • filamentcraft:customize-section. A guided command that searches the built-ins and generates an application-owned subclass — either an additive variant with its own slug, or an explicit application-wide replacement with --replace. The subclass inherits the built-in's settings, blocks, presets, defaults and behaviour, so only what you override changes. --copy-view takes ownership of the Blade markup too; leave it off and upstream view improvements keep applying.
    • filamentcraft:doctor no longer warns about a slug override when the replacement is a subclass of the built-in — that is the supported shape.

Changed

  • A section is only offered the look knobs its markup can answer to. All five knobs used to be appended to every section, so a stats row was asked for an image frame and a gallery for a card style even though those classes reach no element in that markup. Each built-in now declares its applicable set through the new Section::lookKnobs(), and the editor's Look panel is the intersection — banner, footer and gallery show no Look panel at all. A custom section keeps all five unless it narrows them.
    • Arabic: the Look group read المظهر, the same label as every section's own style group, and is now الطابع; the image-frame knob reads نسبة الصورة, and the team section's style field no longer collides with the card-style knob.

[1.32.0]

Added

  • The Locations section draws a real map. Give a location a latitude and longitude — pasted straight from Google Maps or OpenStreetMap, in either field, as a 48.8584, 2.2945 pair, a place link, a #map= fragment or a geo: URI — and the section plots every one of them on a live slippy map with numbered pins that match the numbers on the cards. No API key, no account, no third-party JavaScript.
    • The server resolves the zoom that frames every pin, the tiles that cover the canvas and where each pin lands, then emits them as percentages. The map is correct with JavaScript switched off and never shifts layout; the site bundle then re-tiles at the element's real pixel width and adds drag-to-pan, zoom buttons, Ctrl/ + scroll and double-click zoom. Plain scrolling always scrolls the page.
    • Clicking a card's pin number centres the map on that location.
    • A location with coordinates and no directions link gets one built from them.
    • map_tone re-skins the raster from the section's own palette: muted, tinted (duotoned into the scheme's primary and accent) or night.
    • map_source is auto by default and falls back coordinates → embed URL → image, so a site that only ever set an embed URL renders exactly as before.
    • The map now also renders in the cards-only layout, not just the split one.
  • filamentcraft.maps config: tile_url, attribution, attribution_url and max_zoom. The default is OpenStreetMap because it needs no setup, but its tile policy is best-effort with no SLA and warns that commercial access may be withdrawn — so the URL template is config, not a constant, and understands {z}, {x}, {y}, {s} and {r} for Stadia, MapTiler, Thunderforest or a self-hosted renderer. Set tile_url to an empty string and coordinates fall back to OpenStreetMap's own embed, still interactive, one marker.

[1.31.0]

Fixed

  • The theme's color scheme is finally global. The "Default scheme" picker sits in the editor's global settings next to fonts, buttons and spacing — but it was the only value there that persisted onto the page you happened to have open, so picking a scheme restyled that one template and nothing else. It now lives on Site.settings_json['color_scheme'] alongside every other global setting, and every template, region and host-rendered shell page renders on it. Per-page variation stays where it belongs: a section's own scheme setting. An idempotent upgrade migration promotes the scheme a live site already chose (its home page's, else the first page that carries one) onto the site row, so existing sites keep their look.
  • Host shell pages inherit the site scheme. <x-filamentcraft::layout> and RendersInSiteShell read Site.settings_json['color_scheme'] — a key nothing wrote until now, so cart, checkout and account pages always rendered on the package default no matter what the operator picked. Passing :color-scheme still pins one page to something else.
  • The header / footer region editor previews on the site's scheme instead of a hardcoded default, so chrome is no longer authored against the wrong palette.
  • The editor canvas repaints on a scheme change. A canvas refresh morphs <body> only, so the scheme attributes on <html> kept their initial value — the same gap dir / lang were already patched for. All four attributes now sync from the refreshed document.

Added

  • filamentcraft:doctor warns about stranded per-page color schemes — a site whose pages still ask for a scheme its own row doesn't carry never ran the promotion migration, so it is silently rendering on the package default. The warning names the site, the page and the scheme it wanted.
  • SiteColorSchemes::activeFor() / ::setActive() for reading and writing a site's global scheme from migrations, seeds, and host code.

Upgrading

Package migrations are published, not auto-loaded, so run this once to promote the scheme your sites already chose:

bash
php artisan vendor:publish --tag=filamentcraft-migrations && php artisan migrate

filamentcraft:doctor tells you whether you need it.

[1.30.0]

Added

  • Hover-inspector toggle in the editor topbar. Switches the whole canvas overlay layer off — hover outlines, the selected outline, both toolbars and click-to-select — so the preview reads as a plain page. The choice persists per browser and is re-sent on every iframe handshake, so a preview reload keeps it.
  • Delete on sidebar section rows. A trash action on row hover, with a confirmation naming the section. Hidden rows keep their actions visible; locked rows get none.

Fixed

  • The desktop canvas fills the available width instead of sitting in a fixed 1440px box between gutters. A window wider than the device width previews at its own width; a narrower one still lays out natively and scales down.
  • Dark mode persists across pages inside the editor. The canvas now stores the visitor scheme override under an :editor-suffixed sessionStorage key, so the choice survives a page or region hop without ever touching the visitor's own localStorage key.
  • A republished preview bundle no longer serves stale JavaScript. The injected iframe script was versioned by package version while the parent editor script used file mtime, so republishing assets without an upgrade left the two halves of the bus at different vintages — a working feature read as completely dead in an open tab. It is now cache-busted by mtime.
  • Repository prose (reports, docs) no longer leaks class names into the shipped site.css; Tailwind's auto-detected sources are scoped to real render surfaces.

[1.29.0]

Added

  • Per-section look variants. Five knobs on every section — card style, image frame, arrangement, corners and button weight — each emitting one class on the section wrapper so the built-in primitives re-skin from CSS alone. Two sites on the same section library can now look nothing alike. Every knob defaults to "Theme default", so nothing changes appearance until you pick one. Turn the panel off with sections.look_variants => false; a section can also declare its own subset with the HasLookSettings concern.
  • Mobile filters on product listings. The filter rail becomes a sticky column on desktop and a bottom sheet on phones, with a Filters trigger carrying the active-filter count, a live result count, and clear-filters in both. Previously a phone visitor could not filter a catalogue at all. The sheet opens from a checkbox, so it works with JavaScript disabled; JavaScript adds the scroll lock, Escape, focus trap and keyboard activation.
  • Optional mobile bottom navigation on the header. show_mobile_nav (default off) renders the header's first four nav links as a fixed bottom tab bar on phones, respecting env(safe-area-inset-bottom). It publishes a --fc-bottom-chrome variable that the watermark and toast host read so nothing stacks on top of it.
  • Cart event and toast bus. FilamentCraft\Commerce\CartEvents owns the browser event names, so a host section and a built-in header can finally talk to each other. CartService dispatches a CartUpdated event on every change, any [data-fc-cart-count] updates itself, and <x-filamentcraft::toast-host /> ships the announcement region.
  • RendersInSiteShell for host-owned Livewire pages. Applies the same locale rule the public renderer uses (honour ?locale= only when the site has that locale, never the browser's) and pins it across Livewire updates, so a visitor mid-checkout is no longer dropped back onto the site default.
  • Whole-card click affordance. .fc-card--clickable + .fc-card__hit-area: a card clickable as a whole that still contains its own buttons, without nesting interactive elements in an anchor or faking it in JavaScript.
  • SectionData::currentRecordKey() — what record the page is about. The product carousel now drops it by default, so a "related" row on a product page no longer leads with the product you are already looking at.
  • --fc-card-media-ratio, --fc-cat-ratio and --fc-gallery-ratio so card and gallery frames can be re-themed by inheritance instead of inline styles.
  • .fc-tag--inline for reusing the pill as an ordinary in-flow chip.
  • FILAMENTCRAFT_SOFT_DEGRADE env switch for the attribution link.

Fixed

  • Livewire sections now repaint in the editor preview. A wire:id root was skipped wholesale by the canvas morph, so every LivewireSection ignored colour scheme, preset and setting changes until the iframe was reloaded by hand. The canvas now adopts the server's freshly rendered node and re-registers the component, and leaves it alone when only Livewire's own bookkeeping differs.
  • Dark mode survives a wire:navigate hop. The pre-paint restore ran once and never again, so the first internal link dropped the visitor's choice back to light. It now re-applies on livewire:navigated — and clears the override when nothing is stored, so a page can get back to light too.
  • Two scrollbars in the editor's settings rail. Filament renders toggle-button radios as position: absolute inside a static wrapper, so their containing block fell through to the rail, which then never clipped them and grew a second scrollbar next to the panel's own as soon as a settings group was expanded.
  • Card badges survive a hidden image frame. "Sale" / "New" / "Sold out" are anchored to the card instead of the media frame, so a card variant with no photography keeps its badge.
  • Header icon controls meet the 44px touch target both platform vendors ask for, without changing their painted size.

[1.28.4]

Fixed

  • Preview iframe now truly clips to the phone's rounded corners. The device shell is CSS-scaled, and under a transformed ancestor Chromium promotes the iframe to its own layer that ignores border-radius clipping — so the bottom bar still spilled over the bezel. The frame now uses clip-path, which clips the composited iframe layer reliably. Supersedes the 1.28.3 attempt.

[1.28.3]

Fixed

  • Mobile/tablet preview no longer spills past the phone's rounded corners. Browsers don't clip an <iframe> to its parent's border-radius, so the site's bottom bar and buttons overflowed the device mockup's rounded chin. The preview iframe now carries its own bottom corner radius.

[1.28.2]

Fixed

  • Carousel arrows now point the right way in RTL. The prev/next chevrons were hard-coded left/right, so on Arabic and other RTL sites they contradicted the (already RTL-aware) scroll direction. The icons now mirror in RTL.

[1.28.1]

Fixed

  • Tier reporting now works on installs that published the config file.filamentcraft:install publishes config/filamentcraft.php, and a file published before 1.28.0 has no public_key entry — which shadowed the package default and left every key reading as untiered. The signing key now lives in code, with config as an override for anyone self-signing.

[1.28.0]

Added

  • Your license key now tells you which tier it is. Keys issued from today carry their tier, signed so it cannot be edited, and php artisan filamentcraft:doctor reports it — License allowance (Studio — 2 of 5 sites). Verification happens locally against a key shipped in the package; nothing contacts a server, as before.
  • Doctor warns when an install holds more sites than its tier covers, so an agency can see at a glance whether a project needs its own license.

Notes

  • Nothing is enforced from this and nothing is blocked. Project counts are license terms. The count is per install, so it cannot see sites a license runs elsewhere — a ceiling would penalise a single multi-tenant install while missing an install-per-client setup entirely.
  • Keys issued before this release carry no tier and report no ceiling. They keep working exactly as they did, forever; there is no need to reissue.

[1.26.1]

Added

  • Edit a block straight on the canvas. Pointing at a block raises a small toolbar on it — drag to move, add space above or below, duplicate — each labelled on hover, so the common edits no longer need a trip to the structure tree.
  • Dropping a layout onto a canvas that already has content adds a spacer between them, instead of stacking the two flush as one run-on section.

Fixed

  • A custom section's settings are listed flat. Each block used to get its own collapsible group, so editing a three-card feature section meant opening nine cards to reach nine fields. Fields now sit in document order with the block's name on the field itself — Heading, or Button · Label for a block with several editable props. Existing sections pick this up the next time they are saved.
  • An image uploaded in the builder now shows in the preview. Livewire reports a finished upload at its nested state path, which no control owned, so the file was discarded before it reached the draft — the section only picked the image up once it had been saved and placed on a page.
  • The canvas drag handle sits on the block it drags. It is fixed-positioned but was offset from its static flow position, so it parked near the foot of the document no matter which block was selected.
  • A custom section's hover label drops the type namespace — the canvas toolbar read Custom::Get Started where the section is just "Get Started".

[1.26.0]

Added

  • No-code section builder. Editor users can now design their own section types in the browser — no PHP, no release. They compose one from 25 block primitives (or start from one of 24 curated layouts), arrange it on a live canvas or in a structure tree, style each block from theme tokens, and save it. The result lands in the Add section catalog beside the built-ins and can be placed as many times as you like, each instance holding its own content.
  • The settings panel writes itself. Every editable prop bound while building becomes a setting on the saved section, grouped by the block it came from, so the person who builds a section and the person who fills it in do not have to be the same person. Rich text gets a rich editor, images an upload, icons the picker.
  • Custom sections behave like built-ins. They are cacheable, honour colour schemes and Brand Kit limits, render per locale, and re-saving one bumps a version counter that folds into the fragment-cache key — so a section invalidates its own cached HTML without a manual flush.
  • Fenced for untrusted operators. Definitions resolve only within their own site, trees stop at four levels and a configurable node cap, the HTML block's markup runs through the shared sanitizer with <script> behind an opt-in allow_custom_code, and every control value is validated against its declared option set or numeric bounds before it reaches the tree. Deleting a definition that pages already place tells you how many first.
  • New docs page at /guide/section-builder, with filamentcraft:doctor auditing stored definitions.

Fixed

  • Storefront layouts no longer collapse when the host ships its own Tailwind build. Both bundles emit the same utility names, and unlayered, a host's .grid-cols-1 landed after our lg:grid-cols-4 at equal specificity and won on source order — flattening every responsive section to a single column. The stylesheet now declares an explicit cascade-layer order, so our utilities beat a host's layered output while any unlayered host CSS still overrides us and deliberate storefront overrides keep working.
  • Abandoned builder drafts no longer consume a site's section allowance. A closed browser tab used to leave a draft row that counted against the limit forever; only saved sections count now, and stale drafts are swept.
  • Uploading a file into a setting that cannot hold one no longer 500s with Serialization of 'TemporaryUploadedFile' is not allowed. Draft values are sanitized through one shared path for both the builder and the settings panel.
  • An off-shape section icon can no longer take the editor down. The icon renders in the section rail on every load, so an unresolvable name is coerced back to the default rather than trusted.
  • Closing a saved section from the builder no longer discards it. The back control is non-destructive once a section has been saved, and confirms only when there is unsaved work to lose.

[1.25.0]

Fixed

  • The preview stays where you are working. Reordering, moving, hiding, or restyling a section no longer snaps the canvas back to the top of the page — the preview re-anchors to the section you are editing after every refresh.
  • Auto-save is now off by default, with a longer debounce when you turn it on, so an editing session no longer writes a draft on every keystroke.

[1.24.0]

Added

  • Per-locale headers, footers, and announcement bars. Regions are now locale-bucketed exactly like page content: each locale of a multi-locale site gets its own header/footer/announcement, editable independently through the same locale switcher, copy-from-locale, and empty-locale states the page editor already has. A locale you have not translated yet falls back to the default locale's region on the public site, so nothing renders blank.

Fixed

  • Existing regions upgrade in place. A shipped migration wraps every stored region's current content into its site's default-locale bucket, so live sites keep rendering unchanged and pick up per-locale editing without data loss. The renderer also tolerates an un-migrated region, so a host that updates the package but delays php artisan migrate never 500s. filamentcraft:doctor now flags any region still on the legacy shape.

[1.23.0]

Added

  • Gate who can open the builder. A new canAccessUsing() plugin setter takes a closure — passed the authenticated user — that decides whether the builder is reachable. When it returns false the dashboard, the editor, and the advanced resources all drop out of navigation and return 403 on direct URL access, so a plan/licence/Gate check has a single wiring point with no bypass. Omitting it leaves the builder open to every panel user, as before.

Fixed

  • A missing filamentcraft_sites table no longer 500s the whole panel. On a host that registered the plugin but had not yet run filamentcraft:install, navigation rendering resolved a site on every page and threw an uncaught QueryException, taking down every panel route — not just the builder. Site resolution now probes the table first and degrades to "no site" instead.

[1.22.0]

Added

  • In-editor preview link navigation. Clicking a storefront link in the editor canvas — a product card, a category tile, or a Shop / Cart / Checkout button — now switches the editor to the page that renders it and previews the clicked record, instead of the click being swallowed. The destination page is resolved from the sections each page contains (a Product Detail section marks the product page, Cart the cart page, Product Listing the shop/category page), so it needs no configuration; product and category links carry the clicked slug so the destination previews that exact record, and the topbar page dropdown re-syncs automatically.

[1.20.1]

Fixed

  • Doctor's primary-domain warning was misleading. It claimed an empty filamentcraft.domain.primary degrades "subdomain resolution". Inbound subdomain matching reads APP_URL's host and never touches that key — domain.primary only affects generated public URLs. The warning now says so.
  • install --folio overstated what it does. Its help text and console output claimed it wires Folio routing; it scaffolds resources/views/storefront/ and prints the Folio::path(...) line for you to register yourself. Text corrected — behaviour unchanged.
  • Stale docblocks on SiteThemeSettings (reserved keys) and FontCatalog (font count).

Documentation

  • Audited every docs page against source and fixed 35 false or misleading claims. The material ones: the install guide promised Templates/Editor sidebar entries that need ->showAdvancedResources() (off by default); the public-routing guide told you to set domain.primary for wildcard subdomains, which silently resolves the wrong tenant when APP_URL differs; the cache reference had taggable stores backwards (array caches, file — Laravel's default — does not); the editor guide documented a right settings column and "New page"/"Manage" controls that don't exist; and only([...]), FontCatalog::flush(), and Range::unit() were documented with signatures that throw or don't reach CSS.

[1.20.0]

Added

  • SEO & GEO pack. Server-rendered SEO and AI-search optimisation as a first-class feature: /sitemap.xml (honest lastmod + hreflang alternates), /robots.txt with a per-site AI-crawler policy, /llms.txt, and IndexNow submission on publish — all registered only when public_routes is on and each toggleable under filamentcraft.seo. Per-page SEO lives in the editor (Search engine + Social tabs with live SERP/share-card previews, canonical override, indexing toggle) and is stored per locale on templates.seo_json. Site defaults (title suffix, description, share image, organisation profiles, staging noindex) live in Site settings → Search & AI. All head output flows through one SeoResolver chokepoint (Open Graph, Twitter card, hreflang, JSON-LD). Renaming a slug offers a chain-collapsing 301 redirect. Answer bots are never blocked — only training bots are toggleable.
  • Doctor overhaul. filamentcraft:doctor now runs ~35 grouped checks (Environment / Database / Panel / Configuration / Themes / Sections / Content / SEO / Assets / License) with --json for CI and --strict to fail on warnings. New diagnostics include: upgrade-migration columns, wrong-typed config values (quoted .env booleans), tenancy wiring (mode / owner model / single_site_id), cache store existence + tag support, uploads disk + php.ini upload limits, published pages and regions referencing unregistered section types, legacy payloads, published templates without a revision, commerce sections without a Storefront binding, stale published assets after an update, missing Vite manifests, and the SEO gaps above. Doctor also boots each panel's plugin so console runs see the same section/theme registries as browser requests.
  • Color::allowAlpha() now works. The modifier switches the compiled ColorPicker to rgba format so end users can set an opacity; the color transformer reads rgba(…) / rgb(…) strings back into a ColorValue (with ->alpha). It was previously a no-op.
  • RichText::inline() now works. An inline rich-text setting compiles to a RichEditor with a reduced toolbar (bold, italic, underline, strike, link) and no block-level tools — for short fields like an eyebrow or caption. It was previously indistinguishable from the full editor.

Fixed

  • Host section shadows are now stable across panel and public boots. A host section sharing a builtin slug used to win on public routes but lose on panel routes (the editor rendered a different class than the live site), because panel boot blindly re-registered every builtin. Builtins now register only when the slug is free, and disabling them only forgets slugs the builtin itself still holds.
  • A misconfigured filamentcraft.cache.store name degrades to uncached rendering instead of erroring on every cached section render. Doctor reports the bad store name.
  • An unknown public path now 404s instead of falling back to the home template, so a typo'd URL can never be indexed as duplicate homepage content.

Removed

  • Dead enable_dark_mode_toggle setting on the Studio theme. The checkbox affected nothing — the visitor scheme toggle is gated by each section's show_scheme_toggle — so it and its translations were removed.

[1.19.1]

Fixed

  • No per-request log noise for valid configurations. The v1.19.0 runtime warnings for unregistered theme slugs and section slug overrides fired on every render for legitimate setups (token-only Theme rows, intentional built-in shadowing). Both diagnostics now live in php artisan filamentcraft:doctor instead: orphan theme rows keep their WARN (with a note that token-only rows are fine), and the section registry records slug overrides that doctor reports with both class names.

[1.19.0]

Added

  • php artisan filamentcraft:doctor. One command that diagnoses the whole installation — migrations, panel plugin wiring, registered themes vs. Theme DB rows, orphaned theme slugs, live sites (and published homepages when public_routes is on), the storage symlink, and published editor assets — printing a remediation hint under every failed check.
  • php artisan about integration. The Laravel about screen now reports the installed FilamentCraft version, registered theme/section counts, tenancy mode, public-routes state, and whether a license key is set.
  • Enum options for Select and Radio. ->options(MyEnum::class) now works the way Filament's own fields do — values come from the backed enum, labels from HasLabel (falling back to headlined case names).
  • ->helperText() on every setting as a Filament-familiar alias of ->info().
  • Interactive example seed. A bare interactive filamentcraft:install now offers to seed the example site so first-time users land on a working page.

Changed

  • A broken section can no longer take down the whole page. If a registered section throws while rendering (missing Blade view, bad code), the editor preview shows a "failed to render" card naming the error; published pages report the exception and skip the section. Intentional abort()s still propagate.
  • Silent failures now speak. Unknown theme slugs log a warning naming filamentcraft:sync-themes; section slug collisions log both class names; the public 404s explain what to publish/create; Setting/Block id validation errors describe the rule in plain language with an example.
  • Install and make-commands guide the next step. Install names the exact panel-provider file to register the plugin in, points to filamentcraft:starter and doctor, and skips DB-dependent steps when migrations are declined; make:filamentcraft-section only claims auto-discovery when the class actually lands in app/Sections; make:filamentcraft-theme prints the required sync-themes follow-up.
  • Config cleanup. Removed five dead keys (prefix, route_prefix, routes.public_locale_fallback, assets.dist, themes.paths) and documented editor.enabled, cache.ttl/tag_prefix, and domain.primary.
  • Complete IDE autocomplete. The FilamentCraft facade docblock now covers the navigation setters, blueprint registration, advanced-resources toggle, and the correct viteBuild() signature.

Fixed

  • Section::defaults() implementations that omit the settings or blocks key no longer crash the Add-section modal or blueprint seeding.
  • LivewireSection without a $view now fails with the same descriptive LogicException as BladeSection instead of a framework error.

[1.18.0]

Added

  • Host locale URL strategies (localeUrlsUsing). Hosts that resolve the visitor locale from their own routing (locale-prefixed paths, sub-domains) can now register a closure — FilamentCraftPlugin::localeUrlsUsing(fn (Site $site, string $locale, bool $isDefault): ?string) — and the built-in header language switcher plus every LocaleAlternate consumer (hreflang tags, the <x-filamentcraft::locale-switcher> component) emit those URLs instead of the default ?locale=xx query strategy. The header section turns fragment caching off while a resolver is registered, since host URLs are path-dependent.

Fixed

  • Sections now render (and cache) in the requested locale. __() calls in section views that omitted the explicit locale argument resolved against the app locale, so a ?locale=fr page rendered — and per-locale fragment caching then froze — English strings ("Most popular", "Learn more", nav aria labels). SectionRenderer sets the app locale for the duration of every section render and restores it afterwards.
  • Header locale dropdown closes on outside click and Escape instead of staying open until the trigger is clicked again.
  • Checkout shipping fee can no longer be tampered with. The shipping fee / free-shipping threshold the checkout section posts as hidden inputs are now HMAC-signed (ShippingSignature); a devtools edit that zeroes the fee (or strips the fields) rejects the order instead of placing it with free shipping.
  • Checkout re-validates the cart against the live catalog. Lines whose product disappeared after add-to-cart no longer reach the host's placeOrder() (previously they could crash checkout or place mismatched orders), and a line that has gone out of stock since being added rejects the order — mirroring the guard add already enforced.
  • Checkout form field ids are namespaced per section instance (fc-co-name-{sectionId}), so two checkout sections on one page keep valid label associations.
  • A paused site's custom domain fails closed. DomainResolver no longer falls through to the subdomain lookup when a non-live site claims the exact domain — previously an unrelated live site with a matching subdomain could be served under the paused site's host.
  • In-flight setting edits survive editor navigation. A settings-field edit still inside its 400 ms commit debounce was lost when the next click switched the locale, page, or site; pending commits now flush on pointerdown before any navigation handler runs.

[1.17.1]

Fixed

  • Checkout success page 500 on newer Blade compilers. The checkout view mixed @php(...) inline directives with @php … @endphp blocks; on recent Laravel versions two consecutive inline directives after a block mis-compile into a ParseError. All inline @php(...) in the checkout view now use the block form.

[1.17.0]

Added

  • Visitor dark-mode toggle. The Header and Footer sections gained an opt-in sun/moon switcher (show_scheme_toggle) with inline or floating-button placement. Clicking it flips a data-fc-scheme-override attribute on <html>DesignTokenCompiler now pre-renders a pure-CSS override layer for every scheme, so the whole page (pinned sections included) re-tokens to the dark scheme with no framework JS. The choice persists in localStorage and a pre-paint script in the layout head restores it before first paint (no light flash). Accessible (aria-pressed, focus ring), RTL/safe-area-aware floating variant, reduced-motion-friendly transitions, translated in all seven locales, and documented in the Color Schemes guide. The persisted choice is scoped per site, the editor canvas ignores it (authors always see the authored scheme), and floating buttons reparent to <body> so a sticky header's backdrop-filter can't trap them.

[1.16.2]

Fixed

  • Banner/announcement section wrapped awkwardly on narrow screens. The icon broke onto its own line above the text and the floating pill's rounded-full deformed once the copy wrapped. The icon now stays inline with the (centered) text, and the floating card hugs its content with a softer radius on small screens (rounded-2xlrounded-full from sm:).

[1.16.1]

Fixed

  • Mobile/tablet preview squashed on short screens. The device mockup was sized with min(100%, …), so a small viewport height shortened the phone and distorted its aspect ratio. The mockup now renders at its native size and CSS-scales down uniformly to fit the canvas (the same transform approach the desktop shell uses), with a small gutter for its drop shadow. Tall screens still cap at the device's native size.

[1.16.0]

Added

  • Canvas section hover toolbar. Hovering a section in the editor preview now draws a teal outline with a floating toolbar — section name chip plus edit, move up/down, duplicate, hide, and delete — so sections can be managed directly on the canvas without the sidebar. Move buttons disable at the first/last position, locked sections expose only the name and edit, and the selected section keeps a persistent outline + toolbar (the editor now sends section:select to the iframe; its handler previously never received it).
  • section:toggle-hidden protocol message and a data-fc-section-locked wrapper attribute backing the new toolbar.

Changed

  • Sidebar section rows slimmed down. The per-row hover actions (hide, move, duplicate, delete) moved to the canvas toolbar; rows show just the drag handle and label. Hidden sections don't render in the canvas, so their row keeps an always-visible "show" toggle as the way back.

Fixed

  • Settings panel crashed for image settings stored as URL strings. Stored image values support a plain URL string or a {path, alt} map, but both reached Filament's FileUpload raw state unwrapped and fataled in BaseFileUpload::getUploadedFiles() (foreach on a string). Image-typed values — in section settings and repeater blocks — are now coerced to the file-list shape on hydration, with regression tests for both shapes.

[1.15.0]

Fixed

  • Cart quantity update crashed with a TypeError. The storefront cart's quantity stepper posts qty as a string; CartController::update() passed it straight into CartService::setQty(int $qty), and under declare(strict_types=1) PHP refused the coercion. Quantities now cast at the boundary (matching add() and checkout()), with regression tests covering both the increment and the quantity-zero-removes-the-line paths.

Improved

  • Every built-in section now honours every setting it exposes. A full audit of all 32 sections closed the gaps where a control was declared but did not change the render: the four shape values (clean / contained / layered / wireframe) now render four visibly distinct treatments in every section and are independent of surface_style / surface / media_placement; product-listing columns honours its 4 option; the logo wall's tone applies to text logos, not only images; density now scales card padding on mobile, not just desktop; and several other option values that previously rendered identically are now differentiated.
  • Cleaner empty states. Clearing a heading, label, or announcement no longer leaves a broken empty element — primary text nodes across the pack collapse gracefully, matching the established data-fc-hide-empty pattern.
  • Contrast, accessibility, and polish. Removed hardcoded hex colours in favour of theme tokens (contact, store-hero, video); the store-hero banner stays legible when no image is set; product galleries show an active-thumbnail state; disabled buttons no longer animate on hover; the eyebrow hairline is RTL-correct; and imageless media tiles share one refined monogram placeholder instead of a faint icon. The site header CTA now uses the primary-button primitive, and a sticky header respects surface shapes.

[1.14.0]

Added

  • Eleven new built-in sections — the most-used blocks from every major builder.Team (profile cards / large portraits / minimal list, socials, initials fallback), Gallery (grid / masonry / carousel, ratio + caption controls), Timeline (horizontal steps / vertical rail / alternating sides, number / icon / dot markers), Video (YouTube / Vimeo / file; privacy-friendly youtube-nocookie embeds, lazy-loaded, with a JS-free srcdoc cover facade), Articles (card grid or featured + list), Portfolio (grid or featured case study, result-metric badges), Tabs (underline / pills / boxed, top or side placement, full W3C APG tablist semantics with a stacked no-JS fallback), Comparison (semantic 2–3 column table, highlightable "us" column, yes/no/free-text cells), Countdown (live-ticking tiles, expired state, cache-exempt), Locations (map embed with a strict URL allowlist + location cards), and Announcement Bar (full-width bar or floating pill, brand / surface tones, dismissible with per-section persistence). Every section ships Content / Layout / Style controls, four family presets (modern / editorial / bold / elegant), believable defaults, and names translated into all seven bundled languages.
  • Reusable carousel primitive. <x-filamentcraft::carousel> + <x-filamentcraft::carousel.slide> wrap any section content in the same accessible, dependency-free scroll-snap carousel the product carousel uses: W3C APG region/slide semantics, arrow controls, new dot pagination (grouped-button pattern), keyboard-scrollable track, scroll-snap-stop, RTL-aware navigation, and reduced-motion support. Slides-per-view and gap are per-instance CSS variables.
  • Carousel layouts for existing sections. Testimonials and Logo Cloud gained a Carousel layout option, and the Team, Gallery, and Product Carousel sections ride the same primitive.
  • Storefront JS modules (all progressive enhancement, zero dependencies): APG tabs (roving tabindex, RTL-aware arrow keys, Home/End), countdown ticker, and banner dismissal backed by localStorage.

Changed

  • Style-control parity for commerce and form sections. Cart, Checkout, Contact, Newsletter, Category Grid, Product Listing, Product Carousel, and Product Page now expose the same Density control as the content sections (their vertical rhythm was previously hardcoded), and the Contact textarea now uses the .fc-input primitive.
  • Stats Band layout is now a real band — a single shared surface with divided, centered figures — instead of rendering identically to the grid.
  • Carousel slides upgraded to APG semantics (role="group" + aria-roledescription="slide", labelled track) and the track is keyboard-focusable.
  • Leaner settings-panel helper text. Field hints now appear only where the behaviour is non-obvious (magic values, constraints, hidden interactions) and are kept to one short line, instead of restating the label. Trimmed or removed across Hero, Store hero, Video, Cart, Gallery, Banner, Comparison, and Locations.
  • Stronger defaults for the new sections. Gallery blocks that carry a caption but no image now render as designed gradient tiles on the live site (fully empty blocks are still skipped; the dashed upload hint remains editor-only), gallery ships six starter tiles, and Tabs panels default to the contained card frame with the tab's icon leading image-less panels.

Fixed

  • Locations split layout no longer overflows the section. Cards in the map + cards layout stretched to the full grid-row height and painted over whatever came after the section; full-height cards now apply only in the cards-only grid.

Removed

  • The hero's Custom padding control. Vertical rhythm is owned by the Height presets (compact / comfortable / airy) like every other section; a per-section free-form padding override fought the page rhythm and the theme's section-spacing token. Stored values from existing sites are ignored harmlessly. (The Spacing setting type itself is unchanged and remains available to custom sections.)

[1.13.1]

Added

  • Accessible product-carousel controls. The product carousel now ships keyboard- and screen-reader-friendly previous/next controls (labelled, focus-managed, aria-wired and translated into all seven bundled languages), with a config toggle and the supporting CSS/JS.

[1.13.0]

Added

  • E-commerce section pack — turn any FilamentCraft site into a storefront. Seven new built-in sections: Store hero, Category grid, Product carousel, Product listing (with server-side category / price / sort / search filters), Product page, Cart, and Checkout. They are fully data-driven — you choose what to show (a collection, a category, a limit), never the product data itself.
  • Storefront contract + DTOs (ProductData, CategoryData, CatalogQuery, OrderResult, CustomerDetails). Bind your own implementation over your Eloquent models to feed the sections; the package ships NullStorefront as the default so the sections degrade to a tidy "connect your catalog" empty state until a store is wired.
  • JS-free session cart + cash-on-delivery checkout. CartService (session, namespaced per site) stores only product references — prices always resolve server-side from the Storefront, never the client. Plain form-POST cart routes (filamentcraft/cart/{add,update,remove,checkout}) work with no client runtime and never trip Livewire's stateless-update 419. Checkout places the order via Storefront::placeOrder().
  • Commerce CSS primitives in site.css (fc-product-card, fc-price, fc-tag, fc-ratingstars, fc-qty, fc-option/swatch, CSS-only fc-gallery, fc-filter, fc-chip, fc-summary, fc-cartbar, fc-pay, fc-steps) — token-driven, RTL-safe, reduced-motion aware, no hover-scale. Images degrade to a designed gradient placeholder.
  • Storefront UI strings (commerce.*) translated across all seven locales.

Added (core)

  • Section::cacheable() (default true). The renderer skips the fragment cache for sections whose output depends on the request (filters), the session (cart), or a fresh CSRF token (forms) — the listing, product, cart and checkout sections opt out.

[1.12.2]

Changed

  • The elegant starter family now has a simple header and richer content. The header is a single-row split layout (brand left, nav + one CTA right) instead of a tall stacked centered block; the capabilities section is six considered editorial cards instead of three sparse tiles; and the testimonials section shows three quotes instead of one. Only the elegant family changes.

[1.12.1]

Fixed

  • The elegant starter family read as sparse and empty. It now uses comfortable (not airy) density, contained section shapes (real card structure instead of borderless surfaces), and a cards features layout — so the minimal premium aesthetic looks intentional rather than unfinished. The other three families are unchanged.

[1.12.0]

Added

  • Preset-driven starter sites in four style families. Every built-in section now ships four aligned presets — modern, editorial, bold, elegant — sharing slugs across all sections, so picking one family yields a cohesive, on-brand site. A new parametric StarterSiteBlueprint::seed(StarterFamily::Modern, $owner) provisions a complete, published seven-section homepage (hero → logo cloud → features → stats → testimonials → pricing → CTA) plus matching header and footer regions in a single line — the one-liner DX for a tenant-created hook.
  • StarterFamily enum (value doubles as the shared preset slug; ships label/color/icon contracts and ::options() for Filament selects), the filamentcraft:starter command, the idempotent StarterSiteSeeder, and the filamentcraft.starter.family config key.
  • BlueprintSection::fromPreset() and Preset::findIn() — fill a blueprint section from a section's own family preset; the editor's preset picker reuses the same lookup.
  • Multilingual storefront primitives. New <x-filamentcraft::hreflang> (emits rel="alternate" + x-default SEO tags) and <x-filamentcraft::locale-switcher> (a visitor-facing, RTL-aware, theme-token-styled language switcher with native labels), backed by the FilamentCraft\Support\LocaleAlternate value object / builder and Locales::nativeLabel(). Both render nothing for single-locale sites and support custom URL strategies via an urlFor closure (path-prefix, query-param, sub-domain).
  • Reworked editor language switcher. Full keyboard accessibility (Arrow/Home/End, type-ahead, Escape-returns-focus, roving tabindex, role="menu"), aria-current on the active locale, live translation-status (an Empty tag on untranslated locales, an "N of M translated" header, an amber pip on the trigger), an RTL badge, an unsaved-changes confirmation before switching, a copy-content-from-any-language modal, and a Manage-languages shortcut.
  • Localization & RTL guide in the docs, plus a multilingual feature card and differentiator keywords on the docs home page.

Changed

  • The six bundled translation files (fr, es, de, pt, ja, ar) are back to full key parity with English (they had drifted ~46% behind, rendering raw translation keys in the editor for non-English admins). A new parity test guards against future drift.
  • Active-locale resolution is centralised in a shared InteractsWithLocale editor concern, removing the same logic that was duplicated across six Livewire components.

Security

  • The editor active locale (?locale=) is now re-clamped to a site-opted-in code on every request, not just on mount — closing a vector where a tampered locale could persist an unsupported locale bucket into a template's sections_json. Copy-source locales are validated against the site's configured languages as well.

[1.10.2]

Added

  • Configurable editor control density. A new filamentcraft.editor.control_size config (compact | comfortable | spacious, default comfortable) sizes the settings-panel enum/toggle-button controls. The value is projected onto the editor root as data-fc-control-size and drives --fc-ctl-* CSS tokens.

Changed

  • Settings-panel enum buttons are more compact by default. Filament's full-size toggle buttons made a 4-option enum (e.g. section Shape) dominate the narrow rail; the comfortable default is tighter while staying readable, and control_size lets you go smaller or larger.

Fixed

  • Save / Publish actions were pushed off the right edge. Below 1100px the editor topbar reserved ~6.75rem of right padding for the fixed focus-exit button — but the topbar is display:none in immersive mode (the only state where that button shows), so the reservation just left the Discard/Save/Publish buttons floating ~100px short of the edge. They now sit flush at the end at every width.

Fixed

  • Single-site dashboard empty state rendered a full-screen icon. The Website Builder dashboard's "set up your first site" empty state styled its heroicon with Tailwind utility classes (h-7 w-7, etc.). Filament v4 ships precompiled CSS and does not run Tailwind over a plugin's published Blade views, so in a consuming app those classes no-op'd and the icon (an SVG with no intrinsic size) filled the viewport. The dashboard view is now self-contained with inline styles (and Filament's primary CSS vars), so it renders correctly without the host compiling the plugin's Tailwind. Multi-tenant panels were unaffected because a tenant always resolves a site.

[1.10.0]

Added

  • Premium section design layer. A reusable, token-driven set of fc-* primitives now powers a master-grade default look across every built-in section: premium card surfaces with a hairline ring and soft hover lift, tinted icon tiles, badge-style eyebrows, gradient stat numbers, a gradient-ring "most popular" pricing card, decorative radial/mesh/dot-grid backgrounds and aura glows, premium primary/secondary buttons with a focus ring, a pure-CSS logo marquee, and load-in reveal animations. Every effect derives from the --fc-color-* theme tokens (so it tracks any palette and per-section color scheme), is pure CSS (the storefront ships no JS), is gated behind prefers-reduced-motion, uses no hover scale(), is RTL-safe, and defaults to a light/modern look.
  • Logo-cloud "Marquee (auto-scroll)" layout — an infinite, seamless, hover-pausing logo strip with edge fade, alongside the existing grid and single-row layouts.

Changed

  • Every built-in section redesigned to a master-grade default. Hero (aura glow, badge eyebrow, premium CTA, refined split-media frame), Features (icon tiles, hover-lift cards, staggered reveal), Stats (gradient numerals, tabular figures), Logo cloud (correct monochrome→color hover + marquee), Pricing (elevated gradient-ring "popular" card, bottom-aligned CTAs, tinted check rows), Testimonials (quote-mark accent, avatar ring), FAQ (refined accordion with open-state highlight and a progressive ::details-content height animation), CTA (glow + gradient-ring card), Image-Text (premium media frame), Newsletter/Contact (glow card, focus-ring fields), Rich-text and Footer polish.

Fixed

  • Emoji / short-glyph section icons now render. The icon component called svg() for every value and silently dropped anything that wasn't a registered icon name, so emoji-based icons (e.g. ⚙️) in built-in section defaults rendered as empty boxes. Short non-icon glyphs now fall back to a centered text glyph; longer unresolved names still render nothing (to avoid printing a mistyped icon name).
  • Focus mode no longer squashes tablet/mobile previews. Entering full-page focus mode hides the editor topbar via display: none, which dropped it as a grid item and let the canvas body auto-flow into the auto row and collapse to content height — shrinking tablet/mobile device frames (whose height resolves from min(100%, …)) to the iframe's intrinsic ~150px. The outer-grid children are now pinned to their rows so the body always fills the 1fr track. Desktop was unaffected.

[1.9.3]

Changed

  • Command palette polish. Typing now jumps the highlight back to the best match (so Enter runs the right command), recently-used commands surface at the top when the search is empty, Tab / Shift+Tab move the selection, long labels truncate instead of wrapping, and the panel sizes down on small screens.

Accessibility

  • The command palette is now a proper combobox/listbox (aria-activedescendant), so the highlighted command is announced as you arrow through it; its results list has an accessible name. The editor settings slide-over's Page/Site groups are wired to their labels (role="group" + aria-labelledby). Fixed a brief sun-icon flash on the color-scheme toggle during light-mode loads.

[1.9.2]

Changed

  • The ⌘K command palette now shows a per-command icon next to each entry, making it quicker to scan.

[1.9.1]

Added

  • The ⌘K command palette is now discoverable. A search button in the editor toolbar opens it (with a ⌘K tooltip), and the keyboard-shortcuts help panel (?) now lists it.

[1.9.0]

Added

  • A ⌘K / Ctrl+K command palette in the editor. Press ⌘K to fuzzy-search and run any of the editor's actions from one place — add a section, change theme, page/site settings, new/duplicate/ delete page, new site, all pages, open live, save, publish, undo/redo, switch device, toggle auto-save. Full keyboard control (↑/↓ to move, Enter to run, Esc to close), focus-trapped, and styled in the builder's own dark UI. Built on the existing actions — no new server behaviour.

[1.8.0]

Changed

  • The builder-native dialog skin now covers the editor's toasts and dialog section cards too. Filament notifications (save/publish/auto-save toasts) and the section cards inside action dialogs now use the builder's panel tokens, so nothing in the editor's chrome falls back to default Filament styling. Still scoped to the editor only and light/dark-aware.

Accessibility

  • The ⚙ settings slide-over now traps focus while open (focus moves into the panel and stays there until you close it), matching expected dialog behaviour for keyboard and screen-reader users.

[1.7.0]

Changed

  • The editor toolbar's page/site actions are consolidated behind one ⚙ Settings control. The separate "New page" (+) and "Manage" () buttons are replaced by a single gear that opens a builder-native slide-over grouping every page and site action (page settings, new/duplicate/delete page, all pages, site settings, change theme, new site). Save, Discard, and Publish stay as labelled buttons.
  • Action dialogs now match the builder. Filament's modals and slide-overs opened from inside the editor are skinned with the builder's own design tokens (scoped to the editor only, so the rest of the panel is untouched), so changing a theme or editing site settings no longer drops you into a differently-styled dialog. The skin tracks the editor's light/dark scheme.

Changed

  • The "Website builder" nav item now opens the editor directly on the site's homepage. The builder already owns page/site/theme management, so the intermediate list page is no longer the landing — getNavigationUrl() routes to the homepage template's editor, falling back to the dashboard for first-run (no homepage yet). The list remains reachable from the editor's Manage (⋯) → All pages.
  • The editor's "Open live page" control is now icon-only to reclaim toolbar space; the destination URL is shown on hover (tooltip + aria-label) instead of as always-on text.

Added

  • Change theme and All pages in the editor's Manage (⋯) menu — switch the site's theme (reloads the canvas) and jump to the page-management list without leaving the builder.
  • Editor toolbar polish: equal square hit-areas for the icon-only URL controls, a pressed/open state on the New-page and Manage menu triggers, a subtle press feedback and a unified focus-visible ring across all toolbar icon buttons, and a hover cue on the live-page icon. The disabled (unpublished) live link keeps its explanatory tooltip. The view-controls toolbar group gained an accessible name.

Accessibility

  • Newsletter + Contact sections: form errors are now programmatically associated with their inputs (aria-invalid / aria-describedby), success messages are announced via role="status" live regions, the submit button keeps a stable accessible name while loading, and inputs carry autocomplete / inputmode hints.

Developer experience

  • Section stubs (make:filamentcraft-section) now ship commented category() / description() / blocks() / presets() examples so those features are discoverable from the generated file.
  • The testing reference gains a concrete Event::fake() assertion snippet for the shipped section events.

[1.5.0]

Fixed

  • LivewireSection wire actions now hydrate on the published storefront instead of failing with a 419 "page expired". A LivewireSection renders via Livewire::mount(), which stamps the snapshot with the component's conventional (FQCN-derived) name — but that name was not resolvable back to the class on the stateless /livewire/update request, so the first wire:click/wire:submit returned 419 and the section appeared frozen on the live site. The section registry now registers every LivewireSection under a stable Livewire alias (filamentcraft-section.{slug}) at registration time (which runs on every request), so mount and update agree and the round-trip hydrates. Affects any interactive section, built-in or host-app.

Added

  • Two shipped interactive sections — Newsletter (newsletter) and Contact form (contact). FilamentCraft previously shipped only static BladeSections; these are the first built-in LivewireSections. Both validate their input, show a success state, and are enabled by default in the Add Section catalog (honoring the builtin_sections_enabled opt-out). They double as the canonical copyable reference for building your own interactive sections.
  • Event extension points for the interactive sections. On submit, Newsletter dispatches FilamentCraft\Events\NewsletterSubscribed and Contact form dispatches FilamentCraft\Events\ContactFormSubmitted. With no listener they are harmless no-ops (the visitor still sees the success message); add a listener to persist the subscriber, send mail, or forward to a CRM. Each event carries the submitted values, the resolved Site (if any), and the section id.
  • SectionDataFactory::test() testing helper. Builds the SectionData and mounts a LivewireSection as a Livewire Testable in one call, so consumers can drive a section's wire actions without the explicit Livewire::test(..., ['section' => ...]) wiring. Throws for static sections (use make() there). Documented in the testing reference.

[1.4.0]

Fixed

  • The storefront shell now ships Livewire's frontend runtime when a page needs it. Published pages render through a plain view()->render() (not a full-page Livewire response), so Livewire's automatic asset injection never fired — a LivewireSection (or a BladeSection that embeds a Livewire component) painted its initial HTML but had no livewire.js/Alpine to hydrate it, leaving wire:click, wire:loading, and wire:model dead on the live site. The renderer now detects interactivity (wire: or x-data) in the assembled header/body/footer and conditionally emits @livewireStyles
    • @livewireScripts (Alpine ships inside the Livewire bundle, so Alpine-only sections work too). Purely static marketing pages stay JS-free. Manual injection also suppresses Livewire's auto-injection, so there is no double-load.

Added

  • <x-filamentcraft::layout> injects the Livewire/Alpine runtime by default. Custom dynamic pages mounted in the shell (cart, checkout, account, full-page Livewire components) are interactive by nature, so the component defaults to injecting the runtime. Pass :livewire="false" to opt a purely static custom page out.

[1.3.0]

Fixed

  • Interactive LivewireSections now round-trip. A section extending LivewireSection could render its first paint but threw "Property type not supported in Livewire" on the first wire action, because the injected SectionData (and its nested RenderContext) was not Livewire-serializable. Both now implement Livewire\Wireable: SectionData dehydrates to a primitive payload and rebuilds through SectionData::fromArray() (re-resolving the section class, Site, settings, blocks, locale, and color scheme), and RenderContext round-trips route-model bindings as a morph alias + key. wire:click/wire:submit actions on a LivewireSection now work, with $section intact after every request.

Added

  • Docs + test coverage for interactive sections. New Interactive sections (Livewire) guide (including the Livewire/Alpine asset story) and a testing recipe that drives a wire action with Livewire::test(), plus suite coverage that exercises a LivewireSection round-trip and the new Wireable serializers.

[1.2.1]

Changed

  • Spacing input — faithful to the Bagisto Visual spec. The four-sided control now infers its link state from the data when no link flag is stored (all sides equal ⇒ linked), so a plain {top, right, bottom, left} map (the Bagisto storage shape) imports without silently re-syncing asymmetric values. Negative values are fully supported for margin controls (Spacing::make('margin')->min(-80)), and SpacingValue exposes each side as a raw float property ($pad->top) alongside the unit-suffixed ->top() method and ->css() shorthand.

[1.2.0]

Added

  • Self-contained editor — in-editor page & store management. The editor topbar gains a New page button and a Manage menu to create, edit, duplicate, and delete pages and edit store settings without leaving for the Sites/Templates resources. Built on Filament action modals wired into the topbar (<x-filament-actions::modals/>), with a safe delete that reassigns the homepage pointer, refuses to remove the last page, and redirects to a sibling.
  • Spacing setting type. Four-sided padding/margin control with per-side inputs, a link/lock toggle, and min/max/unit options; renders to a CSS shorthand value.
  • Gradient setting type. Linear/radial gradient editor with a live preview, angle dial, and color stops. Stop colours are restricted to hex or var(--fc-color-*) token references so a gradient can track the active scheme.
  • Hero now exposes a background gradient and custom section padding, and its accent override genuinely recolours the eyebrow and call-to-action.

Fixed

  • Settings panel could discard a sibling's structural change. It now reloads the shared draft before persisting a setting/block/page-style edit, so a just-added/removed/reordered section is never clobbered.
  • Dashboard cross-tenant write. The resolved site is now #[Locked] and re-verified through the tenancy resolver before any create/theme write.
  • Tenancy resolution no longer throws in panel-less contexts (console, queue, tests).
  • Keyboard-shortcut help no longer opened-then-closed on a single keypress, and Escape now closes the help overlay.
  • Discard now asks for confirmation when there are unsaved changes, and several hardcoded editor strings (add-section clear, iframe title) are now translatable.

[1.1.0]

Added

  • Light Northline-brand presets across all 12 built-in sections, so a fresh site can be assembled entirely from light-scheme presets.
  • Light/dark editor switcher at the bottom of the editor icon rail.

Fixed

  • Auto-save never fired. The scheduler checked the server-side hasUnsaved computed property through the JS $wire proxy, where it does not exist. Dirtiness is now tracked client-side in Alpine state (fed by draft-synced / fc:live-edit) and armed on load when a dirty draft already exists.
  • Public catch-all route shadowed host and Livewire routes. The GET /{path?} public route is now registered via Route::fallback(), so host-app routes and Livewire 4's frontend asset route always win.
  • Guaranteed 404 after a minimal (no-tenancy) install.templateBelongsToCurrentTenant now authorises unowned template sites when the host has no tenancy configured, fixing "Open in Editor" out of the box.
  • Dist archive was missing runtime JS fallbacks. .gitattributes export-ignored all of resources/js, so consumer installs failed in filament:upgrade (copy(): No such file or directory). Only the TypeScript sources are excluded from the archive now.

Docs

  • Legal pages (terms, privacy, refund policy), regions and blueprints guides, fresh editor screenshots, APP_URL + fallback-routing notes.

[1.0.0]

First commercial release. Sold at filamentcraft.dev (Paddle checkout), installed from the private Composer registry at packages.filamentcraft.dev.

Added

  • Soft-degrade licensing. FilamentCraft\Licensing\License reads FILAMENTCRAFT_LICENSE_KEY; unlicensed installs keep every feature and render a small "Built with FilamentCraft" link on public pages (both the template renderer and the <x-filamentcraft::layout> shell). Nothing is ever blocked, no network calls are made — install-time enforcement happens at the private Composer registry. softLicense(false) / license.soft_degrade => false disables the attribution link. The unused license.cache_ttl config key was removed.

  • Site blueprints + tenant provisioning. SiteBlueprint (theme, pages, regions, locales, publish, site settings) + BlueprintRegion + SiteProvisioner create a complete live site in one transaction — MyBlueprint::provision($owner) from a model observer is the whole tenant-onboarding story. make:filamentcraft-blueprint {name} [--site] scaffolds page and site blueprints. Documented in the "Seeding & Blueprints" guide.

  • Release pipeline. release.yml now gates a v* tag (dist parity + composer check) and creates a GitHub release; the distribution hub imports new tags automatically. .gitattributes export-ignores were extended so customer dist archives stay lean (~590 KB).

  • Dual Filament 4 + 5 / Livewire 3 + 4 support. composer.json constraints broadened to filament/filament: ^4.0|^5.0, livewire/livewire: ^3.0|^4.0, pestphp/pest: ^3.0|^4.0, pestphp/pest-plugin-laravel: ^3.0|^4.0 and pestphp/pest-plugin-livewire: ^3.0|^4.0. Filament v5 ships zero API changes versus v4 (it only exists to allow Livewire 4); the editor's JS now uses the version-agnostic Livewire.hook('morph.updated', …) API alongside the legacy document.addEventListener('livewire:morph.updated', …) listener so post-DOM-patch reboots fire on both Livewire 3 and 4. phpunit.xml.dist sets a deterministic APP_KEY so Laravel 12 + Pest 4 boots without an encryption-key error. CI matrix in tests.yml runs the full Pest suite against both Filament/Livewire pairs (with filament/blueprint auto-removed on the v5 leg, since Blueprint v1.x caps filament/support at ^4.0).

  • Custom dynamic pages — four idiomatic doors, one shell. Host apps can now render any non-template page (cart, checkout, account, lesson player, search results, blog comments, gated downloads) inside the same theme + header region + footer region + fonts + tokens that FilamentCraft templates use. Each adopter picks the door that matches their style:

    • #[Storefront] Livewire attributeFilamentCraft\Attributes\Storefront extends Livewire\Attributes\Layout with the layout name pre-set. Drop it on any full-page Livewire component for zero-ceremony shell wrapping. The raw #[Layout('filamentcraft::layout')] form also works.
    • Route::filamentCraftStorefront(Owner::class, fn () => …) route macro — registers prefix + tenant middleware + Site binding for a whole group in one line. Reads the owner model from filamentcraft.tenancy.owner_model when omitted.
    • <x-filamentcraft::layout> Blade component — the explicit escape hatch with full prop control (:site, :title, :color-scheme, :mode, :locale). Aliasable via Blade::component('your-name', Layout::class).
    • Laravel Folio integrationphp artisan filamentcraft:install --folio scaffolds a starter resources/views/storefront/cart.blade.php and prints the FolioServiceProvider wiring. Zero PHP boilerplate per page after that.
  • ResolveSiteFromTenant middleware (alias filamentcraft.tenant) — resolves the current tenant from a route-param slug, sets it as the Filament tenant when a panel is bootable, and binds the matching live Site to the container. Config-driven so 'filamentcraft.tenant' with no arguments works when filamentcraft.tenancy.owner_model is set.

  • TenantSiteResolver (src/Resolvers/) — singleton that centralises "owner-by-slug → Filament::setTenant() → live Site-by-morph" so the middleware and the Layout component's URL fallback share one implementation instead of duplicating ~30 lines each.

  • Site::forOwner(Model $owner) local scope — polymorphic owner-match helper used by the resolver, replacing two raw ->where('owner_type', …)->where('owner_id', …) chains.

  • TemplateRenderer::buildShell() — extracted public method that returns the shell payload (tokens, header, footer, stylesheets, scripts, fonts, locale, dir, color scheme). Both renderPayload() and the new Layout component funnel through it so there's a single source of truth for the document chrome.

  • Auto-scroll preview on section selection. Opening a section in the editor sidebar (or visiting an editor URL with ?section=…) now smooth- scrolls the preview iframe to that section, using Livewire's morph.updated hook (version-agnostic) for post-patch reboots. Visibility-guard in the iframe handler suppresses the scroll if the section is already in the upper half of the viewport, so clicking a section inside the iframe doesn't snap-back. Consecutive same-id selections are deduped parent-side to skip the per-iframe postMessage fan-out.

Fixed

  • Editor sidebar resize stopped working after page morphs. layout-resize.ts keyed split-grid instances on the body element only — when Livewire / Filament navigation morphed the page tree and replaced the [data-fc-layout-gutter] node, the resize handle silently lost its mousedown listener. Now tracks the gutter element identity in a parallel gutterByBody WeakMap and rebinds when it changes.

  • Route::filamentCraftTenant() shadowed Filament /admin/* routes. The default tenantPattern was ^(?!admin$)[A-Za-z0-9-]+. Because PHP regex $ anchors to end-of-input (the whole URL path), the negative lookahead only blocked the literal segment admin — multi-segment URLs like /admin/acme passed the lookahead, the FC tenant route captured tenantSlug=admin + path=acme, and every Filament panel route at /admin/{tenant}/... 404'd in real integrations. Default pattern is now ^(?!admin\b)[A-Za-z0-9-]+ (word boundary), which correctly rejects both the bare admin segment and admin/anything. Hosts that mount Filament at a non-default path should pass a custom tenantPattern to the macro that excludes their panel prefix too — see docs/guides/custom-dynamic-pages.md §Gotchas. New regression test in tests/Feature/Routing/AdminRouteCoexistenceTest.php.

Changed

  • <title> in filamentcraft::renderer.layout now accepts an optional $title variable, falling back to $site->name (used by the new Layout component for per-page titles in dynamic pages). No behaviour change for existing template renders.

  • PHPStan grew a phpstan-bootstrap.php that registers the filamentcraft:: view namespace + the Route::filamentCraftTenant() and Route::filamentCraftStorefront() macros at analysis time, so namespaced view paths and macro calls resolve cleanly without per-file @phpstan-ignore noise.

Known caveats

  • The v5 + Livewire 4 PHPStan leg is currently marked continue-on-error in static.yml. Pest 4 + Livewire 4 ship stricter generic stubs whose @template TComponent does not propagate through the Livewire facade's @method static test() declaration, surfacing ~26 false-positive errors in test files (Unable to resolve template type, #[Computed] properties missing on instance()). The Filament 4 + Livewire 3 leg remains the strict static-analysis gate. Tracking upstream: re-enable the v5 PHPStan gate once larastan/larastan-livewire ships v4 support or the Livewire facade propagates the template parameter.

  • The --folio install flag scaffolds the starter file and prints the FolioServiceProvider snippet but does NOT auto-edit the host's service provider — Folio's path/uri/middleware wiring is currently a copy- paste step. Track for full automation once a Folio adopter asks.

Tests

  • 719 / 3098 (was 692 / 3041 in 0.1.0). New coverage: layout component rendering + alias support + custom-title + colour-scheme, ResolveSiteFromTenant middleware happy path + config defaults + not-found cases + invalid-owner errors, Route::filamentCraftStorefront route macro behaviour, URL-parameter fallback inside the Layout component with and without custom param names, #[Layout] and #[Storefront] attribute rendering through Livewire's full-page pipeline, --folio flag warning path. v4 leg PHPStan-clean, v5 leg test-clean.

[0.1.0]

First public release. Covers phases 0–6 of the master plan.

Added

  • ScaffoldingFilamentCraftServiceProvider, FilamentCraftPlugin, package config, install command, stubs.
  • Data layer + tenancySite, Theme, Template, TemplateRevision, Region Eloquent models with circular FK split (templates ↔ revisions); TenancyResolver that works without a tenancy package; SiteStatus, TemplateStatus, TemplateType, RegionName, Device enums.
  • Section DSL + registry + transformersAbstractSection, BladeSection, LivewireSection, Setting value object, Field descriptors, SectionRegistry, JSON ↔ runtime transformers, locale buckets.
  • Public renderer + fragment cacheTemplateResolver (exact + dynamic routes), TemplateRenderer with per-section fragment caching, Region rendering, PublicSiteController, SiteContext middleware.
  • Livewire editor shellEditorPage, plus Livewire components Topbar, SectionList, SettingsPanel, Canvas, AddSectionModal, PresetPicker; DraftStore, UndoStack, TemplateState, LocaleBucket, BroadcastPayloadBuilder, AutoSavePreference.
  • Iframe preview + postMessage bus + morphdomEditor/Protocol/Message + MessageType; resources/js/postmessage-bus.ts, iframe-injected.ts, editor.ts, keybindings.ts, layout-resize.ts, protocol.ts, tooltips.ts; AllowSameOriginIframe and InjectEditorScript middleware; PreviewController, SectionRefreshController, TemplateRefreshController.
  • Filament resourcesSiteResource, TemplateResource, ThemeResource (each with List / Create / Edit pages), the FilamentCraftDashboard page, and the form components ColorSchemeTokensField, ColorSchemeGroupField, ColorSchemeGroupEditor, ColorSchemePicker, FontPickerField, IconPicker, TemplateUrlPicker.
  • BlueprintsAbstractBlueprint, BlueprintRegistry, BlueprintSection, BlueprintSeeder, SeedResult, filamentcraft:seed-blueprints artisan command, plugin-level registration API, locked / hidden section flags with sealed-list guards.
  • ThemingThemeRegistry, ThemeContract, filamentcraft:sync-themes command, default token sets, font-picker integration with Bunny Fonts.
  • Multi-localeLocales helper, LocaleAwareSections state slice, empty-state UX (sidebar hint + canvas card), built-in Header section with locale switcher.
  • Built-in section catalogHeader section with mobile-safe wrapping classes.
  • Make commandsmake:filamentcraft-section, make:filamentcraft-theme.
  • Testing & gate — Orchestra Testbench base case, in-memory SQLite, 692 Pest unit + feature tests at 3043 assertions; Pint + PHPStan level 6
    • Pest wired through composer check; CI workflows for tests, static analysis, and committed JS/CSS dist parity.
  • Demo app integration — end-to-end browser test suite running against filamentcraft-demo via Pest 4 + pest-plugin-browser, covering the editor shell, save / publish, section CRUD, drag reorder at 3 viewports, device switcher, keyboard shortcuts, layout resize, breakpoints, file upload, public renderer, multi-tenant isolation, and locked / hidden Blueprint sections.

Notes

  • This release ships without Anystack licence enforcement. The soft-degrade SDK + UX will land in 0.2.0. Until then the package is delivered as-is via the path repository in filamentcraft-demo for internal verification.
  • Documentation (filamentcraft.dev/docs) is not part of this release.