mirror of
				https://github.com/ionic-team/ionic-framework.git
				synced 2025-11-04 03:48:13 +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() {
 | 
			
		||||
    this.inheritedAttributes = {
 | 
			
		||||
      ...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');
 | 
			
		||||
    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');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 * behavior will not exactly match IonSelect's slots.
 | 
			
		||||
 | 
			
		||||
@ -261,6 +261,22 @@ export class Textarea implements ComponentInterface {
 | 
			
		||||
    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.
 | 
			
		||||
   * Unlike the `ionInput` event, the `ionChange` event is fired when
 | 
			
		||||
@ -331,7 +347,7 @@ export class Textarea implements ComponentInterface {
 | 
			
		||||
  componentWillLoad() {
 | 
			
		||||
    this.inheritedAttributes = {
 | 
			
		||||
      ...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