WIP: Form components extensions and improvements #94707

Draft
Márton Lente wants to merge 12 commits from component-forms into v2

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
3 changed files with 316 additions and 94 deletions

View File

@ -1274,7 +1274,7 @@
<li>Item One</li> <li>Item One</li>
<li>Item Two</li> <li>Item Two</li>
</ul> </ul>
<hr /> <hr>
<p> <p>
Add <code>list-inline</code> for inline layout. Add <code>list-inline</code> for inline layout.
</p> </p>
@ -1603,73 +1603,60 @@
<div class="col-md-12"> <div class="col-md-12">
<form class="form-horizontal"> <form class="form-horizontal">
<fieldset> <fieldset>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<label>Label for full width input</label> <label>Field with text only</label>
<div class="form-group form-group-lg width-full"> <div class="form-group">
<span class="form-group-addon"><i class="bf-network"></i></span> <input class="form-control" placeholder="Default Text" type="text" />
<input class="form-control" placeholder="Full freakin width, from here << to theeeere >>" </div>
type="text" />
<label>Field with required text</label>
<span class="form-required-indicator">*</span>
<div class="form-group">
<input class="form-control" placeholder="Required Text" type="text" required />
</div>
<label>Bunch of inputs on top of each other</label>
<div class="form-group">
<span class="form-group-addon"><i class="i-file-video-o"></i></span>
<input class="form-control" placeholder="Default Text (disabled)" type="text" disabled />
<div class="form-text">
Sorry, this field looks too awesome
</div>
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label for="last_name">Field with button on the right</label> <label for="last_name">Field with button on the right</label>
<div class="form-group form-group-lg width-full"> <div class="form-group">
<input type="text" class="form-control collection-user" placeholder="I've got a button!"> <input type="text" class="form-control collection-user" placeholder="I've got a button!">
<span class="form-group-addon"> <span class="form-group-addon">
<button title="Hi!"><i class="i-cancel"></i></button> <button title="Hi!"><i class="i-cancel"></i></button>
</span> </span>
</div> </div>
</div> <label for="city">City</label>
</div> <div class="form-group has-error">
<span class="form-group-addon"><i class="i-map-marker"></i></span>
<hr /> <input class="form-control" id="city" name="city" placeholder="City" type="text" value="Amsterdam">
<div class="form-text">
<div class="row"> Can't hear you over the beauty of this field
<div class="col-md-6"> </div>
<label>This is just form-group, not large</label>
<div class="form-group width-full">
<input class="form-control" placeholder="Default Text" type="text" />
</div>
</div>
<div class="col-md-6">
<label>Video Example</label>
<div class="form-group form-group-lg width-full">
<span class="form-group-addon"><i class="i-reel"></i></span>
<input class="form-control" placeholder="Default Text" type="text" />
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <hr>
<div class="col-md-6">
<p>
You can also add a <code>disabled</code> class to the <code>form-group</code>.
</p>
</div>
<div class="col-md-6">
<label>Video Example (disabled)</label>
<div class="form-group form-group-lg width-full">
<span class="form-group-addon"><i class="i-reel"></i></span>
<input class="form-control" placeholder="Default Text (disabled)" type="text" disabled />
</div>
</div>
</div>
<hr />
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<label>Image Upload</label> <label>File Upload</label>
<div class="form-group form-group-lg width-full"> <div class="form-group">
<span class="form-group-addon"><i class="i-image"></i></span> <span class="form-group-addon"><i class="i-file"></i></span>
<input class="form-control" type="file" /> <input class="form-control" type="file" />
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-6">
<label>Select the fastest render engine ever</label> <label>Select the fastest render engine ever</label>
<div class="form-group form-group-lg width-full"> <div class="form-group">
<select class="form-control"> <select class="form-control">
<option>Blender Internal</option> <option>Blender Internal</option>
<option>Blender Eternal</option> <option>Blender Eternal</option>
@ -1680,10 +1667,8 @@
<option disabled>Deal with it.</option> <option disabled>Deal with it.</option>
</select> </select>
</div> </div>
</div>
<div class="col-md-3">
<label>Banana</label> <label>Banana</label>
<div class="form-group form-group-lg width-full"> <div class="form-group">
<span class="form-group-addon"><i class="i-bug"></i></span> <span class="form-group-addon"><i class="i-bug"></i></span>
<select class="form-control"> <select class="form-control">
<option disabled>For Scale</option> <option disabled>For Scale</option>
@ -1692,53 +1677,81 @@
</div> </div>
</div> </div>
<hr /> <hr>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<label>Long stuff go in textareas</label> <label>Long stuff go in textareas</label>
<div class="form-group form-group-lg width-full"> <div class="form-group">
<textarea class="form-control" placeholder="Default Text"></textarea> <textarea class="form-control" placeholder="Default Text"></textarea>
</div> </div>
<hr /> <hr>
<button class="btn btn-success width-half pull-right" type="submit"> <button class="btn btn-success width-half pull-right" type="submit">
<i class="i-send"></i> Send Stuff! <i class="i-send"></i> Send Stuff!
</button> </button>
</div> </div>
</div>
<hr>
<div class="row">
<div class="col-md-6"> <div class="col-md-6">
<label class="form-check-label" for="work_travel">This is a checkbox.</label>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" id="work_travel" name="work_travel" <input class="form-check-input" id="checkbox-default-1" type="checkbox" value="" checked>
placeholder="Are you available to travel?" type="checkbox"> <label class="form-check-label" for="checkbox-default-1">
Default checkbox one
</label>
</div> </div>
<div class="form-check">
<label for="work_online">This one has form-group and form-group-lg</label> <input class="form-check-input" id="checkbox-default-2" type="checkbox" value="" checked>
<div class="form-group form-group-lg"> <label class="form-check-label" for="checkbox-default-2">
<input checked="" class="form-control" id="work_online" name="work_online" Default checkbox two
placeholder="Are you available to travel?" type="checkbox"> </label>
</div> </div>
<label>Bunch of inputs on top of each other</label>
<div class="form-group form-group-lg width-full disabled has-error">
<span class="form-group-addon"><i class="i-file-video-o"></i></span>
<input class="form-control" placeholder="Default Text (disabled)" type="text" />
</div>
<p class="error">
Sorry, this field looks too awesome
</p>
<label for="city">City</label>
<div class="form-group form-group-lg width-full has-error">
<span class="form-group-addon"><i class="i-map-marker"></i></span>
<input class="form-control" id="city" name="city" placeholder="City" type="text" value="Amsterdam">
</div>
<p class="error">
Can't hear you over the beauty of this field
</p>
</div> </div>
<div class="col-md-6">
<label class="form-check-custom">
Custom checkbox one
<input type="checkbox" value="" checked>
<span class="form-check-custom-mark"></span>
</label>
<label class="form-check-custom">
Custom checkbox two
<input type="checkbox" value="">
<span class="form-check-custom-mark"></span>
</label>
</div>
</div>
<hr>
<div class="row">
<div class="col-md-6">
<div class="form-check">
<input class="form-check-input" id="radios-default-1" name="radios-default" type="radio" value="option-1" checked>
<label class="form-check-label" for="radios-default-1">
Default radio 1
</label>
</div>
<div class="form-check">
<input class="form-check-input" id="radios-default-2" name="radios-default" type="radio" value="option-2">
<label class="form-check-label" for="radios-default-2">
Default radio 2
</label>
</div>
</div>
<div class="col-md-6">
<label class="form-check-custom form-check-custom-radio">
Custom radio one
<input name="radio" type="radio" value="" checked>
<span class="form-check-custom-mark"></span>
</label>
<label class="form-check-custom form-check-custom-radio">
Custom radio two
<input name="radio" type="radio" value="">
<span class="form-check-custom-mark"></span>
</label>
</div>
</div>
</fieldset> </fieldset>
</form> </form>
<!-- // Forms. --> <!-- // Forms. -->
@ -1747,14 +1760,57 @@
<hr> <hr>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<label class="toggle-bar"> <div class="mb-3">
<input type="checkbox"> <label class="me-3">Toggle bar</label>
<span class="slider"></span> <label class="toggle-bar">
</label> <input type="checkbox">
<label class="toggle-bar toggle-bar-sm"> <span class="slider"></span>
<input type="checkbox"> </label>
<span class="slider"></span> </div>
</label> <div>
<label class="me-3">Toggle bar small</label>
<label class="toggle-bar toggle-bar-sm">
<input type="checkbox">
<span class="slider"></span>
</label>
</div>
</div>
</div>
<hr>
<div class="row">
<div class="col-md-6">
<label>Slider</label>
<input class="slider-custom" id="slider-custom" min="1" max="100" type="range" value="50">
</div>
<div class="col-md-6">
<div class="mb-5">
<label>Slider with step markers (default)</label>
<input class="slider-custom" id="slider-custom" min="1" max="9" type="range" value="5">
<div class="slider-custom-steps">
<div class="slider-custom-steps-item"></div>
<div class="slider-custom-steps-item"></div>
<div class="slider-custom-steps-item"></div>
<div class="slider-custom-steps-item"></div>
<div class="slider-custom-steps-item"></div>
<div class="slider-custom-steps-item"></div>
<div class="slider-custom-steps-item"></div>
<div class="slider-custom-steps-item"></div>
<div class="slider-custom-steps-item"></div>
</div>
</div>
<label>Slider with step markers (dots)</label>
<input class="slider-custom" id="slider-custom" min="1" max="9" type="range" value="5">
<div class="slider-custom-steps">
<div class="slider-custom-steps-item slider-custom-steps-item-dots"></div>
<div class="slider-custom-steps-item slider-custom-steps-item-dots"></div>
<div class="slider-custom-steps-item slider-custom-steps-item-dots"></div>
<div class="slider-custom-steps-item slider-custom-steps-item-dots"></div>
<div class="slider-custom-steps-item slider-custom-steps-item-dots"></div>
<div class="slider-custom-steps-item slider-custom-steps-item-dots"></div>
<div class="slider-custom-steps-item slider-custom-steps-item-dots"></div>
<div class="slider-custom-steps-item slider-custom-steps-item-dots"></div>
<div class="slider-custom-steps-item slider-custom-steps-item-dots"></div>
</div>
</div> </div>
</div> </div>
@ -1782,7 +1838,7 @@
</div> </div>
<hr /> <hr>
</div> <!-- centered container for the page--> </div> <!-- centered container for the page-->
</div> <!-- container-main --> </div> <!-- container-main -->

