forked from tsai/budibase
Browse Source
* Beginnings of text field * Completed textfield component and its dependents * Minor bug fixesgh-pages
committed by
GitHub
17 changed files with 304 additions and 19 deletions
@ -0,0 +1,7 @@ |
|||||
|
<script> |
||||
|
import "@material/floating-label/mdc-floating-label.scss" |
||||
|
export let forInput = "" |
||||
|
export let text = "" |
||||
|
</script> |
||||
|
|
||||
|
<label for={forInput} class="mdc-floating-label">{text}</label> |
||||
@ -0,0 +1,14 @@ |
|||||
|
<script> |
||||
|
import "@material/notched-outline/mdc-notched-outline.scss" |
||||
|
export let useLabel = true |
||||
|
</script> |
||||
|
|
||||
|
<div class="mdc-notched-outline"> |
||||
|
<div class="mdc-notched-outline__leading" /> |
||||
|
{#if useLabel} |
||||
|
<div class="mdc-notched-outline__notch"> |
||||
|
<slot /> |
||||
|
</div> |
||||
|
{/if} |
||||
|
<div class="mdc-notched-outline__trailing" /> |
||||
|
</div> |
||||
@ -1,5 +1,4 @@ |
|||||
import h1 from "../H1.svelte"; |
import h1 from "../H1.svelte"; |
||||
import { button, icon } from "@BBMD"; |
import { button, icon, textfield } from "@BBMD"; |
||||
|
export default { h1, button, icon, textfield }; |
||||
export default { h1, button, icon }; |
|
||||
|
|
||||
|
|||||
@ -0,0 +1,173 @@ |
|||||
|
<script> |
||||
|
import { setContext, onMount } from "svelte" |
||||
|
import { MDCTextField } from "@material/textfield" |
||||
|
import { MDCLineRipple } from "@material/line-ripple" |
||||
|
|
||||
|
import ClassBuilder from "../ClassBuilder.js" |
||||
|
import NotchedOutline from "../Common/NotchedOutline.svelte" |
||||
|
import FloatingLabel from "../Common/FloatingLabel.svelte" |
||||
|
import Icon from "../Icon.svelte" |
||||
|
|
||||
|
const cb = new ClassBuilder("text-field", ["primary", "medium"]) |
||||
|
|
||||
|
let tf = null |
||||
|
let tfInstance = null |
||||
|
|
||||
|
onMount(() => { |
||||
|
if (!!tf) tfInstance = new MDCTextField(tf) |
||||
|
return () => { |
||||
|
!!tfInstance && tf.tfInstance.destroy() |
||||
|
tf = null |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
export let label = "" |
||||
|
export let variant = "standard" //outlined | filled | standard |
||||
|
export let disabled = false |
||||
|
export let fullwidth = false |
||||
|
export let colour = "primary" |
||||
|
export let size = "medium" |
||||
|
export let type = "text" //text or password |
||||
|
export let required = false |
||||
|
export let minLength = 0 |
||||
|
export let maxLength = 100 |
||||
|
export let useCharCounter = false |
||||
|
export let helperText = "" |
||||
|
export let errorText = "" |
||||
|
export let placeholder = "" |
||||
|
export let icon = "" |
||||
|
export let trailingIcon = false |
||||
|
export let textarea = false |
||||
|
export let rows = 4 |
||||
|
export let cols = 40 |
||||
|
export let validation = false |
||||
|
export let persistent = false |
||||
|
|
||||
|
let id = `${label}-${variant}` |
||||
|
let helperClasses = `${cb.block}-helper-text` |
||||
|
|
||||
|
let modifiers = [] |
||||
|
let customs = { colour } |
||||
|
|
||||
|
if (variant == "standard" || fullwidth) { |
||||
|
customs = { ...customs, variant } |
||||
|
} else { |
||||
|
modifiers.push(variant) |
||||
|
} |
||||
|
|
||||
|
if (!textarea && size !== "medium") { |
||||
|
customs = { ...customs, size } |
||||
|
} |
||||
|
|
||||
|
if (!label || fullwidth) { |
||||
|
modifiers.push("no-label") |
||||
|
} |
||||
|
|
||||
|
//TODO: Refactor - this could be handled better using an object as modifier instead of an array |
||||
|
if (fullwidth) modifiers.push("fullwidth") |
||||
|
if (disabled) modifiers.push("disabled") |
||||
|
if (textarea) modifiers.push("textarea") |
||||
|
if (persistent) helperClasses += ` ${cb.block}-helper-text--persistent` |
||||
|
if (validation) helperClasses += ` ${cb.block}-helper-text--validation` |
||||
|
|
||||
|
let useLabel = !!label && (!fullwidth || (fullwidth && textarea)) |
||||
|
let useIcon = !!icon && (!textarea && !fullwidth) |
||||
|
|
||||
|
$: useNotchedOutline = variant == "outlined" || textarea |
||||
|
|
||||
|
if (useIcon) { |
||||
|
setContext("BBMD:icon:context", "text-field") |
||||
|
trailingIcon |
||||
|
? modifiers.push("with-trailing-icon") |
||||
|
: modifiers.push("with-leading-icon") |
||||
|
} |
||||
|
|
||||
|
$: renderLeadingIcon = useIcon && !trailingIcon |
||||
|
$: renderTrailingIcon = useIcon && trailingIcon |
||||
|
|
||||
|
const blockClasses = cb.blocks({ modifiers, customs }) |
||||
|
const inputClasses = cb.elements("input") |
||||
|
|
||||
|
let renderMaxLength = !!maxLength ? `0 / ${maxLength}` : "0" |
||||
|
|
||||
|
function focus(event) { |
||||
|
tfInstance.focus() |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<!-- |
||||
|
TODO:Needs error handling - this will depend on how Budibase handles errors |
||||
|
--> |
||||
|
|
||||
|
<div class="textfield-container" class:fullwidth> |
||||
|
<div bind:this={tf} class={blockClasses}> |
||||
|
{#if textarea} |
||||
|
{#if useCharCounter} |
||||
|
<div class="mdc-text-field-character-counter">{renderMaxLength}</div> |
||||
|
{/if} |
||||
|
<textarea |
||||
|
{id} |
||||
|
class={inputClasses} |
||||
|
class:fullwidth |
||||
|
{disabled} |
||||
|
{rows} |
||||
|
{cols} |
||||
|
{required} |
||||
|
{placeholder} |
||||
|
{minLength} |
||||
|
{maxLength} |
||||
|
on:change /> |
||||
|
{:else} |
||||
|
{#if renderLeadingIcon} |
||||
|
<Icon {icon} /> |
||||
|
{/if} |
||||
|
<input |
||||
|
{id} |
||||
|
{disabled} |
||||
|
on:focus={focus} |
||||
|
class={inputClasses} |
||||
|
{type} |
||||
|
{required} |
||||
|
placeholder={!!label && fullwidth ? label : placeholder} |
||||
|
{minLength} |
||||
|
{maxLength} |
||||
|
aria-label={`Textfield ${variant}`} |
||||
|
on:change /> |
||||
|
{#if renderTrailingIcon} |
||||
|
<Icon {icon} /> |
||||
|
{/if} |
||||
|
{#if variant !== 'outlined'} |
||||
|
<div class="mdc-line-ripple" /> |
||||
|
{/if} |
||||
|
{/if} |
||||
|
{#if useNotchedOutline} |
||||
|
<NotchedOutline {useLabel}> |
||||
|
{#if useLabel} |
||||
|
<FloatingLabel forInput={id} text={label} /> |
||||
|
{/if} |
||||
|
</NotchedOutline> |
||||
|
{:else if useLabel} |
||||
|
<FloatingLabel forInput={id} text={label} /> |
||||
|
{/if} |
||||
|
</div> |
||||
|
<!-- TODO: Split to own component? --> |
||||
|
<div class="mdc-text-field-helper-line"> |
||||
|
<div class={helperClasses}>{!!errorText ? errorText : helperText}</div> |
||||
|
{#if useCharCounter && !textarea} |
||||
|
<div class="mdc-text-field-character-counter">{renderMaxLength}</div> |
||||
|
{/if} |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<style> |
||||
|
.textfield-container { |
||||
|
padding: 8px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
width: 227px; |
||||
|
} |
||||
|
|
||||
|
.fullwidth { |
||||
|
width: 100%; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,5 @@ |
|||||
|
@import "@material/textfield/mdc-text-field.scss"; |
||||
|
@import "@material/line-ripple/mdc-line-ripple.scss"; |
||||
|
@import "./mixins.scss"; |
||||
|
|
||||
|
@include bbmd-textfield-styles(); |
||||
@ -0,0 +1,45 @@ |
|||||
|
@import "@material/feature-targeting/_functions.scss"; |
||||
|
@import "@material/feature-targeting/_mixins.scss"; |
||||
|
|
||||
|
@mixin bbmd-textfield-styles($query: mdc-feature-all()) { |
||||
|
$feat-structure: mdc-feature-create-target($query, structure); |
||||
|
|
||||
|
.mdc-text-field { |
||||
|
&.bbmd-mdc-text-field--size-small { |
||||
|
@include mdc-text-field-height(48px); |
||||
|
} |
||||
|
|
||||
|
&.bbmd-mdc-text-field--size-large { |
||||
|
@include mdc-text-field-height(64px); |
||||
|
} |
||||
|
|
||||
|
&.bbmd-mdc-text-field--colour-secondary { |
||||
|
&.mdc-text-field--focused { |
||||
|
.mdc-floating-label--float-above { |
||||
|
color: var(--mdc-theme-secondary); |
||||
|
} |
||||
|
} |
||||
|
.mdc-line-ripple--active { |
||||
|
background-color: var(--mdc-theme-secondary); |
||||
|
} |
||||
|
|
||||
|
&.mdc-text-field--outlined, |
||||
|
&.mdc-text-field--textarea { |
||||
|
@include mdc-text-field-focused-outline-color(secondary); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.bbmd-mdc-text-field--variant-standard { |
||||
|
@include mdc-text-field-fill-color(transparent); |
||||
|
&:before { |
||||
|
background-color: transparent; |
||||
|
} |
||||
|
} |
||||
|
+ .mdc-text-field-helper-line { |
||||
|
@include mdc-feature-targets($feat-structure) { |
||||
|
padding-right: 0px; |
||||
|
padding-left: 0px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
import "./_index.scss" |
||||
|
export { default as textfield } from "./Textfield.svelte" |
||||
@ -1,4 +1,5 @@ |
|||||
export { default as h1 } from "./H1.svelte"; |
export { default as h1 } from "./H1.svelte"; |
||||
|
|
||||
export { default as icon } from "./Icon.svelte"; |
export { default as icon } from "./Icon.svelte"; |
||||
export { button } from "./Button"; |
export { button } from "./Button"; |
||||
|
export { textfield } from "./Textfield"; |
||||
|
|||||
Loading…
Reference in new issue