Skip to content

Commit

Permalink
fix(ld-input): prop forwarding
Browse files Browse the repository at this point in the history
  • Loading branch information
renet authored Dec 1, 2021
1 parent 9fcd2c6 commit 191e048
Show file tree
Hide file tree
Showing 6 changed files with 381 additions and 61 deletions.
161 changes: 127 additions & 34 deletions src/liquid/components/ld-input/ld-input.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component, Element, h, Host, Method, Prop, Watch } from '@stencil/core'
import { cloneAttributes } from '../../utils/cloneAttributes'
import { getClassNames } from '../../utils/getClassNames'

/**
* The `ld-input` component. You can use it in conjunction with the `ld-label`
Expand Down Expand Up @@ -31,35 +32,83 @@ export class LdInput implements InnerFocusable {
private hiddenInput?: HTMLInputElement
private input: HTMLInputElement | HTMLTextAreaElement

/** Used to specify the name of the control. */
@Prop() name?: string
/** Hint for expected file type in file upload controls. */
@Prop() accept?: string

/** Input tone. Use `'dark'` on white backgrounds. Default is a light tone. */
@Prop() tone: 'dark'
/** Hint for form autofill feature. */
@Prop({ mutable: true, reflect: true }) autocomplete?: string

/** The input value. */
@Prop({ mutable: true, reflect: true }) value: string
/** Automatically focus the form control when the page is loaded. */
@Prop() autofocus?: boolean

/** Media capture input method in file upload controls. */
@Prop() capture?: string

/** Name of form field to use for sending the element's directionality in form submission. */
@Prop() dirname?: string

/** Whether the form control is disabled. */
@Prop() disabled?: boolean

/** Associates the control with a form element. */
@Prop() form?: string

/** Set this property to `true` in order to mark the field visually as invalid. */
@Prop() invalid: boolean
@Prop() invalid?: boolean

/** The input placeholder. */
@Prop() placeholder: string
/** Value of the id attribute of the `<datalist>` of autocomplete options. */
@Prop() list?: string

/** Hint for form autofill feature. */
@Prop({ mutable: true, reflect: true }) autocomplete: string
/** Maximum value. */
@Prop() max?: string

/** The input type. */
@Prop() type: string
/** Maximum length (number of characters) of `value`. */
@Prop() maxlength?: string

/** Size of the input. */
@Prop() size?: 'sm' | 'lg'
/** Minimum value. */
@Prop() min?: string

/** Minimum length (number of characters) of `value`. */
@Prop() minlength?: string

/**
* Uses textarea instead of input internally. Setting this attribute to true
* disables the attribute type and both slots.
*/
@Prop() multiline: boolean
@Prop() multiline?: boolean

/** Boolean. Whether to allow multiple values. */
@Prop() multiple?: boolean

/** Used to specify the name of the control. */
@Prop() name?: string

/** Pattern the `value` must match to be valid. */
@Prop() pattern?: string

/** The input placeholder. */
@Prop() placeholder?: string

/** The value is not editable. */
@Prop() readonly?: boolean

/** A value is required for the form to be submittable. */
@Prop() required?: boolean

/** Size of the input. */
@Prop() size?: 'sm' | 'lg'

/** Incremental values that are valid. */
@Prop() step?: string

/** Input tone. Use `'dark'` on white backgrounds. Default is a light tone. */
@Prop() tone?: 'dark'

/** The input type. */
@Prop() type: string

/** The input value. */
@Prop({ mutable: true }) value?: string

