weblabormx / world-ui
UI Component library built on top of WireUI that implement Weblabor World service out of the box
Requires
- php: ^8.1
- illuminate/support: *
- weblabormx/world: ^1.0.8
- wireui/wireui: ^2.4.3
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
World UI is a component library, based on WireUI for easy implementation with Weblabor World API.
Install
Install the package through composer using:
composer require weblabormx/world-ui
Then, configure on your config/services.php your World API Token.
[
//...
'weblabor' => [
'world' => [
'token' => env('WEBLABOR_WORLD_TOKEN'),
// 'endpoint' => env('WEBLABOR_WORLD_ENDPOINT') // OPTIONAL
]
]
];
Publishing assets
You can optionally publish the wireui.php config file using:
php artisan vendor:publish --tag='worldui.config'
Default config:
<?php
use WeblaborMx\WorldUi\Components;
return [
'endpoint' => rtrim(config('services.weblabor.world.endpoint', env('WEBLABOR_WORLD_ENDPOINT', 'https://world.weblabor.mx/api')), '/'),
'api_token' => config('services.weblabor.world.token', env('WEBLABOR_WORLD_TOKEN')),
'components' => [
[
'class' => Components\CountrySelect::class,
'alias' => 'country-select'
],
[
'class' => Components\DivisionSelect::class,
'alias' => 'division-select'
],
[
'class' => Components\DivisionSearchSelect::class,
'alias' => 'division-search'
],
]
];
Components
Country Select
Example:
<x-country-select
wire:model="country"
wire:key="country-select"
label="Country"
placeholder="Your country" />
Division Select
Unique Fields
- id: The ID of the division to get the children from
- regex: An optional regex to match the names of the countries
Example:
<x-division-select
label="State"
id="{{ $country }}"
wire:key="state-select"
placeholder="Your state" />
When the parent id is empty, the select is automatically disabled. This
makes dependent selects safe to use without extra markup: a city selector
will remain unavailable until its state has been selected.
See Dependent selects for what the select does while its options load, when its parent changes and when the options cannot be loaded.
Search Select
Unique Fields
- search: Content to be searched
- parentId: Division ID to filter the results
Example:
<x-input label="Search"
wire:model.lazy="search"
placeholder="Your search" />
<x-division-search
search="{{ $search }}"
parentId="{{ $country }}"
wire:key="search-select"
wire:target="search"
wire:loading.remove />
The search select depends on search and parentId, so it behaves as a
dependent select too. It only reports a failure when
search has a value.
Dependent selects
division-select (which depends on id) and division-search (which depends
on search and parentId) load their options from the values they depend on.
country-select depends on nothing and keeps the plain WireUI select behaviour.
While the options load. The Livewire request that changes the parent value renders the select again with its new options. While that request runs, the select is blocked (it cannot be opened, focused or chosen from) and a loading message is shown under it.
By default the select is blocked during any request of its Livewire component.
Name the properties that reload it with wire:target to block it only for
those; the retry below is always included:
<x-division-select
wire:model.live="state"
id="{{ $country }}"
wire:target="country"
wire:key="state-select" />
<x-division-select
wire:model="city"
id="{{ $state }}"
wire:target="country,state"
wire:key="city-select" />
When the parent changes. The value bound with wire:model is set to
null as soon as the select is rendered with a different parent value, so a
city never outlives the state it belongs to. Changing the country empties the
state, which in turn empties the city. The property is updated with the same
modifier the select uses: a wire:model.live (or .blur / .change) select
sends the change at once, a deferred one sends it with the next request. A
value that is already loaded when the page opens is never touched.
When the parent has no options. A parent the service answers with an empty list (a country without states, a state without cities) shows No options under the select, with no failure and no retry: asking again cannot change it.
When the service fails. If the World service fails, takes longer than its
timeout, is rate limited or answers something that is not a list of divisions,
the select shows the last list it kept (see Kept lists) and no
message. Only when no list was ever kept does a message appear under the select
with a Retry action. Retry renders the component again ($refresh), which
asks the service again. The select is blocked while the retry runs, and the
message disappears once options arrive. When the service asked to wait
(Retry-After), the message says for how many seconds, and Retry does not ask
the service before then. A select whose parent value is empty stays disabled,
shows no message and never asks the service.
Kept lists
The World service limits how many requests a token may make, so every select keeps what it is given:
- A list the service answered, an empty one included, is kept in the application
cache for one day (
$cacheMinutes, 1440), and kept again with no expiry under the same key plus:stale. Within the day no request is made. - When the service fails after that day, the
:stalecopy is shown instead of a failure. - When the service answers 429 with
Retry-After, the wait is stored underworldui.native-select:wait-untiland every select respects it, because the limit belongs to the token and not to one select.
Clearing the application cache (php artisan cache:clear) drops the kept lists.
A select of your own that extends WorldComponent can answer
fetchOptions(): WeblaborMx\World\Response to get all of the above, as
CountrySelect (Division::allCountries()) and DivisionSelect
(Division::childrenOf()) do. A select that only answers options(): array
cannot tell a failure from an empty answer, so an empty array keeps the earlier
meaning: it is a failure, it is not kept, and it offers a retry.
Texts
The loading message, the failure message, the retry action, the empty message
and the wait notice ship in English and Spanish under the worldui::messages namespace, and are shown in the
application locale with no setup:
| Key | English | Spanish |
|---|---|---|
loading | Loading options… | Cargando opciones… |
failed | The options could not be loaded | No se pudieron cargar las opciones |
retry | Retry | Reintentar |
empty | No options | No hay opciones |
wait | The service asked to wait :seconds seconds before retrying | El servicio pidió esperar :seconds segundos antes de reintentar |
wait has a singular and a plural form separated by |, and is shown with
trans_choice, so keep both when you override it.
To change them, or to add another language, publish them:
php artisan vendor:publish --tag='worldui.lang'
and edit lang/vendor/worldui/{locale}/messages.php. Laravel reads a project's
lang/vendor/worldui files before the package's, and only the keys a project
defines are replaced.
Styles
The dependent select markup lives in resources/views/dependent-select.blade.php.
Projects that build Tailwind from their own sources must include it, for
example in Tailwind 4:
@source '../../vendor/weblabormx/world-ui/resources/views/**/*.blade.php';