PHPackages                             hitaqnia/haykal-filament - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. hitaqnia/haykal-filament

ActiveLibrary[Admin Panels](/categories/admin)

hitaqnia/haykal-filament
========================

Haykal Filament foundation: BasePanel, BaseResource, base pages, Huwiya login page, translatable tabs, base theme, curated plugin set.

v2.0.4(2mo ago)081↓66.7%1proprietaryCSSPHP ^8.3

Since Apr 25Pushed 2mo agoCompare

[ Source](https://github.com/hitaqnia/haykal-filament)[ Packagist](https://packagist.org/packages/hitaqnia/haykal-filament)[ RSS](/packages/hitaqnia-haykal-filament/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (6)Versions (7)Used By (1)

hitaqnia/haykal-filament
========================

[](#hitaqniahaykal-filament)

Filament foundation for HiTaqnia Laravel applications.

`haykal-filament` ships the base classes, middlewares, theme, and Huwiya integration that every HiTaqnia Filament panel uses. Installing this package gives an application a complete panel baseline — authentication via Huwiya, tenant-aware middleware stack, opinionated UI defaults, a shared theme, and a convention-driven resource discovery layout — so panel definitions stay focused on the concrete resources, pages, and navigation of each panel.

---

Table of contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [What this package provides](#what-this-package-provides)
- [Installation](#installation)
- [Configuration](#configuration)
- [Defining panels](#defining-panels)
- [Global Filament defaults](#global-filament-defaults)
- [Resources and pages](#resources-and-pages)
- [Theming](#theming)
- [Translatable forms](#translatable-forms)
- [Mapbox components](#mapbox-components)
- [Customization](#customization)
- [Testing](#testing)

---

Requirements
------------

[](#requirements)

- PHP 8.3 or later
- Laravel 13 or later
- `filament/filament` 5.5 or later
- `hitaqnia/haykal-core` (shared kernel)
- A running instance of the Huwiya Identity Provider

---

What this package provides
--------------------------

[](#what-this-package-provides)

### Panel foundation

[](#panel-foundation)

ClassPurpose`HiTaqnia\Haykal\Filament\BasePanel`Abstract `PanelProvider` that wires the shared middleware stack, Huwiya login, sensible defaults (SPA, full-width, light theme, no global search), convention-driven resource/page discovery (`app/Panels/`), and optional tenancy.`HiTaqnia\Haykal\Filament\BaseFilamentServiceProvider`Abstract application-side provider that applies HiTaqnia's global Filament UX defaults: locked-down modals, no "Create another" action, slide-over column manager + filters, and "Click to copy" tooltips with em-dash placeholders for copyable text columns/entries.`HiTaqnia\Haykal\Filament\Auth\HuwiyaConsentLogin`Consent-style login page — renders a single button that redirects the browser to the Huwiya OAuth authorization endpoint for the active panel's guard. Translated through `haykal-filament::auth.login.*` (en / ar / ku).### Resources and pages

[](#resources-and-pages)

ClassPurpose`HiTaqnia\Haykal\Filament\Resources\BaseResource`Abstract Filament resource with translation-key-driven UI metadata (`panels/{panel}/resources/{resource}.*`).`HiTaqnia\Haykal\Filament\Resources\Pages\BaseListPage`List page that enables the `custom` tabs style hook used by the base theme.`HiTaqnia\Haykal\Filament\Resources\Pages\BaseCreatePage`Create page with Filament's "Create another" action suppressed by default.`HiTaqnia\Haykal\Filament\Resources\Pages\BaseEditPage`Edit page with a read-only fallback for view-only users.### Forms

[](#forms)

ClassPurpose`HiTaqnia\Haykal\Filament\Forms\TranslatableTabs`Tabbed multi-language editor for `spatie/laravel-translatable` attributes, with per-locale icon state and configurable required-language policy.### Mapbox (form fields + infolist entries)

[](#mapbox-form-fields--infolist-entries)

ClassPurpose`HiTaqnia\Haykal\Filament\Mapbox\Components\MapboxLocationPicker`Form field that captures a `{lng, lat}` pair via a draggable marker.`HiTaqnia\Haykal\Filament\Mapbox\Components\MapboxLocationViewer`Read-only infolist entry that displays a stored `{lng, lat}` location.`HiTaqnia\Haykal\Filament\Mapbox\Components\MapboxPolygonsDrawer`Form field that captures a GeoJSON `FeatureCollection` of polygons drawn on the map. Supports `maxPolygons()` cap.`HiTaqnia\Haykal\Filament\Mapbox\Components\MapboxPolygonsViewer`Read-only infolist entry that renders a stored GeoJSON `FeatureCollection`.`HiTaqnia\Haykal\Filament\Mapbox\Concerns\InteractsWithMapbox`Fluent configuration trait shared by all four components (container, height, style, center, zoom, navigation control).### Middlewares

[](#middlewares)

AliasClassPurpose`haykal.filament.tenancy``Http\Middlewares\FilamentTenancyMiddleware`Propagates Filament's resolved tenant into Haykal's `Tenancy` context.### Theming and assets

[](#theming-and-assets)

ResourceNotes`resources/css/base-theme.css`Loaded directly from the vendor path by every scaffolded panel theme. Updates propagate through `composer update` — no republishing required. Publishable under `haykal-filament-theme` only when an application needs to fork the file for per-application overrides.`config/haykal-filament-icons.php`Merged into `config.filament.icons` on register; publishable under `haykal-filament-icons`.`stubs/panel-theme.css.stub`Publishable under `haykal-filament-stubs`; consumed by the publish-theme command.### Console commands

[](#console-commands)

CommandPurpose`haykal:publish-theme {panel} {--force}`Scaffolds a per-panel theme entry file at `resources/css/filament//theme.css` that `@import`s Filament's default theme and the Haykal base theme directly from the vendor directory and sets up the Tailwind 4 `@source` directives for the panel's PHP and Blade paths.---

Installation
------------

[](#installation)

With `hitaqnia/haykal-core` already wired (see its README), require this package alongside:

```
composer require hitaqnia/haykal-filament
```

That single require is enough — Phosphor icons (`codeat3/blade-phosphor-icons` via [`tonegabes/filament-phosphor-icons`](https://github.com/tonegabes/filament-phosphor-icons)) are pulled transitively, so every alias declared in `config/haykal-filament-icons.php` resolves out of the box. The `ToneGabes\Filament\Icons\Enums\Phosphor` enum is also available for typed icon references in resources, navigation items, and form components.

---

Configuration
-------------

[](#configuration)

### 1. Register the Huwiya web guard

[](#1-register-the-huwiya-web-guard)

In `config/auth.php`, register a guard for every panel that uses Huwiya authentication. The guard driver must be `huwiya-web`:

```
'guards' => [
    // ... existing guards ...

    'web' => [
        'driver' => 'huwiya-web',
        'provider' => 'users',
    ],
],
```

Panels may each use their own named guard (`admin`, `residents`, …). Filament resolves the guard for the active panel via `Filament::getAuthGuard()`.

### 2. Scaffold the panel theme

[](#2-scaffold-the-panel-theme)

Run the publish-theme command once per panel:

```
php artisan haykal:publish-theme admin
```

The command scaffolds `resources/css/filament/admin/theme.css`. The scaffold `@import`s Filament's default theme and the Haykal base theme **directly from the vendor directory**, plus the correct Tailwind 4 `@source` directives for the panel's paths. Because both imports reference vendor paths, updates to either flow through `composer update` without republishing. Register the panel theme in `vite.config.js`:

```
laravel({
    input: [
        'resources/css/app.css',
        'resources/js/app.js',
        'resources/css/filament/admin/theme.css',
    ],
});
```

Wire the panel theme through `BasePanel::customizePanel()`:

```
protected function customizePanel(Panel $panel): Panel
{
    return $panel->viteTheme('resources/css/filament/admin/theme.css');
}
```

### 3. Publish the icon overrides (optional)

[](#3-publish-the-icon-overrides-optional)

Icon overrides are merged into `config.filament.icons` automatically. Publish the config file only if per-application tweaks are needed:

```
php artisan vendor:publish --tag=haykal-filament-icons
```

---

Defining panels
---------------

[](#defining-panels)

Subclass `BasePanel` for every panel. The minimum viable panel declares only an id and a customization hook; everything else — login page, middleware stack, plugins, defaults — is inherited.

```
namespace App\Providers\Panels;

use App\Models\Complex;
use Filament\Panel;
use HiTaqnia\Haykal\Filament\BasePanel;

final class ManagementPanelProvider extends BasePanel
{
    protected function getId(): string
    {
        return 'management';
    }

    protected function customizePanel(Panel $panel): Panel
    {
        return $panel
            ->brandName('Management')
            ->viteTheme('resources/css/filament/management/theme.css');
    }

    protected function tenantModel(): ?string
    {
        return Complex::class;
    }

    protected function tenantSlugAttribute(): ?string
    {
        return 'slug';
    }
}
```

Register the provider in `bootstrap/providers.php`. Panels without tenancy (super-admin dashboards, system settings) return `null` from `tenantModel()` and skip the tenant middleware stack.

### Multiple tenant types: one panel per type

[](#multiple-tenant-types-one-panel-per-type)

Filament binds exactly one tenant model per panel, so applications with multiple tenant types (for example, **Agency** and **Development Company**) implement **one panel per type**. Each panel declares its own tenant model, middleware stack, login route, and URL prefix; users working with Agencies sign in at `/agency/...` and never see Developer resources, and vice versa.

```
final class AgencyPanelProvider extends BasePanel
{
    protected function getId(): string { return 'agency'; }

    protected function tenantModel(): ?string { return Agency::class; }
    protected function tenantSlugAttribute(): ?string { return 'slug'; }

    protected function customizePanel(Panel $panel): Panel { /* ... */ }
}

final class DevelopmentCompanyPanelProvider extends BasePanel
{
    protected function getId(): string { return 'developers'; }

    protected function tenantModel(): ?string { return DevelopmentCompany::class; }
    protected function tenantSlugAttribute(): ?string { return 'slug'; }

    protected function customizePanel(Panel $panel): Panel { /* ... */ }
}
```

`FilamentTenancyMiddleware` stores whichever tenant the active panel resolves into `Tenancy::setTenantId(...)` as a single value — only one tenant type is active per request. Resources on each panel declare their own `$tenantForeignKey` (see `haykal-core`'s "Multiple tenant types" section) so queries filter on the correct column (`agency_id` for `Property`, `developer_id` for `Project`) against that single active id.

### Hooks exposed by `BasePanel`

[](#hooks-exposed-by-basepanel)

HookDefaultPurpose`getId()`*(abstract)*Unique panel identifier. Drives routing, session scoping, and resource discovery.`customizePanel(Panel)`*(abstract)*Apply panel-specific branding, plugins, navigation, and theme.`loginPage()``HuwiyaConsentLogin::class`Override to replace the Huwiya consent page with a custom page (auto-redirect, custom layout, …).`tenantModel()``null`Concrete Tenant model for this panel, or `null` for tenant-less panels.`tenantSlugAttribute()``null`Column on the tenant model used as the URL slug. `null` falls back to the primary key.`defaultPlugins()`SpatieTranslatableOverride to install a different base plugin set.`fontFamiliesByLocale()``en→Outfit`, `ar→Tajawal`, `ku→Noto Sans Arabic` (default `Outfit`)Override the locale → font family map applied through `Panel::font(...)`.`fontFamilyForLocale($locale)`reads the mapResolves the family for a single locale; rarely needs an override on its own.`getName()``Str::studly(id)`Derives the directory name for resource discovery. Override for custom layouts.### Locale-aware fonts

[](#locale-aware-fonts)

`BasePanel` calls Filament's `Panel::font(...)` with a closure that resolves the font family from the active locale on every render — switching the user's language switches the panel's typography on the next request. Defaults:

LocaleFont`en` (and any unknown locale)Outfit`ar`Tajawal`ku`Noto Sans ArabicFonts load through Filament's [`BunnyFontProvider`](https://fonts.bunny.net) (the Google Fonts mirror Filament ships with), so no app-side font hosting or build-step is required.

To swap fonts per locale, override `fontFamiliesByLocale()`:

```
final class ManagementPanelProvider extends BasePanel
{
    // ...

    protected function fontFamiliesByLocale(): array
    {
        return [
            'default' => 'Inter',     // every locale not listed below falls back here
            'ar'      => 'Cairo',
            'ku'      => 'Vazirmatn',
        ];
    }
}
```

The `'default'` key is the safety net — any locale not in the map falls through to it.

---

Global Filament defaults
------------------------

[](#global-filament-defaults)

`BaseFilamentServiceProvider` is an application-side provider that applies HiTaqnia's shared Filament UX defaults across every panel. Subclass it in your application, register the subclass in `bootstrap/providers.php`, and the defaults boot once per request.

```
namespace App\Providers;

use HiTaqnia\Haykal\Filament\BaseFilamentServiceProvider;

final class FilamentServiceProvider extends BaseFilamentServiceProvider
{
    // Inherit every default. Override individual configure*() hooks
    // when an app needs to relax or extend a single concern.
}
```

### What the base applies

[](#what-the-base-applies)

HookDefault behavior`configureModalDefaults()``ModalComponent::closedByClickingAway(false)` — modals never auto-close on outside click.`configureActionDefaults()``CreateAction` defaults to `createAnother(false)`.`configureTableDefaults()`Column manager and filters render in a slide-over with no cancel button; filters use `FiltersLayout::Modal`.`configureTextDefaults()``TextColumn` and `TextEntry` get an em-dash (`—`) placeholder, plus a "Click to copy" tooltip on copyable instances. The tooltip resolves through the package translation namespace `haykal-filament::copyable.tooltip` (English / Arabic / Kurdish ship in the box).Per-call configuration always wins — calling `->placeholder('...')` or `->tooltip(...)` on a column or entry overrides the default for that instance.

### Extending

[](#extending)

Each concern is its own `protected` method, so an app subclass replaces only what it needs:

```
final class FilamentServiceProvider extends BaseFilamentServiceProvider
{
    // Allow modals to close on outside click in this app.
    protected function configureModalDefaults(): void
    {
        ModalComponent::closedByClickingAway(true);
    }

    // Add an extra default on top of the base's text defaults.
    protected function configureTextDefaults(): void
    {
        parent::configureTextDefaults();

        TextColumn::configureUsing(static function (TextColumn $column): void {
            $column->size(TextColumn\TextColumnSize::Small);
        });
    }
}
```

To skip a hook entirely, override it with an empty body. To replace a tooltip translation, either change the active locale or publish the package translations and edit them locally:

```
php artisan vendor:publish --tag=haykal-filament-translations
```

Published files land at `lang/vendor/haykal-filament/{en,ar,ku}/copyable.php`.

---

Resources and pages
-------------------

[](#resources-and-pages-1)

Every Haykal resource extends `BaseResource` and leverages translation-key conventions for its labels:

```
namespace App\Panels\Management\Resources;

use App\Models\Unit;
use HiTaqnia\Haykal\Filament\Resources\BaseResource;
use HiTaqnia\Haykal\Filament\Resources\Pages\BaseCreatePage;
use HiTaqnia\Haykal\Filament\Resources\Pages\BaseEditPage;
use HiTaqnia\Haykal\Filament\Resources\Pages\BaseListPage;

final class UnitResource extends BaseResource
{
    protected static ?string $model = Unit::class;

    public static function getPages(): array
    {
        return [
            'index' => BaseListPage::route('/'),
            'create' => BaseCreatePage::route('/create'),
            'edit' => BaseEditPage::route('/{record}/edit'),
        ];
    }
}
```

Labels resolve from `lang/en/panels/management/resources/units.php`:

```
return [
    'model' => [
        'singular' => 'Unit',
        'plural' => 'Units',
    ],
    'navigation' => [
        'label' => 'Units',
        'group' => 'Property',       // optional
        'parent' => 'Complex',       // optional
    ],
];
```

---

Theming
-------

[](#theming)

`resources/css/base-theme.css` is the single shared theme — an opinionated, fully-skinned Filament look inspired by polished SaaS dashboards: dark near-black sidebar with orange accents, light airy content area, flat surfaces (no shadows except on overlays), rounded corners, and gentle motion. Every panel imports it directly from the vendor directory, so updates flow through `composer update`.

The `haykal:publish-theme` command scaffolds a per-panel theme file; subsequent runs skip existing files unless `--force` is passed. A scaffolded panel theme looks like:

```
@import '../../../../vendor/filament/filament/resources/css/theme.css';
@import '../../../../vendor/hitaqnia/haykal-filament/resources/css/base-theme.css';

@source '../../../../app/Panels/Management/**/*.php';
@source '../../../../resources/views/filament/management/**/*.blade.php';

/* Management panel overrides go below. */
```

Tailwind 4 CSS-first configuration lives entirely in the panel theme file — the package does not publish any Tailwind config. Extend the `@source` list for application-specific content paths.

### Re-skinning via tokens

[](#re-skinning-via-tokens)

The base theme exposes its color/radius/elevation system as CSS tokens declared in a `@theme {}` block. Override any of them in a panel's own `@theme {}` block placed *after* the `@import` to re-skin without forking the file:

```
@import '../../../../vendor/filament/filament/resources/css/theme.css';
@import '../../../../vendor/hitaqnia/haykal-filament/resources/css/base-theme.css';

@source '../../../../app/Panels/Management/**/*.php';

@theme {
    --filament-primary-rgb: 16 129 105;   /* swap accent */
    --filament-shell:       #0c1117;      /* darker sidebar */
    --filament-radius:      1rem;         /* rounder cards */
}
```

### Forking

[](#forking)

When token overrides aren't enough, publish the file:

```
php artisan vendor:publish --tag=haykal-filament-theme
```

After publishing, update each panel theme's `@import` to point at the local copy (`resources/css/haykal/base-theme.css`). **This opts out of upstream updates** — prefer the `@theme {}` token-override approach whenever the change can be expressed that way.

### Token reference

[](#token-reference)

Every variable below is declared in the base theme's `@theme {}` block.

#### Shell — the dark sidebar / app frame

[](#shell--the-dark-sidebar--app-frame)

The "shell" tokens describe the dark surface on the left edge: the sidebar background, its borders, and the text colors that sit on top of it.

TokenDefaultPurpose`--filament-shell``#0e0f12`Sidebar background.`--filament-shell-soft``#17191e`Slightly lighter shell tone (reserved).`--filament-shell-elevated``#1c1e24`Active sidebar item card background.`--filament-shell-line``#23262d`Hairline borders on the shell.`--filament-shell-line-strong``#2a2d35`Stronger border (active item).`--filament-shell-text``#f3f4f6`Primary text color on the shell.`--filament-shell-muted``#9ca3af`Secondary text / inactive icons.`--filament-shell-dim``#6b7280`Tertiary text (group labels, chevrons).#### Canvas — the light content area

[](#canvas--the-light-content-area)

The "canvas"/"surface" tokens describe everything to the right of the sidebar: the page background, cards, table chrome, dividers, and text colors on top of them.

TokenDefaultPurpose`--filament-canvas``#ffffff`Page background.`--filament-surface``#ffffff`Card / section / table body background.`--filament-surface-soft``#fafbfc`Subtle alternate surface (table head, hover row).`--filament-line``#eef0f3`Default hairline divider.`--filament-line-strong``#e2e6ec`Stronger border (inputs, gray buttons).`--filament-ink``#0f1620`Primary text color on canvas.`--filament-ink-soft``#4a5568`Body text, table cells.`--filament-ink-muted``#8a96a8`Secondary text, placeholders, hints.#### Radius

[](#radius)

TokenDefaultPurpose`--filament-radius-sm``0.625rem`Buttons, inputs, pills.`--filament-radius``0.875rem`Cards, sections, tables.`--filament-radius-lg``1.125rem`Large surfaces (reserved).#### Elevation

[](#elevation)

The theme is intentionally flat — no ambient shadows on resting surfaces. Only floating layers (modals, dropdowns, notifications) get a single soft lift.

TokenDefaultPurpose`--filament-shadow-none``0 0 #0000`Explicit zero shadow (use to neutralize Filament defaults).`--filament-shadow-overlay`soft liftSingle shadow applied to floating layers (dropdowns, notifications).#### Motion

[](#motion)

TokenDefaultPurpose`--filament-ease``cubic-bezier(0.32, 0.72, 0.32, 1)`Shared easing curve for hover transitions across buttons, sidebar items, sort headers, dropdowns, etc.---

Translatable forms
------------------

[](#translatable-forms)

Multi-language form fields belong inside `TranslatableTabs`:

```
use HiTaqnia\Haykal\Filament\Forms\TranslatableTabs;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;

TranslatableTabs::make('translations')
    ->languages(config('app.supported_locales'))
    ->primaryLanguage('ar')
    ->requirePrimaryLanguageOnly()
    ->fields([
        TextInput::make('name')->required(),
        Textarea::make('description'),
    ]);
```

The component clones each declared field per locale, binding state paths to `.`. Tab icons reflect state at a glance: filled (check), required-but-empty (warning), or optional-and-empty (dashed circle).

---

Mapbox components
-----------------

[](#mapbox-components)

Four components cover every Mapbox use case encountered across HiTaqnia projects. All four share the same fluent configuration API through the `InteractsWithMapbox` trait.

### Configuration

[](#configuration-1)

Add a Mapbox access token to `.env`:

```
MAPBOX_TOKEN=pk.your-mapbox-access-token
```

Publish the config only when overrides are needed — the token is already read from `MAPBOX_TOKEN` through the package default:

```
php artisan vendor:publish --tag=haykal-filament-mapbox-config
```

### Location picker (form field)

[](#location-picker-form-field)

Captures a `{lng, lat}` coordinate pair from a draggable marker. Binds to a JSON column or any cast that accepts an associative array.

```
use HiTaqnia\Haykal\Filament\Mapbox\Components\MapboxLocationPicker;

MapboxLocationPicker::make('coordinates')
    ->mapStyle('mapbox://styles/mapbox/streets-v12')
    ->mapCenter([44.3661, 33.3152])  // Baghdad
    ->mapZoom(12)
    ->mapHeight(500)
    ->navigationControl();
```

Stored shape:

```
{ "lng": 44.3712, "lat": 33.3203 }
```

### Location viewer (infolist entry)

[](#location-viewer-infolist-entry)

Renders a stored `{lng, lat}` as a read-only map marker.

```
use HiTaqnia\Haykal\Filament\Mapbox\Components\MapboxLocationViewer;

MapboxLocationViewer::make('coordinates')
    ->mapStyle('mapbox://styles/mapbox/satellite-v9')
    ->mapHeight(400);
```

### Polygons drawer (form field)

[](#polygons-drawer-form-field)

Captures a GeoJSON `FeatureCollection` of user-drawn polygons. `maxPolygons()` caps how many the user can create; `-1` (the default) means unlimited.

```
use HiTaqnia\Haykal\Filament\Mapbox\Components\MapboxPolygonsDrawer;

MapboxPolygonsDrawer::make('boundaries')
    ->maxPolygons(3)
    ->mapCenter([44.3661, 33.3152])
    ->mapZoom(13);
```

Stored shape:

```
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Polygon", "coordinates": [[[...]]] },
      "properties": {}
    }
  ]
}
```

### Polygons viewer (infolist entry)

[](#polygons-viewer-infolist-entry)

Renders a stored `FeatureCollection` read-only and auto-fits the map to the polygons.

```
use HiTaqnia\Haykal\Filament\Mapbox\Components\MapboxPolygonsViewer;

MapboxPolygonsViewer::make('boundaries')
    ->mapHeight(500);
```

### Shared fluent API

[](#shared-fluent-api)

Every Mapbox component accepts these setters through `InteractsWithMapbox`:

SetterDefaultPurpose`mapContainer(string)`Field nameDOM id of the map container.`mapHeight(int|Closure)``400`Pixel height of the map.`mapStyle(string)`Mapbox defaultAny `mapbox://styles/...` URL.`mapCenter(array|Closure)``[-74.5, 40]``[lng, lat]` for the initial viewport. Ignored when state is loaded and polygons auto-fit.`mapZoom(int|Closure)``9`Initial zoom level.`navigationControl(bool|Closure)``false`Show Mapbox's zoom/compass controls.### Reactive configuration via closures

[](#reactive-configuration-via-closures)

`mapHeight`, `mapCenter`, `mapZoom`, and `navigationControl` accept either a static value or a Filament-style closure. Closures resolve the same named/typed injections as any other Filament closure (`$state`, `$get`, `$set`, `$record`, `$livewire`, …) and are re-evaluated on every render — pair them with a `live()` source field to drive the map from another component:

```
use Filament\Forms\Components\Select;
use Filament\Schemas\Components\Utilities\Get;
use HiTaqnia\Haykal\Filament\Mapbox\Components\MapboxLocationPicker;

Select::make('city')
    ->options([
        'baghdad' => 'Baghdad',
        'erbil'   => 'Erbil',
    ])
    ->live();

MapboxLocationPicker::make('coordinates')
    ->mapCenter(fn (Get $get): array => match ($get('city')) {
        'baghdad' => [44.3661, 33.3152],
        'erbil'   => [44.0090, 36.1900],
        default   => [-74.5, 40.0],
    })
    ->mapZoom(fn (Get $get): int => $get('city') ? 12 : 9);
```

Switching the `city` Select re-renders the picker with a fresh center and zoom — no manual `afterStateUpdated()` plumbing required.

### Assets

[](#assets)

Both the Mapbox GL CSS (`mapbox-gl.css`, `mapbox-gl-draw.css`) and the compiled Alpine bundles for each component are registered with Filament automatically via `HaykalFilamentServiceProvider`. The bundles are loaded on request — pages that do not reference a Mapbox component pay no runtime cost.

The bundles are built from `resources/js/mapbox/components/*.js` with esbuild and committed under `resources/js/mapbox/dist/`. After editing any source module, refresh them from inside the package:

```
cd packages/haykal-filament
npm install
npm run build
```

### Right-to-left text

[](#right-to-left-text)

Every component initializes [`mapbox-gl-rtl-text`](https://github.com/mapbox/mapbox-gl-rtl-text) on the first map render, so Arabic, Hebrew, and Persian labels join correctly instead of rendering as disconnected glyphs. The plugin is registered with lazy-loading (the third argument to `setRTLTextPlugin`), so its script is only fetched the first time a tile actually contains RTL text — non-RTL maps pay nothing.

The registration is idempotent across all four components (Mapbox throws if `setRTLTextPlugin` runs twice), and the plugin URL is pinned to the version embedded in the package bundles. No application configuration is required.

---

Customization
-------------

[](#customization)

### Overriding hooks

[](#overriding-hooks)

Every override point is method-based — subclass `BasePanel`, override the relevant hooks, and the rest inherits from the base. See the [Hooks exposed by `BasePanel`](#hooks-exposed-by-basepanel) table above.

### Publishable resources

[](#publishable-resources)

TagContents`haykal-filament-theme``resources/css/base-theme.css` → `resources/css/haykal/base-theme.css` (fork only when the base needs app-specific overrides; prefer overriding individual tokens via `@theme {}`).`haykal-filament-icons``config/haykal-filament-icons.php` → `config/haykal-filament-icons.php``haykal-filament-mapbox-config``config/mapbox.php` → `config/mapbox.php` (only needed when overriding the default `MAPBOX_TOKEN` env binding).`haykal-filament-stubs``stubs/panel-theme.css.stub` → `resources/stubs/haykal/panel-theme.css.stub``haykal-filament-translations``lang/{en,ar,ku}/{auth,copyable}.php` → `lang/vendor/haykal-filament/{en,ar,ku}/...` (override the consent-login texts and the "Click to copy" tooltip strings).### Fixed conventions

[](#fixed-conventions)

ConventionCurrent valueLocationResource directory layout`app/Panels//{Resources,Pages,Widgets,Clusters}``BasePanel::panel()`Translation key prefix`panels/{panel}/resources/{resource-kebab-plural}``BaseResource::getTranslationKeyPrefix()`---

Testing
-------

[](#testing)

Run the monorepo suite from the repository root:

```
composer test
```

Tests use Orchestra Testbench with an in-memory SQLite database. Filament and Livewire service providers must be registered on the test case's `getPackageProviders()` list; see `tests/Filament/FilamentTestCase.php` for the canonical setup.

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance85

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

6

Last Release

77d ago

Major Versions

v1.0.0 → v2.0.02026-05-05

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/48333830?v=4)[Mahdi Mohammed](/maintainers/mahdi-mk)[@mahdi-mk](https://github.com/mahdi-mk)

---

Top Contributors

[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (7 commits)")

### Embed Badge

![Health badge](/badges/hitaqnia-haykal-filament/health.svg)

```
[![Health](https://phpackages.com/badges/hitaqnia-haykal-filament/health.svg)](https://phpackages.com/packages/hitaqnia-haykal-filament)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.8k](/packages/rawilk-profile-filament-plugin)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)[tapp/filament-lms

193.5k](/packages/tapp-filament-lms)[a2insights/filament-saas

Filament Saas for A2Insights

191.7k](/packages/a2insights-filament-saas)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
