PAD writes the page.
Alpine wakes it up.
Alpine adds behaviour to HTML with a few attributes - and PAD writes that HTML. Both
like braces, so the trick is to let each have its own: PAD hands Alpine its state as JSON
with the ^ sigil, and longer components live in a file of www/.
<div x-data="{^profile}"> <!-- $profile from the page's PHP -->
<h2 x-text="name"></h2>
<button @click="likes++">
♥ <span x-text="likes"></span>
</button>
</div>
The template holds no brace of Alpine's: the state is the JSON of a PHP array.
State from the server
2 examplesAlpine lives in the HTML PAD writes. Its state comes from the page's PHP as JSON in the attribute - the ^ sigil writes it - or as the argument of a component registered in a file of www/.
State from PHP
x-data="{^profile}": the page's PHP prepares an array, the ^ sigil writes it as JSON into the attribute, and Alpine makes it live - no braces of Alpine's in the template at all.
{^field}x-datax-modelx-textComponents in a file
Tabs, an accordion and a dialog registered with Alpine.data in www/alpine/ - the template calls them by name and hands them PAD's data as the argument: x-data="accordion({^faq})".
{^field}{faq}Alpine.datax-showx-transitionTalking back to PAD
4 examplesA component asks the page again: the JSON of $padExpose, a post with the session's token, a stream of events. The server keeps the truth.
Live search
x-model.debounce feeds a fetch of the same page with padFormat=json; the PHP that rendered the first results answers the next ones as JSON - $padExpose names what may leave.
$padExposepadFormat=jsonx-model.debouncex-forfetchOne set of rules
The rules live in the page's PHP: padValidate checks the post with them, padValidateClient hands them to Alpine, and {validator} checks them in the browser first - the same messages on both sides.
padValidateClientpadValidate{validator}@blurpadValidate.checkA list PAD keeps
Every change shows at once and is posted to the page, which keeps the list in the session and answers it - the server's answer is the list. Reload, and it is still there.
padSession$padExposex-for@submit.preventfetch POSTServer-sent events
padSse sends the server's numbers every second as JSON; the component opens an EventSource in x-init and closes it when the stream says it is done.
padSseevery=EventSourcex-init