Skip to content

Commit d0de977

Browse files
committed
Add interactive Checkbox playground for JavaScript frameworks
1 parent cea527f commit d0de977

13 files changed

Lines changed: 344 additions & 0 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace App\Filament\Pages;
4+
5+
use App\Filament\Widgets\CheckboxBlade;
6+
use App\Filament\Widgets\CheckboxReact;
7+
use App\Filament\Widgets\CheckboxSvelte;
8+
use App\Filament\Widgets\CheckboxVue;
9+
use Filament\Pages\Dashboard;
10+
11+
class CheckboxPlayground extends Dashboard
12+
{
13+
protected static string $routePath = 'checkbox-playground';
14+
15+
protected static ?string $title = 'Checkbox playground';
16+
17+
public function getWidgets(): array
18+
{
19+
return [CheckboxBlade::class, CheckboxReact::class, CheckboxVue::class, CheckboxSvelte::class];
20+
}
21+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace App\Filament\Widgets;
4+
5+
use Filament\Widgets\Widget;
6+
7+
class CheckboxBlade extends Widget
8+
{
9+
protected string $view = 'filament.widgets.checkbox-blade';
10+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Filament\Widgets;
4+
5+
use Filament\Widgets\Concerns\HasJsRenderer;
6+
use Filament\Widgets\Widget;
7+
use Illuminate\Support\Facades\Vite;
8+
9+
class CheckboxReact extends Widget
10+
{
11+
use HasJsRenderer;
12+
13+
public function getRenderer(): string
14+
{
15+
return Vite::asset('resources/js/filament/widgets/checkbox-react.jsx');
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Filament\Widgets;
4+
5+
use Filament\Widgets\Concerns\HasJsRenderer;
6+
use Filament\Widgets\Widget;
7+
use Illuminate\Support\Facades\Vite;
8+
9+
class CheckboxSvelte extends Widget
10+
{
11+
use HasJsRenderer;
12+
13+
public function getRenderer(): string
14+
{
15+
return Vite::asset('resources/js/filament/widgets/checkbox-svelte.svelte.js');
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Filament\Widgets;
4+
5+
use Filament\Widgets\Concerns\HasJsRenderer;
6+
use Filament\Widgets\Widget;
7+
use Illuminate\Support\Facades\Vite;
8+
9+
class CheckboxVue extends Widget
10+
{
11+
use HasJsRenderer;
12+
13+
public function getRenderer(): string
14+
{
15+
return Vite::asset('resources/js/filament/widgets/checkbox-vue.js');
16+
}
17+
}

‎resources/css/filament/admin/theme.css‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,23 @@
107107
.loading-indicator-demo-accent {
108108
@apply text-primary-600 dark:text-primary-400;
109109
}
110+
111+
.checkbox-demo,
112+
.checkbox-demo form {
113+
@apply grid gap-4;
114+
}
115+
116+
.checkbox-demo {
117+
& label {
118+
@apply flex items-center gap-2 text-sm;
119+
}
120+
121+
& p,
122+
& output {
123+
@apply text-sm text-gray-600 dark:text-gray-300;
124+
}
125+
}
126+
127+
.checkbox-demo-controls {
128+
@apply flex flex-wrap gap-4;
129+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<script>
2+
import Checkbox from '../../../../vendor/filament/support/resources/js/svelte/Checkbox.svelte'
3+
let checked = $state(true)
4+
let disabled = $state(false)
5+
let invalid = $state(false)
6+
let required = $state(false)
7+
let submitted = $state('Not submitted')
8+
</script>
9+
10+
<div class="checkbox-demo" data-framework="svelte">
11+
<h2 class="fi-section-header-heading">Svelte · JavaScript</h2>
12+
<form
13+
onsubmit={(event) => {
14+
event.preventDefault()
15+
submitted = JSON.stringify([...new FormData(event.currentTarget)])
16+
}}
17+
>
18+
<label
19+
><Checkbox
20+
bind:checked
21+
name="digest"
22+
value="weekly"
23+
{disabled}
24+
valid={!invalid}
25+
{required}
26+
aria-invalid={invalid}
27+
/> Send me the weekly digest</label
28+
>
29+
<button type="submit" class="fi-btn fi-size-sm"
30+
>Preview submission</button
31+
>
32+
</form>
33+
<div class="checkbox-demo-controls">
34+
<label><input type="checkbox" bind:checked={disabled} /> Disabled</label
35+
>
36+
<label><input type="checkbox" bind:checked={invalid} /> Invalid</label>
37+
<label><input type="checkbox" bind:checked={required} /> Required</label
38+
>
39+
</div>
40+
<output>{checked ? 'Subscribed' : 'Not subscribed'} · {submitted}</output>
41+
<button
42+
type="button"
43+
class="fi-btn fi-size-sm"
44+
onclick={() => {
45+
checked = true
46+
disabled = false
47+
invalid = false
48+
required = false
49+
submitted = 'Not submitted'
50+
}}>Reset</button
51+
>
52+
</div>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<script setup>
2+
import { ref } from 'vue'
3+
import Checkbox from '../../../../vendor/filament/support/resources/js/vue/Checkbox.vue'
4+
const checked = ref(true)
5+
const disabled = ref(false)
6+
const invalid = ref(false)
7+
const required = ref(false)
8+
const submitted = ref('Not submitted')
9+
function submit(event) {
10+
submitted.value = JSON.stringify([...new FormData(event.currentTarget)])
11+
}
12+
function reset() {
13+
checked.value = true
14+
disabled.value = false
15+
invalid.value = false
16+
required.value = false
17+
submitted.value = 'Not submitted'
18+
}
19+
</script>
20+
21+
<template>
22+
<div class="checkbox-demo" data-framework="vue">
23+
<h2 class="fi-section-header-heading">Vue · JavaScript</h2>
24+
<form @submit.prevent="submit">
25+
<label
26+
><Checkbox
27+
v-model="checked"
28+
name="digest"
29+
value="weekly"
30+
:disabled="disabled"
31+
:valid="!invalid"
32+
:required="required"
33+
:aria-invalid="invalid"
34+
/>
35+
Send me the weekly digest</label
36+
>
37+
<button type="submit" class="fi-btn fi-size-sm">
38+
Preview submission
39+
</button>
40+
</form>
41+
<div class="checkbox-demo-controls">
42+
<label><input type="checkbox" v-model="disabled" /> Disabled</label>
43+
<label><input type="checkbox" v-model="invalid" /> Invalid</label>
44+
<label><input type="checkbox" v-model="required" /> Required</label>
45+
</div>
46+
<output
47+
>{{ checked ? 'Subscribed' : 'Not subscribed' }} ·
48+
{{ submitted }}</output
49+
>
50+
<button type="button" class="fi-btn fi-size-sm" @click="reset">
51+
Reset
52+
</button>
53+
</div>
54+
</template>
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React, { useState } from 'react'
2+
import { createRoot } from 'react-dom/client'
3+
import Checkbox from '../../../../vendor/filament/support/resources/js/react/Checkbox'
4+
5+
function CheckboxReact() {
6+
const [checked, setChecked] = useState(true)
7+
const [disabled, setDisabled] = useState(false)
8+
const [invalid, setInvalid] = useState(false)
9+
const [required, setRequired] = useState(false)
10+
const [submitted, setSubmitted] = useState('Not submitted')
11+
return (
12+
<div className="checkbox-demo" data-framework="react">
13+
<h2 className="fi-section-header-heading">React · JavaScript</h2>
14+
<form
15+
onSubmit={(event) => {
16+
event.preventDefault()
17+
setSubmitted(
18+
JSON.stringify([...new FormData(event.currentTarget)]),
19+
)
20+
}}
21+
>
22+
<label>
23+
<Checkbox
24+
name="digest"
25+
value="weekly"
26+
checked={checked}
27+
onChange={(event) => setChecked(event.target.checked)}
28+
disabled={disabled}
29+
valid={!invalid}
30+
required={required}
31+
aria-invalid={invalid}
32+
/>{' '}
33+
Send me the weekly digest
34+
</label>
35+
<button type="submit" className="fi-btn fi-size-sm">
36+
Preview submission
37+
</button>
38+
</form>
39+
<div className="checkbox-demo-controls">
40+
<label>
41+
<input
42+
type="checkbox"
43+
checked={disabled}
44+
onChange={(event) => setDisabled(event.target.checked)}
45+
/>{' '}
46+
Disabled
47+
</label>
48+
<label>
49+
<input
50+
type="checkbox"
51+
checked={invalid}
52+
onChange={(event) => setInvalid(event.target.checked)}
53+
/>{' '}
54+
Invalid
55+
</label>
56+
<label>
57+
<input
58+
type="checkbox"
59+
checked={required}
60+
onChange={(event) => setRequired(event.target.checked)}
61+
/>{' '}
62+
Required
63+
</label>
64+
</div>
65+
<output>
66+
{checked ? 'Subscribed' : 'Not subscribed'} · {submitted}
67+
</output>
68+
<button
69+
type="button"
70+
className="fi-btn fi-size-sm"
71+
onClick={() => {
72+
setChecked(true)
73+
setDisabled(false)
74+
setInvalid(false)
75+
setRequired(false)
76+
setSubmitted('Not submitted')
77+
}}
78+
>
79+
Reset
80+
</button>
81+
</div>
82+
)
83+
}
84+
85+
export default function mountCheckboxReact({ host, props: initialProps }) {
86+
const root = createRoot(host)
87+
const update = (props) => root.render(<CheckboxReact {...props} />)
88+
update(initialProps)
89+
90+
return { update, destroy: () => root.unmount() }
91+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { mount, unmount } from 'svelte'
2+
import CheckboxSvelte from './CheckboxSvelte.svelte'
3+
4+
export default function mountCheckboxSvelte({ host, props: initialProps }) {
5+
const props = $state({ ...initialProps })
6+
const component = mount(CheckboxSvelte, { target: host, props })
7+
8+
return {
9+
update: (nextProps) => {
10+
Object.assign(props, nextProps)
11+
},
12+
destroy: () => unmount(component),
13+
}
14+
}

0 commit comments

Comments
 (0)