/**
* Sets focus on the input
Expand All @@ -71,25 +120,66 @@ export class LdInput implements InnerFocusable {
}
}

@Watch('dirname')
@Watch('form')
@Watch('name')
@Watch('value')
updateValue() {
updateHiddenInput() {
const outerForm = this.el.closest('form')
if (!this.hiddenInput && this.name && (outerForm || this.form)) {
this.hiddenInput = document.createElement('input')
this.el.appendChild(this.hiddenInput)
}

if (this.hiddenInput) {
this.hiddenInput.value = this.value
this.hiddenInput.dirName = this.dirname

if (this.name) {
this.hiddenInput.name = this.name
} else if (this.hiddenInput.name) {
this.hiddenInput.remove()
this.hiddenInput = undefined
return
}

if (this.form) {
this.hiddenInput.setAttribute('form', this.form)
} else if (this.hiddenInput.getAttribute('form')) {
if (outerForm) {
this.hiddenInput.removeAttribute('form')
} else {
this.hiddenInput.remove()
this.hiddenInput = undefined
return
}
}

if (this.value) {
this.hiddenInput.value = this.value
} else if (this.hiddenInput.value) {
this.hiddenInput.removeAttribute('value')
}
}
}

componentWillLoad() {
const outerForm = this.el.closest('form')

if (outerForm) {
if (!this.autocomplete) {
this.autocomplete = outerForm.getAttribute('autocomplete')
}
if (outerForm && !this.autocomplete) {
this.autocomplete = outerForm.getAttribute('autocomplete')
}

if (outerForm || this.form) {
if (this.name) {
this.hiddenInput = document.createElement('input')
this.hiddenInput.dirName = this.dirname
this.hiddenInput.type = 'hidden'
this.hiddenInput.name = this.name

if (this.form) {
this.hiddenInput.setAttribute('form', this.form)
}

if (this.value) {
this.hiddenInput.value = this.value
}
Expand Down Expand Up @@ -136,6 +226,12 @@ export class LdInput implements InnerFocusable {
})
}

componentDidLoad() {
if (this.autofocus) {
this.focusInner()
}
}

private handleBlur = (ev: FocusEvent) => {
setTimeout(() => {
this.el.dispatchEvent(ev)
Expand Down Expand Up @@ -186,10 +282,12 @@ export class LdInput implements InnerFocusable {
}

render() {
let cl = 'ld-input'
if (this.size) cl += ` ld-input--${this.size}`
if (this.tone) cl += ` ld-input--${this.tone}`
if (this.invalid) cl += ' ld-input--invalid'
const cl = getClassNames([
'ld-input',
this.size && `ld-input--${this.size}`,
this.tone && `ld-input--${this.tone}`,
this.invalid && 'ld-input--invalid',
])

if (this.multiline) {
return (
Expand All @@ -199,10 +297,8 @@ export class LdInput implements InnerFocusable {
onFocus={this.handleFocus}
onInput={this.handleInput.bind(this)}
part="input focusable"
placeholder={this.placeholder}
ref={(el) => (this.input = el)}
{...cloneAttributes(this.el)}
value={this.value}
{...cloneAttributes(this.el, ['multiline', 'type'])}
/>
{this.type === 'file' && (
<span class="ld-input__placeholder" part="placeholder">
Expand All @@ -217,17 +313,14 @@ export class LdInput implements InnerFocusable {
<Host class={cl} onClick={this.handleClick}>
<slot name="start"></slot>
<input
autocomplete={this.autocomplete}
onBlur={this.handleBlur}
onFocus={this.handleFocus}
onInput={this.handleInput.bind(this)}
onKeyDown={this.handleKeyDown}
part="input focusable"
placeholder={this.placeholder}
ref={(el) => (this.input = el)}
type={this.type}
{...cloneAttributes(this.el)}
autocomplete={this.autocomplete}
value={this.value}
{...cloneAttributes(this.el, ['autocomplete'])}
/>
{this.type === 'file' && (
<span class="ld-input__placeholder" part="placeholder">
Expand Down
24 changes: 20 additions & 4 deletions src/liquid/components/ld-input/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -963,16 +963,16 @@ The `ld-input` Web Component does not provide any properties or methods for vali
return true
}
username.addEventListener('input', ev => {
validateInput(username, usernameErrorMessage)
validateInput(username, form.login.value, usernameErrorMessage)
})
username.addEventListener('blur', ev => {
validateInput(username, usernameErrorMessage)
validateInput(username, form.login.value, usernameErrorMessage)
})
password.addEventListener('input', ev => {
validateInput(password, passwordErrorMessage)
validateInput(password, form.password.value, passwordErrorMessage)
})
password.addEventListener('blur', ev => {
validateInput(password, passwordErrorMessage)
validateInput(password, form.password.value, passwordErrorMessage)
})
form.addEventListener('submit', ev => {
ev.preventDefault()
Expand All @@ -997,14 +997,30 @@ The `ld-input` Web Component does not provide any properties or methods for vali

| Property | Attribute | Description | Type | Default |
| -------------- | -------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------ | ----------- |
| `accept` | `accept` | Hint for expected file type in file upload controls. | `string` | `undefined` |
| `autocomplete` | `autocomplete` | Hint for form autofill feature. | `string` | `undefined` |
| `autofocus` | `autofocus` | Automatically focus the form control when the page is loaded. | `boolean` | `undefined` |
| `capture` | `capture` | Media capture input method in file upload controls. | `string` | `undefined` |
| `dirname` | `dirname` | Name of form field to use for sending the element's directionality in form submission. | `string` | `undefined` |
| `disabled` | `disabled` | Whether the form control is disabled. | `boolean` | `undefined` |
| `form` | `form` | Associates the control with a form element. | `string` | `undefined` |
| `invalid` | `invalid` | Set this property to `true` in order to mark the field visually as invalid. | `boolean` | `undefined` |
| `key` | `key` | for tracking the node's identity when working with lists | `string \| number` | `undefined` |
| `list` | `list` | Value of the id attribute of the `<datalist>` of autocomplete options. | `string` | `undefined` |
| `max` | `max` | Maximum value. | `string` | `undefined` |
| `maxlength` | `maxlength` | Maximum length (number of characters) of `value`. | `string` | `undefined` |
| `min` | `min` | Minimum value. | `string` | `undefined` |
| `minlength` | `minlength` | Minimum length (number of characters) of `value`. | `string` | `undefined` |
| `multiline` | `multiline` | Uses textarea instead of input internally. Setting this attribute to true disables the attribute type and both slots. | `boolean` | `undefined` |
| `multiple` | `multiple` | Boolean. Whether to allow multiple values. | `boolean` | `undefined` |
| `name` | `name` | Used to specify the name of the control. | `string` | `undefined` |
| `pattern` | `pattern` | Pattern the `value` must match to be valid. | `string` | `undefined` |
| `placeholder` | `placeholder` | The input placeholder. | `string` | `undefined` |
| `readonly` | `readonly` | The value is not editable. | `boolean` | `undefined` |
| `ref` | `ref` | reference to component | `any` | `undefined` |
| `required` | `required` | A value is required for the form to be submittable. | `boolean` | `undefined` |
| `size` | `size` | Size of the input. | `"lg" \| "sm"` | `undefined` |
| `step` | `step` | Incremental values that are valid. | `string` | `undefined` |
| `tone` | `tone` | Input tone. Use `'dark'` on white backgrounds. Default is a light tone. | `"dark"` | `undefined` |
| `type` | `type` | The input type. | `string` | `undefined` |
| `value` | `value` | The input value. | `string` | `undefined` |
Expand Down
Loading

0 comments on commit 191e048

Please sign in to comment.