mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-08 23:58:13 +08:00
chore(packages): move the packages to root
This commit is contained in:
318
core/src/components/textarea/readme.md
Normal file
318
core/src/components/textarea/readme.md
Normal file
@ -0,0 +1,318 @@
|
||||
# ion-textarea
|
||||
|
||||
The textarea component is used for multi-line text input. A native textarea element is rendered inside of the component. The user experience and interactivity of the textarea component is improved by having control over the native textarea.
|
||||
|
||||
Unlike the native textarea element, the Ionic textarea does not support loading its value from the inner content. The textarea value should be set in the `value` attribute.
|
||||
|
||||
The textarea component accepts the [native textarea attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) in addition to the Ionic properties.
|
||||
|
||||
```html
|
||||
<!-- Default textarea -->
|
||||
<ion-textarea></ion-textarea>
|
||||
|
||||
<!-- Textarea in an item with a placeholder -->
|
||||
<ion-item>
|
||||
<ion-textarea placeholder="Enter more information here..."></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<!-- Textarea in an item with a floating label -->
|
||||
<ion-item>
|
||||
<ion-label floating>Description</ion-label>
|
||||
<ion-textarea></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<!-- Disabled and readonly textarea in an item with a stacked label -->
|
||||
<ion-item>
|
||||
<ion-label stacked>Summary</ion-label>
|
||||
<ion-textarea
|
||||
disabled
|
||||
readonly
|
||||
value="Ionic enables developers to build performant, high-quality mobile apps.">
|
||||
</ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<!-- Textarea that clears the value on edit -->
|
||||
<ion-item>
|
||||
<ion-label>Comment</ion-label>
|
||||
<ion-textarea clear-on-edit="true"></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<!-- Textarea with custom number of rows and cols -->
|
||||
<ion-item>
|
||||
<ion-label>Notes</ion-label>
|
||||
<ion-textarea rows="6" cols="20" placeholder="Enter any notes here..."></ion-textarea>
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
#### autocapitalize
|
||||
|
||||
string
|
||||
|
||||
Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Defaults to `"none"`.
|
||||
|
||||
|
||||
#### autocomplete
|
||||
|
||||
string
|
||||
|
||||
Indicates whether the value of the control can be automatically completed by the browser. Defaults to `"off"`.
|
||||
|
||||
|
||||
#### autofocus
|
||||
|
||||
boolean
|
||||
|
||||
This Boolean attribute lets you specify that a form control should have input focus when the page loads. Defaults to `false`.
|
||||
|
||||
|
||||
#### clearOnEdit
|
||||
|
||||
boolean
|
||||
|
||||
If true, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types.
|
||||
|
||||
|
||||
#### cols
|
||||
|
||||
number
|
||||
|
||||
The visible width of the text control, in average character widths. If it is specified, it must be a positive integer.
|
||||
|
||||
|
||||
#### debounce
|
||||
|
||||
number
|
||||
|
||||
Set the amount of time, in milliseconds, to wait to trigger the `ionInput` event after each keystroke. Default `0`.
|
||||
|
||||
|
||||
#### disabled
|
||||
|
||||
boolean
|
||||
|
||||
If true, the user cannot interact with the textarea. Defaults to `false`.
|
||||
|
||||
|
||||
#### maxlength
|
||||
|
||||
number
|
||||
|
||||
If the value of the type attribute is `text`, `email`, `search`, `password`, `tel`, or `url`, this attribute specifies the maximum number of characters that the user can enter.
|
||||
|
||||
|
||||
#### minlength
|
||||
|
||||
number
|
||||
|
||||
If the value of the type attribute is `text`, `email`, `search`, `password`, `tel`, or `url`, this attribute specifies the minimum number of characters that the user can enter.
|
||||
|
||||
|
||||
#### name
|
||||
|
||||
string
|
||||
|
||||
The name of the control, which is submitted with the form data.
|
||||
|
||||
|
||||
#### placeholder
|
||||
|
||||
string
|
||||
|
||||
Instructional text that shows before the input has a value.
|
||||
|
||||
|
||||
#### readonly
|
||||
|
||||
boolean
|
||||
|
||||
If true, the user cannot modify the value. Defaults to `false`.
|
||||
|
||||
|
||||
#### required
|
||||
|
||||
boolean
|
||||
|
||||
If true, the user must fill in a value before submitting a form.
|
||||
|
||||
|
||||
#### rows
|
||||
|
||||
number
|
||||
|
||||
The number of visible text lines for the control.
|
||||
|
||||
|
||||
#### spellcheck
|
||||
|
||||
boolean
|
||||
|
||||
If true, the element will have its spelling and grammar checked. Defaults to `false`.
|
||||
|
||||
|
||||
#### value
|
||||
|
||||
string
|
||||
|
||||
The value of the textarea.
|
||||
|
||||
|
||||
#### wrap
|
||||
|
||||
string
|
||||
|
||||
Indicates how the control wraps text. Possible values are: `"hard"`, `"soft"`, `"off"`.
|
||||
|
||||
|
||||
## Attributes
|
||||
|
||||
#### autocapitalize
|
||||
|
||||
string
|
||||
|
||||
Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Defaults to `"none"`.
|
||||
|
||||
|
||||
#### autocomplete
|
||||
|
||||
string
|
||||
|
||||
Indicates whether the value of the control can be automatically completed by the browser. Defaults to `"off"`.
|
||||
|
||||
|
||||
#### autofocus
|
||||
|
||||
boolean
|
||||
|
||||
This Boolean attribute lets you specify that a form control should have input focus when the page loads. Defaults to `false`.
|
||||
|
||||
|
||||
#### clear-on-edit
|
||||
|
||||
boolean
|
||||
|
||||
If true, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types.
|
||||
|
||||
|
||||
#### cols
|
||||
|
||||
number
|
||||
|
||||
The visible width of the text control, in average character widths. If it is specified, it must be a positive integer.
|
||||
|
||||
|
||||
#### debounce
|
||||
|
||||
number
|
||||
|
||||
Set the amount of time, in milliseconds, to wait to trigger the `ionInput` event after each keystroke. Default `0`.
|
||||
|
||||
|
||||
#### disabled
|
||||
|
||||
boolean
|
||||
|
||||
If true, the user cannot interact with the textarea. Defaults to `false`.
|
||||
|
||||
|
||||
#### maxlength
|
||||
|
||||
number
|
||||
|
||||
If the value of the type attribute is `text`, `email`, `search`, `password`, `tel`, or `url`, this attribute specifies the maximum number of characters that the user can enter.
|
||||
|
||||
|
||||
#### minlength
|
||||
|
||||
number
|
||||
|
||||
If the value of the type attribute is `text`, `email`, `search`, `password`, `tel`, or `url`, this attribute specifies the minimum number of characters that the user can enter.
|
||||
|
||||
|
||||
#### name
|
||||
|
||||
string
|
||||
|
||||
The name of the control, which is submitted with the form data.
|
||||
|
||||
|
||||
#### placeholder
|
||||
|
||||
string
|
||||
|
||||
Instructional text that shows before the input has a value.
|
||||
|
||||
|
||||
#### readonly
|
||||
|
||||
boolean
|
||||
|
||||
If true, the user cannot modify the value. Defaults to `false`.
|
||||
|
||||
|
||||
#### required
|
||||
|
||||
boolean
|
||||
|
||||
If true, the user must fill in a value before submitting a form.
|
||||
|
||||
|
||||
#### rows
|
||||
|
||||
number
|
||||
|
||||
The number of visible text lines for the control.
|
||||
|
||||
|
||||
#### spellcheck
|
||||
|
||||
boolean
|
||||
|
||||
If true, the element will have its spelling and grammar checked. Defaults to `false`.
|
||||
|
||||
|
||||
#### value
|
||||
|
||||
string
|
||||
|
||||
The value of the textarea.
|
||||
|
||||
|
||||
#### wrap
|
||||
|
||||
string
|
||||
|
||||
Indicates how the control wraps text. Possible values are: `"hard"`, `"soft"`, `"off"`.
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
#### ionBlur
|
||||
|
||||
Emitted when the input loses focus.
|
||||
|
||||
|
||||
#### ionFocus
|
||||
|
||||
Emitted when the input has focus.
|
||||
|
||||
|
||||
#### ionInput
|
||||
|
||||
Emitted when the input value has changed.
|
||||
|
||||
|
||||
#### ionStyle
|
||||
|
||||
Emitted when the styles change.
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
*Built with [StencilJS](https://stenciljs.com/)*
|
||||
19
core/src/components/textarea/test/basic/e2e.js
Normal file
19
core/src/components/textarea/test/basic/e2e.js
Normal file
@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
const { By, until } = require('selenium-webdriver');
|
||||
const { register, Page, platforms } = require('../../../../../scripts/e2e');
|
||||
|
||||
class E2ETestPage extends Page {
|
||||
constructor(driver, platform) {
|
||||
super(driver, `http://localhost:3333/src/components/textarea/test/basic?ionicplatform=${platform}`);
|
||||
}
|
||||
}
|
||||
|
||||
platforms.forEach(platform => {
|
||||
describe('textarea/basic', () => {
|
||||
register('should init', driver => {
|
||||
const page = new E2ETestPage(driver, platform);
|
||||
return page.navigate('#content');
|
||||
});
|
||||
});
|
||||
});
|
||||
125
core/src/components/textarea/test/basic/index.html
Normal file
125
core/src/components/textarea/test/basic/index.html
Normal file
@ -0,0 +1,125 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Input - Textarea</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<script src="/dist/ionic.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<ion-app>
|
||||
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Input - Textarea</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content id="content">
|
||||
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label color="primary">Inline Label</ion-label>
|
||||
<ion-textarea placeholder="Textarea"></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label color="primary" fixed>Fixed Label</ion-label>
|
||||
<ion-textarea placeholder="Textarea"></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-textarea placeholder="Textarea with no label"></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label color="primary" stacked>Stacked Label</ion-label>
|
||||
<ion-textarea placeholder="Textarea"></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label color="primary" floating>Floating Label</ion-label>
|
||||
<ion-textarea></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Disabled</ion-label>
|
||||
<ion-textarea id="dynamicDisabled" value="Disabled" disabled></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Readonly</ion-label>
|
||||
<ion-textarea id="dynamicReadonly" value="Readonly" readonly></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Dynamic Value</ion-label>
|
||||
<ion-input id="dynamicValue" value="dynamic"></ion-input>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Dynamic Value</ion-label>
|
||||
<ion-textarea id="dynamicTextareaValue" value="dynamic"></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label color="primary">Clear on Edit</ion-label>
|
||||
<ion-textarea clear-on-edit="true"></ion-textarea>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label color="primary">Clear on Edit</ion-label>
|
||||
<ion-input clear-on-edit="true"></ion-input>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
||||
<div text-center>
|
||||
<ion-button onclick="toggleBoolean('dynamicDisabled', 'disabled')">
|
||||
Toggle Disabled
|
||||
</ion-button>
|
||||
|
||||
<ion-button color="secondary" onclick="toggleBoolean('dynamicReadonly', 'readonly')">
|
||||
Toggle Readonly
|
||||
</ion-button>
|
||||
|
||||
<ion-button color="light" onclick="toggleString('dynamicValue', 'value'); toggleString('dynamicTextareaValue', 'value')">
|
||||
Toggle Value
|
||||
</ion-button>
|
||||
|
||||
<ion-button color="danger" onclick="clearString('dynamicValue', 'value'); clearString('dynamicTextareaValue', 'value')">
|
||||
Clear Value
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
<script>
|
||||
function toggleBoolean(id, prop) {
|
||||
var el = document.getElementById(id);
|
||||
|
||||
var isTrue = el[prop] ? false : true;
|
||||
el[prop] = isTrue;
|
||||
console.log('in toggleBoolean, setting', prop, 'to', isTrue);
|
||||
}
|
||||
|
||||
function toggleString(id, prop) {
|
||||
var el = document.getElementById(id);
|
||||
console.log('INPUT ELE', el);
|
||||
|
||||
var newString = el[prop] === 'dynamic' ? 'changed' : 'dynamic';
|
||||
el[prop] = newString;
|
||||
console.log('in toggleString, setting', prop, 'to', newString);
|
||||
}
|
||||
|
||||
function clearString(id, prop) {
|
||||
var el = document.getElementById(id);
|
||||
|
||||
el[prop] = '';
|
||||
console.log('in toggleString, setting', prop, 'to', '');
|
||||
}
|
||||
</script>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
19
core/src/components/textarea/test/standalone/e2e.js
Normal file
19
core/src/components/textarea/test/standalone/e2e.js
Normal file
@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
const { By, until } = require('selenium-webdriver');
|
||||
const { register, Page, platforms } = require('../../../../../scripts/e2e');
|
||||
|
||||
class E2ETestPage extends Page {
|
||||
constructor(driver, platform) {
|
||||
super(driver, `http://localhost:3333/src/components/textarea/test/standalone?ionicplatform=${platform}`);
|
||||
}
|
||||
}
|
||||
|
||||
platforms.forEach(platform => {
|
||||
describe('textarea/standalone', () => {
|
||||
register('should init', driver => {
|
||||
const page = new E2ETestPage(driver, platform);
|
||||
return page.navigate();
|
||||
});
|
||||
});
|
||||
});
|
||||
16
core/src/components/textarea/test/standalone/index.html
Normal file
16
core/src/components/textarea/test/standalone/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Textarea - Standalone</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<script src="/dist/ionic.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-textarea placeholder="Textarea"></ion-textarea>
|
||||
<ion-textarea value="value"></ion-textarea>
|
||||
<ion-textarea value="44"></ion-textarea>
|
||||
</body>
|
||||
</html>
|
||||
43
core/src/components/textarea/textarea.ios.scss
Normal file
43
core/src/components/textarea/textarea.ios.scss
Normal file
@ -0,0 +1,43 @@
|
||||
@import "./textarea";
|
||||
@import "./textarea.ios.vars";
|
||||
|
||||
// iOS Textarea
|
||||
// --------------------------------------------------
|
||||
|
||||
.native-textarea-ios {
|
||||
@include placeholder($textarea-ios-placeholder-color);
|
||||
@include margin($textarea-ios-margin-top, $textarea-ios-margin-end, $textarea-ios-margin-bottom, $textarea-ios-margin-start);
|
||||
@include padding(0);
|
||||
|
||||
width: calc(100% - #{($textarea-ios-margin-end + $textarea-ios-margin-start)});
|
||||
|
||||
font-family: $textarea-ios-font-family;
|
||||
font-size: $textarea-ios-font-size;
|
||||
}
|
||||
|
||||
|
||||
// iOS Stacked & Floating Textarea
|
||||
// --------------------------------------------------
|
||||
|
||||
.item-ios.item-label-stacked .native-textarea,
|
||||
.item-ios.item-label-floating .native-textarea {
|
||||
@include margin(8px, null, 8px, 0);
|
||||
|
||||
width: calc(100% - #{$textarea-ios-margin-end});
|
||||
}
|
||||
|
||||
.item-ios.item-label-stacked .label-ios + .input + .cloned-input,
|
||||
.item-ios.item-label-floating .label-ios + .input + .cloned-input {
|
||||
@include margin-horizontal(0, null);
|
||||
}
|
||||
|
||||
|
||||
// iOS Textarea After Label
|
||||
// --------------------------------------------------
|
||||
|
||||
.label-ios + ion-textarea .native-textarea,
|
||||
.label-ios + .input + .cloned-input {
|
||||
@include margin-horizontal($textarea-ios-by-label-margin-start, null);
|
||||
|
||||
width: calc(100% - (#{$item-ios-padding-end} / 2) - #{$item-ios-padding-start});
|
||||
}
|
||||
30
core/src/components/textarea/textarea.ios.vars.scss
Normal file
30
core/src/components/textarea/textarea.ios.vars.scss
Normal file
@ -0,0 +1,30 @@
|
||||
@import "../../themes/ionic.globals.ios";
|
||||
|
||||
@import "../item/item.ios.vars";
|
||||
|
||||
// iOS Textarea
|
||||
// --------------------------------------------------
|
||||
|
||||
/// @prop - Margin start of the textarea when it is after a label
|
||||
$textarea-ios-by-label-margin-start: $item-ios-padding-start !default;
|
||||
|
||||
/// @prop - Font family of the textarea
|
||||
$textarea-ios-font-family: $font-family-ios-base !default;
|
||||
|
||||
/// @prop - Font size of the textarea
|
||||
$textarea-ios-font-size: inherit !default;
|
||||
|
||||
/// @prop - Margin top of the textarea
|
||||
$textarea-ios-margin-top: $item-ios-padding-top !default;
|
||||
|
||||
/// @prop - Margin end of the textarea
|
||||
$textarea-ios-margin-end: ($item-ios-padding-end / 2) !default;
|
||||
|
||||
/// @prop - Margin bottom of the textarea
|
||||
$textarea-ios-margin-bottom: $item-ios-padding-bottom !default;
|
||||
|
||||
/// @prop - Margin start of the textarea
|
||||
$textarea-ios-margin-start: 0 !default;
|
||||
|
||||
/// @prop - Placeholder text color of the textarea
|
||||
$textarea-ios-placeholder-color: $placeholder-text-ios-color !default;
|
||||
27
core/src/components/textarea/textarea.md.scss
Normal file
27
core/src/components/textarea/textarea.md.scss
Normal file
@ -0,0 +1,27 @@
|
||||
@import "./textarea";
|
||||
@import "./textarea.md.vars";
|
||||
|
||||
// Material Design Textarea
|
||||
// --------------------------------------------------
|
||||
|
||||
.native-textarea-md {
|
||||
@include placeholder($textarea-md-placeholder-color);
|
||||
@include margin($textarea-md-margin-top, $textarea-md-margin-end, $textarea-md-margin-bottom, $textarea-md-margin-start);
|
||||
@include padding(0);
|
||||
|
||||
width: calc(100% - #{$textarea-md-margin-end} - #{$textarea-md-margin-start});
|
||||
|
||||
font-family: $textarea-md-font-family;
|
||||
font-size: $textarea-md-font-size;
|
||||
}
|
||||
|
||||
|
||||
// Material Design Stacked & Floating Textarea
|
||||
// --------------------------------------------------
|
||||
|
||||
.item-label-stacked .native-textarea-md,
|
||||
.item-label-floating .native-textarea-md {
|
||||
@include margin(8px, null, 8px, 0);
|
||||
|
||||
width: calc(100% - #{$textarea-md-margin-end});
|
||||
}
|
||||
27
core/src/components/textarea/textarea.md.vars.scss
Normal file
27
core/src/components/textarea/textarea.md.vars.scss
Normal file
@ -0,0 +1,27 @@
|
||||
@import "../../themes/ionic.globals.md";
|
||||
|
||||
@import "../item/item.md.vars";
|
||||
|
||||
// Material Design Textarea
|
||||
// --------------------------------------------------
|
||||
|
||||
/// @prop - Font family of the textarea
|
||||
$textarea-md-font-family: $font-family-md-base !default;
|
||||
|
||||
/// @prop - Font size of the textarea
|
||||
$textarea-md-font-size: inherit !default;
|
||||
|
||||
/// @prop - Margin top of the textarea
|
||||
$textarea-md-margin-top: $item-md-padding-top !default;
|
||||
|
||||
/// @prop - Margin end of the textarea
|
||||
$textarea-md-margin-end: ($item-md-padding-end / 2) !default;
|
||||
|
||||
/// @prop - Margin bottom of the textarea
|
||||
$textarea-md-margin-bottom: $item-md-padding-bottom !default;
|
||||
|
||||
/// @prop - Margin start of the textarea
|
||||
$textarea-md-margin-start: ($item-md-padding-start / 2) !default;
|
||||
|
||||
/// @prop - Placeholder text color of the textarea
|
||||
$textarea-md-placeholder-color: $placeholder-text-md-color !default;
|
||||
86
core/src/components/textarea/textarea.scss
Normal file
86
core/src/components/textarea/textarea.scss
Normal file
@ -0,0 +1,86 @@
|
||||
@import "./textarea.vars";
|
||||
|
||||
// Textarea
|
||||
// --------------------------------------------------
|
||||
|
||||
ion-textarea {
|
||||
position: relative;
|
||||
display: block;
|
||||
|
||||
flex: 1;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.item-input ion-textarea {
|
||||
position: static;
|
||||
}
|
||||
|
||||
// Textarea Within An Item
|
||||
// --------------------------------------------------
|
||||
|
||||
.item.item-textarea {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
// Native Textarea
|
||||
// --------------------------------------------------
|
||||
|
||||
.native-textarea {
|
||||
@include appearance(none);
|
||||
@include border-radius(0);
|
||||
|
||||
display: block;
|
||||
|
||||
flex: 1;
|
||||
|
||||
width: 92%;
|
||||
width: calc(100% - 10px);
|
||||
|
||||
border: 0;
|
||||
|
||||
font-size: inherit;
|
||||
|
||||
background: transparent;
|
||||
|
||||
&:active,
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.native-textarea[disabled] {
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
.platform-mobile .native-textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.item-input-has-focus a,
|
||||
.item-input-has-focus button,
|
||||
.item-input-has-focus textarea {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
// Input Cover: Unfocused
|
||||
// --------------------------------------------------
|
||||
// The input cover is the div that actually receives the
|
||||
// tap/click event when scroll assist is configured to true.
|
||||
// This make it so the native input element is not clickable.
|
||||
// This will only show when the scroll assist is configured
|
||||
// otherwise the .input-cover will not be rendered at all
|
||||
// The input cover is not clickable when the input is disabled
|
||||
|
||||
.textarea-cover {
|
||||
@include position(0, null, null, 0);
|
||||
|
||||
position: absolute;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.textarea[disabled] .textarea-cover {
|
||||
pointer-events: none;
|
||||
}
|
||||
272
core/src/components/textarea/textarea.tsx
Normal file
272
core/src/components/textarea/textarea.tsx
Normal file
@ -0,0 +1,272 @@
|
||||
import { Component, Element, Event, EventEmitter, Prop, Watch } from '@stencil/core';
|
||||
|
||||
import { debounceEvent } from '../../utils/helpers';
|
||||
import { createThemedClasses } from '../../utils/theme';
|
||||
import { TextareaComponent } from '../input/input-base';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'ion-textarea',
|
||||
|
||||
// TODO: separate textarea from input scss
|
||||
// right now we're cheating by knowing ion-input
|
||||
// css is bundled with ion-textarea
|
||||
|
||||
styleUrls: {
|
||||
ios: 'textarea.ios.scss',
|
||||
md: 'textarea.md.scss'
|
||||
},
|
||||
host: {
|
||||
theme: 'textarea'
|
||||
}
|
||||
})
|
||||
export class Textarea implements TextareaComponent {
|
||||
mode: string;
|
||||
color: string;
|
||||
|
||||
didBlurAfterEdit: boolean;
|
||||
styleTmr: number;
|
||||
|
||||
@Element() private el: HTMLElement;
|
||||
|
||||
/**
|
||||
* Emitted when the input value has changed.
|
||||
*/
|
||||
@Event() ionInput: EventEmitter;
|
||||
|
||||
/**
|
||||
* Emitted when the styles change.
|
||||
*/
|
||||
@Event() ionStyle: EventEmitter;
|
||||
|
||||
/**
|
||||
* Emitted when the input loses focus.
|
||||
*/
|
||||
@Event() ionBlur: EventEmitter;
|
||||
|
||||
/**
|
||||
* Emitted when the input has focus.
|
||||
*/
|
||||
@Event() ionFocus: EventEmitter;
|
||||
|
||||
/**
|
||||
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Defaults to `"none"`.
|
||||
*/
|
||||
@Prop() autocapitalize = 'none';
|
||||
|
||||
/**
|
||||
* Indicates whether the value of the control can be automatically completed by the browser. Defaults to `"off"`.
|
||||
*/
|
||||
@Prop() autocomplete = 'off';
|
||||
|
||||
/**
|
||||
* This Boolean attribute lets you specify that a form control should have input focus when the page loads. Defaults to `false`.
|
||||
*/
|
||||
@Prop() autofocus = false;
|
||||
|
||||
/**
|
||||
* If true, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types.
|
||||
*/
|
||||
@Prop({ mutable: true }) clearOnEdit: boolean;
|
||||
|
||||
/**
|
||||
* Set the amount of time, in milliseconds, to wait to trigger the `ionInput` event after each keystroke. Default `0`.
|
||||
*/
|
||||
@Prop() debounce = 0;
|
||||
|
||||
@Watch('debounce')
|
||||
protected debounceChanged() {
|
||||
this.ionInput = debounceEvent(this.ionInput, this.debounce);
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, the user cannot interact with the textarea. Defaults to `false`.
|
||||
*/
|
||||
@Prop() disabled = false;
|
||||
|
||||
@Watch('disabled')
|
||||
protected disabledChanged() {
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the value of the type attribute is `text`, `email`, `search`, `password`, `tel`, or `url`, this attribute specifies the maximum number of characters that the user can enter.
|
||||
*/
|
||||
@Prop() maxlength: number;
|
||||
|
||||
/**
|
||||
* If the value of the type attribute is `text`, `email`, `search`, `password`, `tel`, or `url`, this attribute specifies the minimum number of characters that the user can enter.
|
||||
*/
|
||||
@Prop() minlength: number;
|
||||
|
||||
/**
|
||||
* The name of the control, which is submitted with the form data.
|
||||
*/
|
||||
@Prop() name: string;
|
||||
|
||||
/**
|
||||
* Instructional text that shows before the input has a value.
|
||||
*/
|
||||
@Prop() placeholder: string;
|
||||
|
||||
/**
|
||||
* If true, the user cannot modify the value. Defaults to `false`.
|
||||
*/
|
||||
@Prop() readonly = false;
|
||||
|
||||
/**
|
||||
* If true, the user must fill in a value before submitting a form.
|
||||
*/
|
||||
@Prop() required = false;
|
||||
|
||||
/**
|
||||
* If true, the element will have its spelling and grammar checked. Defaults to `false`.
|
||||
*/
|
||||
@Prop() spellcheck = false;
|
||||
|
||||
/**
|
||||
* The visible width of the text control, in average character widths. If it is specified, it must be a positive integer.
|
||||
*/
|
||||
@Prop() cols: number;
|
||||
|
||||
/**
|
||||
* The number of visible text lines for the control.
|
||||
*/
|
||||
@Prop() rows: number;
|
||||
|
||||
/**
|
||||
* Indicates how the control wraps text. Possible values are: `"hard"`, `"soft"`, `"off"`.
|
||||
*/
|
||||
@Prop() wrap: string;
|
||||
|
||||
/**
|
||||
* The value of the textarea.
|
||||
*/
|
||||
@Prop({ mutable: true }) value: string;
|
||||
|
||||
/**
|
||||
* Update the native input element when the value changes
|
||||
*/
|
||||
@Watch('value')
|
||||
protected valueChanged() {
|
||||
const inputEl = this.el.querySelector('textarea');
|
||||
if (inputEl.value !== this.value) {
|
||||
inputEl.value = this.value;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
this.debounceChanged();
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
private emitStyle() {
|
||||
clearTimeout(this.styleTmr);
|
||||
|
||||
const styles = {
|
||||
'textarea': true,
|
||||
'input': true,
|
||||
'input-disabled': this.disabled,
|
||||
'input-has-value': this.hasValue(),
|
||||
'input-has-focus': this.hasFocus()
|
||||
};
|
||||
|
||||
this.styleTmr = setTimeout(() => {
|
||||
this.ionStyle.emit(styles);
|
||||
});
|
||||
}
|
||||
|
||||
clearTextInput(ev: Event) {
|
||||
this.value = '';
|
||||
this.ionInput.emit(ev);
|
||||
}
|
||||
|
||||
inputBlurred(ev: Event) {
|
||||
this.ionBlur.emit(ev);
|
||||
|
||||
this.focusChange(this.hasFocus());
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
inputChanged(ev: Event) {
|
||||
this.value = ev.target && (ev.target as HTMLInputElement).value;
|
||||
this.ionInput.emit(ev);
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
inputFocused(ev: Event) {
|
||||
this.ionFocus.emit(ev);
|
||||
|
||||
this.focusChange(this.hasFocus());
|
||||
this.emitStyle();
|
||||
}
|
||||
|
||||
inputKeydown(ev: Event) {
|
||||
this.checkClearOnEdit(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we need to clear the text input if clearOnEdit is enabled
|
||||
*/
|
||||
checkClearOnEdit(ev: Event) {
|
||||
if (!this.clearOnEdit) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Did the input value change after it was blurred and edited?
|
||||
if (this.didBlurAfterEdit && this.hasValue()) {
|
||||
// Clear the input
|
||||
this.clearTextInput(ev);
|
||||
}
|
||||
|
||||
// Reset the flag
|
||||
this.didBlurAfterEdit = false;
|
||||
}
|
||||
|
||||
focusChange(inputHasFocus: boolean) {
|
||||
// If clearOnEdit is enabled and the input blurred but has a value, set a flag
|
||||
if (this.clearOnEdit && !inputHasFocus && this.hasValue()) {
|
||||
this.didBlurAfterEdit = true;
|
||||
}
|
||||
}
|
||||
|
||||
hasFocus(): boolean {
|
||||
// check if an input has focus or not
|
||||
return this.el && (this.el.querySelector(':focus') === this.el.querySelector('textarea'));
|
||||
}
|
||||
|
||||
hasValue(): boolean {
|
||||
return (this.value !== null && this.value !== undefined && this.value !== '');
|
||||
}
|
||||
|
||||
render() {
|
||||
const themedClasses = createThemedClasses(this.mode, this.color, 'native-textarea');
|
||||
// TODO aria-labelledby={this.item.labelId}
|
||||
|
||||
return (
|
||||
<textarea
|
||||
autoCapitalize={this.autocapitalize}
|
||||
// autoComplete={this.autocomplete}
|
||||
autoFocus={this.autofocus}
|
||||
disabled={this.disabled}
|
||||
maxLength={this.maxlength}
|
||||
minLength={this.minlength}
|
||||
name={this.name}
|
||||
placeholder={this.placeholder}
|
||||
readOnly={this.readonly}
|
||||
required={this.required}
|
||||
spellCheck={this.spellcheck}
|
||||
cols={this.cols}
|
||||
rows={this.rows}
|
||||
wrap={this.wrap}
|
||||
class={themedClasses}
|
||||
onBlur={this.inputBlurred.bind(this)}
|
||||
onInput={this.inputChanged.bind(this)}
|
||||
onFocus={this.inputFocused.bind(this)}
|
||||
onKeyDown={this.inputKeydown.bind(this)}
|
||||
>
|
||||
{this.value}
|
||||
</textarea>
|
||||
);
|
||||
}
|
||||
}
|
||||
1
core/src/components/textarea/textarea.vars.scss
Normal file
1
core/src/components/textarea/textarea.vars.scss
Normal file
@ -0,0 +1 @@
|
||||
@import "../../themes/ionic.globals";
|
||||
Reference in New Issue
Block a user