View File

@ -1,3 +1,4 @@
// TODO: refactor and organize styles
.form .form
+list-unstyled +list-unstyled
+inputs-generic +inputs-generic
@ -12,7 +13,6 @@
.input-group-addon .input-group-addon
border-color: var(--color-danger) border-color: var(--color-danger)
.form-text, .helptext .form-text, .helptext
color: var(--color-text-secondary) color: var(--color-text-secondary)
font-size: var(--fs-sm) font-size: var(--fs-sm)
@ -26,6 +26,17 @@
&:focus &:focus
border-color: var(--color-accent) border-color: var(--color-accent)
// TODO: check if using form-control with checkbox and radio is a real use case
&[type="checkbox"],
&[type="radio"]
height: var(--spacer)
min-height: 0
width: auto
&[type="checkbox"]
&:hover
cursor: pointer
&[type="file"] &[type="file"]
padding: 0 padding: 0
@ -62,25 +73,29 @@ input,
background-color: var(--input-color-bg) background-color: var(--input-color-bg)
color: var(--color-text) color: var(--color-text)
height: calc(var(--spacer) * 2.5) min-height: calc(var(--spacer) * 2.5)
+padding(3, x) +padding(3, x)
+padding(2, y) +padding(2, y)
+media-sm +media-sm
height: var(--spacer-5) min-height: var(--spacer-5)
&:disabled &:disabled
--input-color-bg-hover: var(--input-color-bg) --input-color-bg-hover: var(--input-color-bg)
background-color: var(--input-color-bg)
cursor: not-allowed cursor: not-allowed
&::placeholder
color: var(--color-text-tertiary)
&:focus, &:focus,
&:hover &:hover
background-color: var(--input-color-bg-hover) background-color: var(--input-color-bg-hover)
color: var(--color-text) color: var(--color-text)
&::placeholder &::placeholder
color: var(--color-text-tertiary) color: var(--color-text-secondary)
// Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526 // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526
opacity: 1 opacity: 1
@ -107,14 +122,16 @@ label sup,
text-decoration: underline text-decoration: underline
.form-group .form-group
align-items: center
display: flex
justify-content: end
position: relative position: relative
.form-group-addon .form-group-addon
position: absolute position: absolute
right: var(--spacer-2) right: var(--spacer-2)
top: var(--spacer-2)
&:has([type="checkbox"]),
&:has([type="radio"])
justify-content: start
.toggle-bar .toggle-bar
border: var(--border-width) solid var(--border-color) border: var(--border-width) solid var(--border-color)
@ -177,3 +194,150 @@ label sup,
left: .2rem left: .2rem
height: 1.2rem height: 1.2rem
width: 1.2rem width: 1.2rem
select
&.form-control
&:hover
cursor: pointer
// Checkboxes and radios Bootstrap overrides
// TODO: remove overrides when cleaning up Bootstrap deprecated partials
.form-check,
.form-check-input
position: static
.form-check
line-height: var(--lh-sm)
+padding(0, left)
.form-check-input
+margin(0, left)
+margin(1, right)
+margin(0, top)
.form-check-label
+fw-normal
&:hover
cursor: pointer
[type="checkbox"],
[type="radio"]
height: var(--spacer)
min-height: 0
width: auto
[type="checkbox"]
&:hover
cursor: pointer
.form-check-custom
cursor: pointer
display: block
+fw-normal
+margin(3, bottom)
padding-left: calc(var(--spacer) * 2)
position: relative
input
height: 0
opacity: 0
width: 0
.form-check-custom-mark
background-color: var(--input-color-bg)
border: var(--border-width) solid var(--border-color)
height: var(--spacer-4)
left: 0
position: absolute
top: 0
transition: background-color var(--transition-speed)
width: var(--spacer-4)
&:after
content: ""
display: none
position: absolute
&:hover input ~ .form-check-custom-mark
background-color: var(--input-color-bg-hover)
input:checked ~ .form-check-custom-mark
background-color: var(--color-accent)
&:after
display: block
.form-check-custom-mark:after
border: solid white
border-width: 0 .2rem .2rem 0
display: none
height: 1.0rem
left: .8rem
top: .4rem
transform: rotate(45deg)
width: .6rem
.form-check-custom-radio
.form-check-custom-mark
border-radius: 50%
&:after
background: white
border: 0
border-radius: 50%
height: var(--spacer-2)
left: .6rem
top: .6rem
width: var(--spacer-2)
.slider-custom
background: var(--color-text-tertiary)
border: var(--border-width) solid var(--border-color)
border-radius: 1.2rem
height: var(--spacer-4)
min-height: 0
outline: none
+padding(1, x)
transition: opacity var(--transition-speed-slow)
-webkit-appearance: none
-webkit-transition: var(--transition-speed-slow)
width: 100%
&:active,
&:focus
background-color: var(--color-text-tertiary)
&:hover
background-color: var(--color-text-secondary)
&::-moz-range-thumb
background: white
border-radius: 50%
cursor: pointer
height: var(--spacer)
width: var(--spacer)
&::-webkit-slider-thumb
appearance: none
background: white
border-radius: 50%
cursor: pointer
height: var(--spacer)
-webkit-appearance: none
width: var(--spacer)
.slider-custom-steps
display: flex
justify-content: space-between
padding-left: 1.6rem
padding-right: 1.2rem
.slider-custom-steps-item
background-color: var(--color-text-tertiary)
height: var(--spacer-1)
transform: translateX(-.1rem)
width: .2rem
.slider-custom-steps-item-dots
border-radius: 50%
width: var(--spacer-1)

View File

@ -287,9 +287,11 @@ html[data-theme="dark"]
/* Config. */ /* Config. */
$font-path: '../assets/fonts' !default $font-path: '../assets/fonts' !default
// TODO: change and simplify Sass variables to CSS custom properties
$input-box-shadow: none $input-box-shadow: none
$input-border-color: rgba(black, .1) $input-border-color: rgba(black, .1)
$input-border-width: .2rem $input-border-width: .2rem
$input-transition: background-color var(--transition-speed-slow) var(--transition-timing-fast), border-color var(--transition-speed-slow) var(--transition-timing-fast), box-shadow var(--transition-speed-slow) var(--transition-timing-fast)
$label-margin-bottom: .2rem $label-margin-bottom: .2rem