-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Form Components #62
base: main
Are you sure you want to change the base?
Form Components #62
Changes from 17 commits
5ccad1f
d03725c
fe7834e
35f143b
15c55d5
1b5f344
c2b55a0
bd54ded
10f16e0
cdf88a0
cd72c27
ee181a7
a27a422
b485975
8950492
91ed3b7
0e0f130
0fd4407
c511aac
144e8a8
a7b77a0
f80c3d5
b072093
d69cca8
6aea959
e588f38
c60f74d
05659cd
8a425cc
3b7d469
a30806a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# DIALOG | ||
|
||
NOTE: you must add the component | ||
``` | ||
<x-cd.component-scripts /> | ||
``` | ||
to the head element of the page before using the `cd.dialog` component. | ||
|
||
The modal dialog component is used as follows: | ||
|
||
``` | ||
<x-cd.dialog> | ||
<x-cd.dialog.button> | ||
<x-cd.form.submitbutton value="Open Modal"/> | ||
</x-cd.dialog.button> | ||
<x-cd.dialog.panel> | ||
<div> | ||
<h2>This is my modal</h2> | ||
<p>Isn't it great?</p> | ||
</div> | ||
</x-cd.dialog.panel> | ||
</x-cd.dialog> | ||
|
||
``` | ||
|
||
You can use any markup in `<x-cd.dialog.button>`, e.g., a button, link, etc. The click handler is already included in `cd-dialog.button`, so clicking on your element will open the dialog. | ||
|
||
If you would like to open the dialog from a Livewire component, add a `wire:model` atribute to the `<x-cd.dialog>` tag, like the following: | ||
|
||
``` | ||
<x-cd-dialog wire:model="dialogFlag"> | ||
.... | ||
</x-cd-dialog> | ||
``` | ||
|
||
When dialogFlag (or whatever property you use) becomes true, the dialog will open. | ||
|
||
Any content you include in `<x-cd.dialog.panel>` will be displayed in the dialog when it opens. | ||
|
||
The modal dialog has a close button in the upper right corner. You can add a close button to your panel content by including | ||
|
||
``` | ||
<x-cd.dialog.close-button value="Close" /> | ||
``` | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<span x-on:click="dialogOpen = true"> | ||
{{ $slot }} | ||
</span> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<span x-on:click="dialogOpen = false"> | ||
{{ $slot }} | ||
</span> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<div x-data="{ dialogOpen: false }" x-modelable="dialogOpen" {{$attributes}}> | ||
{{ $slot }} | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<div | ||
x-dialog | ||
x-model="dialogOpen" | ||
style="display: none; | ||
position:fixed; | ||
top: 0; right: 0; bottom: 0; left: 0; | ||
overflow-y:auto; | ||
z-index: 10" | ||
{{-- tailwindclass="fixed inset-0 overflow-y-auto z-10" --}} | ||
> | ||
<div>In panel, open is <span x-text="open"></span></div> | ||
<!-- Overlay --> | ||
<div x-dialog:overlay x-transition.opacity | ||
style="position:fixed; | ||
top: 0; right: 0; bottom: 0; left: 0; | ||
--bg-opacity: 1; | ||
background-color: #000; | ||
background-color: rgba(0, 0, 0, .25);" | ||
{{-- tailwindclass="fixed inset-0 bg-black/25" --}} | ||
|
||
></div> | ||
|
||
<!-- Panel --> | ||
<div | ||
{{-- tailwindclass="relative min-h-screen flex items-center justify-center p-4" --}} | ||
style="position:relative; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 1rem;" | ||
> | ||
<div | ||
x-dialog:panel | ||
x-transition.in x-transition.out.opacity | ||
{{-- tailwindclass="relative max-w-2xl w-full bg-white rounded-xl shadow-lg overflow-y-auto" --}} | ||
style="position: relative; max-width: 42rem; width: 100%; | ||
--bg-opacity: 1; background-color: #fff; background-color: rgba(255,255,255,var(--bg-opacity)); | ||
border-radius: 0.75rem; | ||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); | ||
overflow-y: auto;" | ||
> | ||
<!-- Close Button --> | ||
<div | ||
{{-- tailwindclass="absolute top-0 right-0 pt-4 pr-4" --}} | ||
style="position:absolute; top: 0; right: 0; padding-top: 1rem; padding-right: 1rem;" | ||
> | ||
<button type="button" @click="$dialog.close()" | ||
{{-- tailwindclass="bg-gray-50 rounded-lg p-2 text-gray-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2" --}} | ||
style="--bg-opacity: 1; | ||
background-color: #a0aec0; | ||
background-color: rgba(160, 174, 192, var(--bg-opacity)); | ||
border-radius: 0.5rem; | ||
padding: 0.5rem; | ||
--text-opacity: 1; | ||
color: #718096; | ||
color: rgba(113, 128, 150, var(--text-opacity));" | ||
> | ||
<span class="sr-only">Close modal</span> | ||
<svg xmlns="http://www.w3.org/2000/svg" tailwindclass="h-4 w-4" style="height: 1rem; width: 1 rem;" viewBox="0 0 20 20" fill="currentColor"> | ||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" /> | ||
</svg> | ||
</button> | ||
</div> | ||
|
||
<!-- Panel --> | ||
<div | ||
{{-- tailwindclass="p-8" --}} | ||
style="padding: 2rem;" | ||
> | ||
{{ $slot }} | ||
</div> | ||
</div> | ||
</div> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
# Form Components | ||
|
||
A set of form components provides support the the styled form elements in the CD Framework. | ||
|
||
## Form | ||
|
||
The form component creates the required fieldset and legend. | ||
|
||
Use wire:submit on the form component rather than wire:click on the submit button to maintain the | ||
expected behavior of submitting the form if the user hits enter in a text element. | ||
|
||
Here is an example of a simple form: | ||
|
||
``` | ||
<x-cd.form.form legend="Simple form" wire:submit="submit"> | ||
<x-cd.form.text label="Name" wire:model="name"/> | ||
<div> | ||
<x-cd.form.submitbutton/> | ||
<x-cd.form.resetbutton/> | ||
</div> | ||
</x-cd.form.form> | ||
``` | ||
|
||
## Form elements | ||
|
||
The `name` and `id` attributes on the form inputs default to the same value as | ||
that used in the `wire:model` attribute. You may supply different values for `name` and `id `. | ||
Inputs are not required by default; you can supply the `:required="true"` attribute if the input | ||
should be required for your form. | ||
|
||
Use the `description` attribute to provide additional instruction or formatting hints. The description text is displayed below the input. The component will add an `aria-describedby` attribute to the input to associate the description text with the input. | ||
|
||
## Text | ||
|
||
The `placeholder` attribute can be used on text inputs. | ||
|
||
To adjust the width of the text input, use the `size` attribute and add the class `use-size-attr`. | ||
|
||
Example: | ||
``` | ||
<x-cd.form.text label="Text Input" wire:model="name"/> | ||
``` | ||
## Select | ||
|
||
The select form input requires an array of options. | ||
The options and the component call are demonstrated below. The required attribute is optional. | ||
Making the first option disabled gives it the function of placeholder text. | ||
|
||
``` | ||
$this->roleoptions = [ | ||
[ 'value'=>'', 'option'=>'Select a Role', 'disabled'=>true], | ||
[ 'value'=>'administrator', 'option'=>'Administrator', 'disabled'=>false], | ||
[ 'value'=>'editor', 'option'=>'Editor', 'disabled'=>false], | ||
[ 'value'=>'subscriber', 'option'=>'Subscriber', 'disabled'=>false], | ||
]; | ||
``` | ||
|
||
``` | ||
<x-cd.form.select :options="$roleoptions" required="1" label="Select" wire:model="role" /> | ||
``` | ||
You may add the attribute `multiple="multiple"` to create a multiselect. Multiselect with groups are not yet supported. | ||
|
||
## Checkbox | ||
|
||
The checkbox component implements a single checkbox (see Checkboxes for multiple checkboxes). | ||
The checkbox component needs a value to return when the box is checked. The checkbox-inline variant places the label next to the checkbox input rather than above it. | ||
|
||
Note: single checkboxes cannot be required. | ||
|
||
``` | ||
<x-cd.form.checkbox label="Subscription" text="Subscribe" value="1" wire:model="subscribe" /> | ||
``` | ||
|
||
``` | ||
<x-cd.form.checkbox-inline name="inline" value="1" label="Select me" description="description" wire:model="subscribe"/> | ||
``` | ||
## Checkboxes | ||
|
||
The checkboxes component implements a set of related checkboxes which are bound to one Livewire variable. | ||
An array of options define the set of checkboxes as demonstrated here. | ||
|
||
``` | ||
$this->checkboxoptions = [ | ||
[ 'value' => "tomato", "label" => "Tomato"], | ||
[ 'value' => "lettuce", "label" => "Lettuce"], | ||
[ 'value' => "pickle", "label" => "Pickle"], | ||
[ 'value' => "onion", "label" => "Onion"], | ||
]; | ||
richmarisa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
``` | ||
<x-cd.form.checkboxes :checkboxes="$checkboxoptions" wire:model="toppings" label="Topping Choices"/> | ||
``` | ||
|
||
## Special text inputs | ||
|
||
The CD Framework provides styling for several special-purpose text inputs. These may be selected | ||
using the `type` attribute, as in the following examples: | ||
|
||
|
||
``` | ||
<x-cd.form.text type="search" label="Search" wire:model="search"/> | ||
<x-cd.form.text type="telephone" label="Telephone" wire:model="telephone"/> | ||
<x-cd.form.text type="url" label="URL" wire:model="url"/> | ||
<x-cd.form.text type="email" label="Email" wire:model="email"/> | ||
<x-cd.form.text type="password" label="Password" wire:model="password"/> | ||
<x-cd.form.text type="number" label="Number" wire:model="number"/> | ||
<x-cd.form.text type="datetime" label="Datetime" wire:model="datetime"/> | ||
<x-cd.form.text type="datetimelocal" label="Datetime Local" wire:model="datetimelocal"/> | ||
<x-cd.form.text type="date" label="Date" wire:model="date"/> | ||
<x-cd.form.text type="month" label="Month" wire:model="month"/> | ||
<x-cd.form.text type="week" label="Week" wire:model="week"/> | ||
<x-cd.form.text type="time" label="Time" wire:model="time"/> | ||
``` | ||
## Range | ||
|
||
A range input rendered as a slider may be specified using this special text input which requires | ||
`max` and `min` attributes. | ||
|
||
``` | ||
<x-cd.form.text type="range" required="1" label="Range" min="1" max="10" wire:model="range"/> | ||
``` | ||
|
||
## File | ||
|
||
The file selector input is also a variant of the text input. | ||
``` | ||
<x-cd.form.text type="file" required="1" label="File" wire:model="file"/> | ||
``` | ||
|
||
## Color | ||
|
||
The color picker is also a variant of the text input. Take care to initialize the value of this | ||
input to a valid `value`, which is a hash (#) character followed by six hexadecimal digits. | ||
``` | ||
<x-cd.form.text type="color" label="Color" wire:model="color" value="#ff0000"/> | ||
``` | ||
|
||
# Radio Buttons | ||
|
||
The `radios` component implements a set of related radio buttons defined by an array of options, as demonstrated below.</p> | ||
|
||
``` | ||
<x-cd.form.radios label="Radios" wire:model="radios" :radiobuttons="$radiooptions" /> | ||
``` | ||
|
||
# Submit, Reset and Cancel Buttons | ||
|
||
Components are provided for the submit and reset buttons often used in forms. Since the submit button will cause | ||
the form to call the `wire:submit` function specified in the form element, no `wire:click` is required in that element. | ||
|
||
The reset button will clear the form. | ||
|
||
The cancel button requires a `wire:click` or `x-on:click` attribute to specify the action which should be | ||
taken when the button is pressed. | ||
|
||
``` | ||
<x-cd.form.submitbutton /> | ||
<x-cd.form.resetbutton /> | ||
<x-cd.form.cancelbutton wire:click"closemodal"> | ||
woodseowl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
|
||
|
||
|
richmarisa marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<span> | ||
<input type="button" class="button js-form-submit form-submit" value="{{$value??"Cancel"}}" {{$attributes}}/> | ||
</span> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
@php | ||
$field = $name ?? $attributes->whereStartsWith('wire:model')->first(); | ||
@endphp | ||
<div class="form-item"> | ||
<input type="checkbox" id="{{ $id ?? $field }}" | ||
name="{{ $field }}" | ||
value="{{ $value }}" | ||
{{ $attributes->whereStartsWith('wire:model') }} | ||
{{ $attributes->whereStartsWith('aria') }} | ||
{{ $attributes->whereStartsWith('checked') }} | ||
@if (!empty($description)) | ||
aria-describedby="{{ $field }}_desc" | ||
@endif | ||
/> | ||
<label class="option-label" id="{{$field}}_desc">{{$label}}</label> | ||
@if (!empty($description)) | ||
<div class="description">{{$description}}</div> | ||
@endif | ||
richmarisa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</div> |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,23 @@ | ||||||
<x-cd.form.form-item field="{{ $name ?? $attributes->whereStartsWith('wire:model')->first() }}" | ||||||
classes="{{ $classes ?? '' }}" | ||||||
required="false" | ||||||
richmarisa marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
:description="$description??''" | ||||||
> | ||||||
@php | ||||||
$field = $name ?? $attributes->whereStartsWith('wire:model')->first(); | ||||||
@endphp | ||||||
<x-slot name="field_title">{!! $label !!}</x-slot> | ||||||
<div class="form-item"> | ||||||
richmarisa marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
<input type="checkbox" id="{{ $id ?? $field }}" | ||||||
name="{{ $field }}" | ||||||
value="{{ $value }}" | ||||||
{{ $attributes->whereStartsWith('wire:model') }} | ||||||
{{ $attributes->whereStartsWith('aria') }} | ||||||
{{ $attributes->whereStartsWith('checked') }} | ||||||
@if (!empty($description)) | ||||||
aria-describedby="{{ $field }}_desc" | ||||||
@endif | ||||||
/> | ||||||
<span class="option-label" for="{{$field}}">{!!$text??''!!}</span> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Two suggestions here:
Regardless of whether you want to use text or slot, it needs to be documented in the README example, because I only found it when I couldn't figure out why my checkbox didn't show anything. |
||||||
</div> | ||||||
</x-cd.form.form-item> |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,24 @@ | ||||||||||||
<x-cd.form.form-item field="{{ $name ?? $attributes->whereStartsWith('wire:model')->first() }}" | ||||||||||||
classes="{{ $classes ?? '' }}" | ||||||||||||
required="{{ (($required??'') === 'false') ? 0 : (boolval($required??'')?1:0) }}" | ||||||||||||
:description="$description ?? ''" | ||||||||||||
> | ||||||||||||
Comment on lines
+1
to
+5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this usage of form-item for the checkboxes is creating more problems than it is solving, but I don't see a simple solution. Here are the issues when I try to create a list of checkboxes like the CSSF example:
I think the CSSF example would suggest just removing this wrapper entirely. But we lose the "required" feature and the automatic wiring for the description. It's easy enough to pull the description code up to this component. Not sure what to do for labeling and requiredness, though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think other changes fix the form-items nesting; the trailing description is for consistency with other components. If you don't specify it, it doesn't appear. To fix the label issue, I think we need a div with the same styling as the label; I'll work on that. |
||||||||||||
@php | ||||||||||||
$field=$name ?? $attributes->whereStartsWith('wire:model')->first(); | ||||||||||||
@endphp | ||||||||||||
<x-slot name="field_title">{!! $label !!}</x-slot> | ||||||||||||
<div class="flex-grid compact-rows"> | ||||||||||||
Comment on lines
+9
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What would you think of putting $slot between these:
Suggested change
That would make it possible to include content between the heading and the options, like in the "A Plethora of Checkboxes" example |
||||||||||||
@foreach ($checkboxes as $cb) | ||||||||||||
<div class="form-item"> | ||||||||||||
<input type="checkbox" id="{{$field}}-{{$loop->index}}" name="{{ $field }}" value="{{ $cb['value']}}" | ||||||||||||
{{ $attributes->whereStartsWith('wire:model') }} | ||||||||||||
{{ $attributes->whereStartsWIth('aria') }} | ||||||||||||
@if (!empty($description)) | ||||||||||||
aria-describedby="{{ $field }}_desc" | ||||||||||||
@endif | ||||||||||||
> | ||||||||||||
richmarisa marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||
<label class="option-label" for="{{$field}}-{{$loop->index}}">{{$cb["label"]}}</label> | ||||||||||||
</div> | ||||||||||||
@endforeach | ||||||||||||
</div> | ||||||||||||
</x-cd.form.form-item> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo