Advanced Fields and Components
| MoonShine Advanced | MoonShine |
|---|---|
| 1.x | 3.x |
| 2.x | 4.x |
composer require moonshine/advanceduse MoonShine\Advanced\Components\Stepper\Stepper;
use MoonShine\Advanced\Components\Stepper\Step;
Stepper::make([
Step::make([
Heading::make('Step 1 content')
], 'Step 1', 'Some description'),
Step::make([
FormBuilder::make()
], 'Step 2', 'Some description'),
Step::make([
// any components
], 'Step 3', 'Some description'),
])Stepper::make([
Step::make(title: 'Step', description: 'Some description')->async('/html')
])Also with events:
Stepper::make([
Step::make(title: 'Step', description: 'Some description')->async('/html', events: [
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'fragment-1')
])
])Events when a step is changing:
Step::make(title: 'Step', description: 'Some description')
->whenChangingEvents([
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'fragment-2')
], once: false)Events when a step is completed:
Step::make(title: 'Step', description: 'Some description')
->whenFinishEvents([
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'fragment-2')
], once: true)The once parameter indicates once the events will be caused or with each change
When all the steps are completed, this set of components will be displayed on the page
Stepper::make([
// ...
], finishComponent: [
Heading::make('Thanks!')
]),Stepper::make([
// ...
], nextText: 'Next step', finishText: 'Finish'),Stepper::make([
// ...
])->changeNextButton(function(ActionButton $btn, int $index) {
return $btn->badge($index);
}),Active default step
Stepper::make([
// ...
])->current(2),Completed by default
Stepper::make([
// ...
])->finished(),You cannot go to the next step, you can switch to the next Schag only using the event (go_to_step_ {index}: {stPper_name})
Step::make()->nextLock(),The transition in the upper navigation is blocked:
Stepper::make([
// ...
])->lock(),Once all steps are completed, the top navigation is locked:
Stepper::make([
// ...
])->lockWhenFinish(),use MoonShine\Advanced\Components\AsyncTabs\AsyncTabs;
use MoonShine\Advanced\Components\AsyncTabs\AsyncTab;
AsyncTabs::make([
AsyncTab::make('Tab 1', '/html'),
AsyncTab::make('Tab 2', '/html')->icon('users'),
]),By default the first tab is opened on every page load. To keep the active tab
in the URL (so that reloads and shared links restore it) enable withUrl():
AsyncTabs::make([
AsyncTab::make('Profile', '/html/profile'),
AsyncTab::make('Security', '/html/security'),
])->withUrl(),
// ?tab=securityThe query key defaults to tab. Each tab's slug defaults to Str::slug($label)
(e.g. User Profile → user-profile). Both can be overridden:
AsyncTabs::make([
AsyncTab::make('Profile', '/html/profile')->slug('me'),
AsyncTab::make('Security', '/html/security')->slug('sec'),
])->withUrl('account'),
// ?account=secNested AsyncTabs (tabs loaded as content of another async tab) are supported
— just give each group a unique query key:
AsyncTabs::make([
AsyncTab::make('Profile', '/html/profile'),
AsyncTab::make('Security', '/html/security'),
])->withUrl('section'),
// inside the /html/security response:
AsyncTabs::make([
AsyncTab::make('Password', '/html/password'),
AsyncTab::make('Devices', '/html/devices'),
])->withUrl('detail'),
// final URL: ?section=security&detail=devicesBy default switching a tab calls history.replaceState to avoid polluting
browser history. Pass pushHistory: true to push a new entry per switch so
that the Back/Forward buttons navigate between tabs:
AsyncTabs::make([...])->withUrl(pushHistory: true),use MoonShine\Advanced\Components\LinkGroup\LinkGroup;
use MoonShine\Advanced\Components\LinkGroup\LinkItem;
LinkGroup::make([
LinkItem::make('/documentation', 'Documentation', 'Some description')->icon('arrow-right'),
// ...
]),use MoonShine\Advanced\Fields\RadioGroup;
RadioGroup::make('Sex')->options([
1 => 'Male',
2 => 'Female',
])->inline(),use MoonShine\Advanced\Fields\CheckboxList;
CheckboxList::make('Plan')->options([
1 => 'Basic',
2 => 'Standard',
3 => 'Pro',
])->inline(),use MoonShine\Advanced\Fields\ButtonGroup;
ButtonGroup::make('Plan')->options([
1 => 'Basic',
2 => 'Standard',
3 => 'Pro',
])->multiple(),use MoonShine\MenuManager\MenuItem;
protected function menu(): array
{
return [
MenuItem::make('Users', UserResource::class)->spa(),
];
}public function stepForm(MoonShineRequest $request): MoonShineJsonResponse
{
$request->validate([
'name' => ['required'],
'email' => ['required'],
]);
return MoonShineJsonResponse::make()->events([
'go_to_step_2:dashboard'
]);
}
protected function components(): iterable
{
return [
Stepper::make([
Step::make([
FormBuilder::make()
->name('step_1_form')
->asyncMethod('stepForm')
->fields([
Grid::make([
Column::make([
Box::make([
Text::make('Name'),
Email::make('Email'),
RadioGroup::make('Sex')->options([
1 => 'Male',
2 => 'Female',
])->inline(),
])
])->columnSpan(6),
Column::make([
Box::make([
CheckboxList::make('Job title')->options([
1 => 'Developer',
2 => 'Team lead',
]),
ButtonGroup::make('Plan')->options([
1 => 'Free',
2 => 'Basic',
3 => 'Pro',
]),
])
])->columnSpan(6)
])
])
->hideSubmit()
], 'Step 1', 'Tell us about yourself')->nextLock()->whenChangingEvents([
AlpineJs::event(JsEvent::FORM_SUBMIT, 'step_1_form')
]),
Step::make([
AsyncTabs::make([
AsyncTab::make('How to use the project', '/html'),
AsyncTab::make('User agreement', '/html'),
]),
], 'Step 2', 'Rules')->icon('users'),
Step::make([], 'Step 3', 'Finishing')->async('/html', events: [
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'time')
])->whenFinishEvents([
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'time')
]),
], [
Heading::make('Thanks!'),
LinkGroup::make([
LinkItem::make('#', 'Link 1', 'Description 1')->icon('arrow-right'),
LinkItem::make('#', 'Link 2'),
])
], 'Next', 'Finish')->name('dashboard')->lock(),
Fragment::make([
time()
])->name('time'),
];
}