Skip to content

Commit

Permalink
fix: clone attributes from component props instead of attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
borisdiakur committed Dec 8, 2021
1 parent 29f4680 commit d468293
Show file tree
Hide file tree
Showing 27 changed files with 308 additions and 165 deletions.
5 changes: 4 additions & 1 deletion src/docs/components/docs-page-nav/docs-page-nav.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@

.docs-page-nav__push {
margin-left: auto;
margin-right: var(--ld-sp-16);

.docs-page-nav--has-slot & {
margin-right: var(--ld-sp-16);
}
}

.docs-page-nav--has-slot {
Expand Down
31 changes: 19 additions & 12 deletions src/liquid/components/ld-button/ld-button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Element, h, Method, Prop } from '@stencil/core'
import { Component, Element, h, Method, Prop, State } from '@stencil/core'
import { getClassNames } from 'src/liquid/utils/getClassNames'
import { cloneAttributes } from '../../utils/cloneAttributes'

Expand All @@ -13,10 +13,12 @@ import { cloneAttributes } from '../../utils/cloneAttributes'
styleUrl: 'ld-button.css',
shadow: true,
})
export class LdButton implements InnerFocusable {
export class LdButton implements InnerFocusable, ClonesAttributes {
@Element() el: HTMLElement
private button: HTMLAnchorElement | HTMLButtonElement

private attributesObserver: MutationObserver

/** Align text. */
@Prop({ mutable: true }) alignText?: 'left' | 'right'

Expand Down Expand Up @@ -52,7 +54,7 @@ export class LdButton implements InnerFocusable {
* See [mdn docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-href)
* for more information on the `href` attribute.
*/
@Prop({ reflect: true }) href?: string
@Prop() href?: string

/** Justify content. */
@Prop({ mutable: true }) justifyContent?: 'start' | 'end' | 'between'
Expand Down Expand Up @@ -88,6 +90,8 @@ export class LdButton implements InnerFocusable {
/** Defines the value associated with the button’s `name` when it’s submitted with the form data. */
@Prop() value?: string

@State() clonedAttributes

/**
* Sets focus on the button
*/
Expand All @@ -114,6 +118,7 @@ export class LdButton implements InnerFocusable {
this.el.removeEventListener('click', this.handleClick, {
capture: true,
})
this.attributesObserver.disconnect()
}

private clickHiddenButton() {
Expand Down Expand Up @@ -162,6 +167,15 @@ export class LdButton implements InnerFocusable {
}

componentWillLoad() {
this.attributesObserver = cloneAttributes.call(this, [
'align-text',
'justify-content',
'mode',
'progress',
'size',
this.type === 'submit' ? 'type' : undefined, // submit is default
])

this.el.querySelectorAll('ld-icon').forEach((icon) => {
if (this.size !== undefined) {
icon.setAttribute('size', this.size)
Expand Down Expand Up @@ -193,7 +207,7 @@ export class LdButton implements InnerFocusable {

const Tag = this.href ? 'a' : 'button'

const hasProgress = this.progress !== undefined
const hasProgress = this.progress !== undefined && this.progress !== null

const styleProgress = !isNaN(parseFloat(this.progress + ''))
? { '--ld-button-progress': this.progress + '' }
Expand All @@ -204,21 +218,14 @@ export class LdButton implements InnerFocusable {

return (
<Tag
{...this.clonedAttributes}
aria-busy={hasProgress ? 'true' : undefined}
aria-disabled={this.disabled ? 'true' : undefined}
aria-live="polite"
class={cl}
part="button focusable"
ref={(el: HTMLAnchorElement | HTMLButtonElement) => (this.button = el)}
rel={this.target === '_blank' ? 'noreferrer noopener' : undefined}
{...cloneAttributes(this.el, [
'align-text',
'justify-content',
'mode',
'progress',
'size',
])}
href={this.href}
>
<slot />
{hasProgress && (
Expand Down
2 changes: 1 addition & 1 deletion src/liquid/components/ld-button/test/ld-button.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
jest.mock('../../../utils/cloneAttributes')
import { newSpecPage } from '@stencil/core/testing'
import { LdButton } from '../ld-button'
import '../../../utils/mutationObserver'

const mockClickHiddenButton = (
form: HTMLFormElement,
Expand Down
32 changes: 22 additions & 10 deletions src/liquid/components/ld-checkbox/ld-checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { Component, Element, h, Host, Method, Prop, Watch } from '@stencil/core'
import {
Component,
Element,
h,
Host,
Method,
Prop,
State,
Watch,
} from '@stencil/core'
import { cloneAttributes } from '../../utils/cloneAttributes'
import { getClassNames } from '../../utils/getClassNames'

Expand All @@ -12,15 +21,14 @@ import { getClassNames } from '../../utils/getClassNames'
styleUrl: 'ld-checkbox.css',
shadow: true,
})
export class LdCheckbox implements InnerFocusable {
export class LdCheckbox implements InnerFocusable, ClonesAttributes {
@Element() el: HTMLInputElement

private attributesObserver: MutationObserver

private input: HTMLInputElement
private hiddenInput: HTMLInputElement

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

/** Automatically focus the form control when the page is loaded. */
@Prop() autofocus?: boolean

Expand Down Expand Up @@ -60,6 +68,8 @@ export class LdCheckbox implements InnerFocusable {
/** The input value. */
@Prop() value: string

@State() clonedAttributes

/**
* Sets focus on the checkbox
*/
Expand Down Expand Up @@ -152,11 +162,9 @@ export class LdCheckbox implements InnerFocusable {
}

componentWillLoad() {
const outerForm = this.el.closest('form')
this.attributesObserver = cloneAttributes.call(this, ['tone', 'mode'])

if (outerForm && !this.autocomplete) {
this.autocomplete = outerForm.getAttribute('autocomplete')
}
const outerForm = this.el.closest('form')

if (this.name && (outerForm || this.form)) {
this.createHiddenInput()
Expand All @@ -179,6 +187,10 @@ export class LdCheckbox implements InnerFocusable {
}
}

disconnectedCallback() {
this.attributesObserver.disconnect()
}

render() {
const cl = [
'ld-checkbox',
Expand All @@ -190,12 +202,12 @@ export class LdCheckbox implements InnerFocusable {
return (
<Host part="root" class={getClassNames(cl)} onClick={this.handleClick}>
<input
{...this.clonedAttributes}
part="input focusable"
onBlur={this.handleBlur.bind(this)}
onFocus={this.handleFocus}
ref={(ref) => (this.input = ref)}
type="checkbox"
{...cloneAttributes(this.el, ['autocomplete', 'tone', 'mode'])}
disabled={this.disabled}
checked={this.checked}
/>
Expand Down
1 change: 0 additions & 1 deletion src/liquid/components/ld-checkbox/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,6 @@ The `ld-checkbox` Web Component provides a low level API for integrating the com

| Property | Attribute | Description | Type | Default |
| --------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------- | ----------- |
| `autocomplete` | `autocomplete` | Hint for form autofill feature. | `string` | `undefined` |
| `autofocus` | `autofocus` | Automatically focus the form control when the page is loaded. | `boolean` | `undefined` |
| `checked` | `checked` | Indicates whether the checkbox is checked. | `boolean` | `undefined` |
| `disabled` | `disabled` | Disabled state of the checkbox. | `boolean` | `undefined` |
Expand Down
3 changes: 2 additions & 1 deletion src/liquid/components/ld-checkbox/test/ld-checkbox.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { newSpecPage } from '@stencil/core/testing'
jest.mock('../../../utils/cloneAttributes')
import { LdCheckbox } from '../ld-checkbox'
import '../../../utils/mutationObserver'

describe('ld-checkbox', () => {
it('renders', async () => {
Expand Down Expand Up @@ -173,6 +173,7 @@ describe('ld-checkbox', () => {
expect(ldCheckbox.querySelector('input')).toHaveProperty('value', 'test')

ldCheckbox.removeAttribute('value')
ldCheckbox.value = undefined
await waitForChanges()

expect(ldCheckbox.querySelector('input').getAttribute('value')).toEqual(
Expand Down
3 changes: 1 addition & 2 deletions src/liquid/components/ld-input/ld-input.css
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@
height: 100%;
max-height: inherit;
min-height: inherit;
max-width: inherit;
min-width: inherit;
flex-grow: 1;
}

::slotted(ld-button),
Expand Down
48 changes: 42 additions & 6 deletions src/liquid/components/ld-input/ld-input.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { Component, Element, h, Host, Method, Prop, Watch } from '@stencil/core'
import {
Component,
Element,
h,
Host,
Method,
Prop,
State,
Watch,
} from '@stencil/core'
import { cloneAttributes } from '../../utils/cloneAttributes'
import { getClassNames } from '../../utils/getClassNames'

Expand Down Expand Up @@ -27,8 +36,11 @@ import { getClassNames } from '../../utils/getClassNames'
styleUrl: 'ld-input.css',
shadow: true,
})
export class LdInput implements InnerFocusable {
export class LdInput implements InnerFocusable, ClonesAttributes {
@Element() el: HTMLInputElement | HTMLTextAreaElement

private attributesObserver: MutationObserver

private hiddenInput?: HTMLInputElement
private input: HTMLInputElement | HTMLTextAreaElement

Expand All @@ -44,6 +56,9 @@ export class LdInput implements InnerFocusable {
/** Media capture input method in file upload controls. */
@Prop() capture?: string

/** The number of columns. */
@Prop() cols?: number

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

Expand Down Expand Up @@ -95,6 +110,9 @@ export class LdInput implements InnerFocusable {
/** A value is required for the form to be submittable. */
@Prop() required?: boolean

/** The number of rows. */
@Prop() rows?: number

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

Expand All @@ -110,6 +128,8 @@ export class LdInput implements InnerFocusable {
/** The input value. */
@Prop({ mutable: true }) value?: string

@State() clonedAttributes

/**
* Sets focus on the input
*/
Expand All @@ -131,7 +151,9 @@ export class LdInput implements InnerFocusable {
}

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

if (this.name) {
this.hiddenInput.name = this.name
Expand Down Expand Up @@ -168,6 +190,11 @@ export class LdInput implements InnerFocusable {
}

componentWillLoad() {
this.attributesObserver = cloneAttributes.call(this, [
'multiline',
'autocomplete',
])

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

if (outerForm && !this.autocomplete) {
Expand All @@ -176,9 +203,12 @@ export class LdInput implements InnerFocusable {

if (this.name && (outerForm || this.form)) {
this.createHiddenInput()
this.hiddenInput.dirName = this.dirname
this.hiddenInput.name = this.name

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

if (this.form) {
this.hiddenInput.setAttribute('form', this.form)
}
Expand Down Expand Up @@ -281,6 +311,10 @@ export class LdInput implements InnerFocusable {
}
}

disconnectedCallback() {
this.attributesObserver.disconnect()
}

render() {
const cl = getClassNames([
'ld-input',
Expand All @@ -290,15 +324,17 @@ export class LdInput implements InnerFocusable {
])

if (this.multiline) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { type, ...clonedAttributesWithoutType } = this.clonedAttributes
return (
<Host class={cl} onClick={this.handleClick}>
<textarea
{...clonedAttributesWithoutType}
onBlur={this.handleBlur}
onFocus={this.handleFocus}
onInput={this.handleInput.bind(this)}
part="input focusable"
ref={(el) => (this.input = el)}
{...cloneAttributes(this.el, ['multiline', 'type'])}
/>
{this.type === 'file' && (
<span class="ld-input__placeholder" part="placeholder">
Expand All @@ -313,14 +349,14 @@ export class LdInput implements InnerFocusable {
<Host class={cl} onClick={this.handleClick}>
<slot name="start"></slot>
<input
{...this.clonedAttributes}
autocomplete={this.autocomplete}
onBlur={this.handleBlur}
onFocus={this.handleFocus}
onInput={this.handleInput.bind(this)}
onKeyDown={this.handleKeyDown}
part="input focusable"
ref={(el) => (this.input = el)}
{...cloneAttributes(this.el, ['autocomplete'])}
/>
{this.type === 'file' && (
<span class="ld-input__placeholder" part="placeholder">
Expand Down
2 changes: 2 additions & 0 deletions src/liquid/components/ld-input/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,7 @@ The `ld-input` Web Component does not provide any properties or methods for vali
| `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` |
| `cols` | `cols` | The number of columns. | `number` | `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` |
Expand All @@ -1019,6 +1020,7 @@ The `ld-input` Web Component does not provide any properties or methods for vali
| `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` |
| `rows` | `rows` | The number of rows. | `number` | `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` |
Expand Down
Loading

0 comments on commit d468293

Please sign in to comment.