mirror of
				https://github.com/ionic-team/ionic-framework.git
				synced 2025-11-04 12:11:57 +08:00 
			
		
		
		
	feat(input, textarea): dir is inherited to native form control (#30102)
Issue number: resolves #30193 resolves #29577 Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							18e26acb01
						
					
				
				
					commit
					504fb6a25f
				
			@ -338,10 +338,26 @@ export class Input implements ComponentInterface {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * dir is a globally enumerated attribute.
 | 
				
			||||||
 | 
					   * As a result, creating these as properties
 | 
				
			||||||
 | 
					   * can have unintended side effects. Instead, we
 | 
				
			||||||
 | 
					   * listen for attribute changes and inherit them
 | 
				
			||||||
 | 
					   * to the inner `<input>` element.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  @Watch('dir')
 | 
				
			||||||
 | 
					  onDirChanged(newValue: string) {
 | 
				
			||||||
 | 
					    this.inheritedAttributes = {
 | 
				
			||||||
 | 
					      ...this.inheritedAttributes,
 | 
				
			||||||
 | 
					      dir: newValue,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    forceUpdate(this);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentWillLoad() {
 | 
					  componentWillLoad() {
 | 
				
			||||||
    this.inheritedAttributes = {
 | 
					    this.inheritedAttributes = {
 | 
				
			||||||
      ...inheritAriaAttributes(this.el),
 | 
					      ...inheritAriaAttributes(this.el),
 | 
				
			||||||
      ...inheritAttributes(this.el, ['tabindex', 'title', 'data-form-type']),
 | 
					      ...inheritAttributes(this.el, ['tabindex', 'title', 'data-form-type', 'dir']),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -44,6 +44,24 @@ describe('input: rendering', () => {
 | 
				
			|||||||
    const bottomContent = page.body.querySelector('ion-input .input-bottom');
 | 
					    const bottomContent = page.body.querySelector('ion-input .input-bottom');
 | 
				
			||||||
    expect(bottomContent).toBe(null);
 | 
					    expect(bottomContent).toBe(null);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should inherit watched attributes', async () => {
 | 
				
			||||||
 | 
					    const page = await newSpecPage({
 | 
				
			||||||
 | 
					      components: [Input],
 | 
				
			||||||
 | 
					      html: '<ion-input label="Input" dir="ltr"></ion-input>',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const inputEl = page.body.querySelector('ion-input')!;
 | 
				
			||||||
 | 
					    const nativeEl = inputEl.querySelector('input')!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(nativeEl.getAttribute('dir')).toBe('ltr');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inputEl.setAttribute('dir', 'rtl');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await page.waitForChanges();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(nativeEl.getAttribute('dir')).toBe('rtl');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,24 @@ it('should inherit attributes', async () => {
 | 
				
			|||||||
  expect(nativeEl.getAttribute('data-form-type')).toBe('password');
 | 
					  expect(nativeEl.getAttribute('data-form-type')).toBe('password');
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					it('should inherit watched attributes', async () => {
 | 
				
			||||||
 | 
					  const page = await newSpecPage({
 | 
				
			||||||
 | 
					    components: [Textarea],
 | 
				
			||||||
 | 
					    html: '<ion-textarea dir="ltr"></ion-textarea>',
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const textareaEl = page.body.querySelector('ion-textarea')!;
 | 
				
			||||||
 | 
					  const nativeEl = textareaEl.querySelector('textarea')!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  expect(nativeEl.getAttribute('dir')).toBe('ltr');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  textareaEl.setAttribute('dir', 'rtl');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  await page.waitForChanges();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  expect(nativeEl.getAttribute('dir')).toBe('rtl');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Textarea uses emulated slots, so the internal
 | 
					 * Textarea uses emulated slots, so the internal
 | 
				
			||||||
 * behavior will not exactly match IonSelect's slots.
 | 
					 * behavior will not exactly match IonSelect's slots.
 | 
				
			||||||
 | 
				
			|||||||
@ -261,6 +261,22 @@ export class Textarea implements ComponentInterface {
 | 
				
			|||||||
    this.runAutoGrow();
 | 
					    this.runAutoGrow();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * dir is a globally enumerated attribute.
 | 
				
			||||||
 | 
					   * As a result, creating these as properties
 | 
				
			||||||
 | 
					   * can have unintended side effects. Instead, we
 | 
				
			||||||
 | 
					   * listen for attribute changes and inherit them
 | 
				
			||||||
 | 
					   * to the inner `<textarea>` element.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  @Watch('dir')
 | 
				
			||||||
 | 
					  onDirChanged(newValue: string) {
 | 
				
			||||||
 | 
					    this.inheritedAttributes = {
 | 
				
			||||||
 | 
					      ...this.inheritedAttributes,
 | 
				
			||||||
 | 
					      dir: newValue,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    forceUpdate(this);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * The `ionChange` event is fired when the user modifies the textarea's value.
 | 
					   * The `ionChange` event is fired when the user modifies the textarea's value.
 | 
				
			||||||
   * Unlike the `ionInput` event, the `ionChange` event is fired when
 | 
					   * Unlike the `ionInput` event, the `ionChange` event is fired when
 | 
				
			||||||
@ -331,7 +347,7 @@ export class Textarea implements ComponentInterface {
 | 
				
			|||||||
  componentWillLoad() {
 | 
					  componentWillLoad() {
 | 
				
			||||||
    this.inheritedAttributes = {
 | 
					    this.inheritedAttributes = {
 | 
				
			||||||
      ...inheritAriaAttributes(this.el),
 | 
					      ...inheritAriaAttributes(this.el),
 | 
				
			||||||
      ...inheritAttributes(this.el, ['data-form-type', 'title', 'tabindex']),
 | 
					      ...inheritAttributes(this.el, ['data-form-type', 'title', 'tabindex', 'dir']),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user