diff --git a/packages/core/src/components/input/input.ios.scss b/packages/core/src/components/input/input.ios.scss new file mode 100644 index 0000000000..a0898f7375 --- /dev/null +++ b/packages/core/src/components/input/input.ios.scss @@ -0,0 +1,182 @@ +@import "../../themes/ionic.globals.ios"; +@import "./input"; + + +// iOS Input +// -------------------------------------------------- + +/// @prop - Background color of the input +$text-input-ios-background-color: $list-ios-background-color !default; + +/// @prop - Margin top of the input +$text-input-ios-margin-top: $item-ios-padding-top !default; + +// deprecated +$text-input-ios-margin-right: ($item-ios-padding-end / 2) !default; +/// @prop - Margin end of the input +$text-input-ios-margin-end: $text-input-ios-margin-right !default; + +/// @prop - Margin bottom of the input +$text-input-ios-margin-bottom: $item-ios-padding-bottom !default; + +// deprecated +$text-input-ios-margin-left: 0 !default; +/// @prop - Margin start of the input +$text-input-ios-margin-start: $text-input-ios-margin-left !default; + +/// @prop - Width of the icon used to clear the input +$text-input-ios-input-clear-icon-width: 30px !default; + +/// @prop - Color of the icon used to clear the input +$text-input-ios-input-clear-icon-color: rgba(0, 0, 0, .5) !default; + +/// @prop - Icon used to clear the input +$text-input-ios-input-clear-icon-svg: "" !default; + +/// @prop - Size of the icon used to clear the input +$text-input-ios-input-clear-icon-size: 18px !default; + +/// @prop - Show the focus highlight when the input has focus +$text-input-ios-show-focus-highlight: false !default; + +/// @prop - Show the valid highlight when it is valid and has a value +$text-input-ios-show-valid-highlight: $text-input-ios-show-focus-highlight !default; + +/// @prop - Show the invalid highlight when it is invalid and has value +$text-input-ios-show-invalid-highlight: $text-input-ios-show-focus-highlight !default; + +/// @prop - Color of the input highlight +$text-input-ios-highlight-color: color($colors-ios, primary) !default; + +/// @prop - Color of the input highlight when valid +$text-input-ios-highlight-color-valid: $text-input-highlight-color-valid !default; + +/// @prop - Color of the input highlight when invalid +$text-input-ios-highlight-color-invalid: $text-input-highlight-color-invalid !default; + + +// iOS Default Input +// -------------------------------------------------- + +.text-input-ios { + @include margin($text-input-ios-margin-top, $text-input-ios-margin-end, $text-input-ios-margin-bottom, $text-input-ios-margin-start); + @include padding(0); + + width: calc(100% - #{($text-input-ios-margin-end + $text-input-ios-margin-start)}); +} + + +// iOS Inset Input +// -------------------------------------------------- + +.input-ios .inset-input { + @include padding(($item-ios-padding-top / 2), ($item-ios-padding-end / 2), ($item-ios-padding-bottom / 2), ($item-ios-padding-start / 2)); + @include margin(($item-ios-padding-top / 2), $item-ios-padding-end, ($item-ios-padding-bottom / 2), 0); +} + + +// iOS Highlighted Input +// -------------------------------------------------- + +// Input highlight mixin for focus, valid, and invalid states +@mixin ios-input-highlight($highlight-color) { + border-bottom-color: $highlight-color; +} + +// Show the focus highlight when the input has focus +@if ($text-input-ios-show-focus-highlight) { + // In order to get a 2px border we need to add an inset + // box-shadow 1px (this is to avoid the div resizing) + + // TODO remove all uses of input-has-focus in v4 + // TODO remove all uses of input-has-value in v4 + .item-ios.item-input.item-input-has-focus .item-inner, + .item-ios.item-input.input-has-focus .item-inner { + @include ios-input-highlight($text-input-ios-highlight-color); + } + + // The last item in a list has a border on the item, not the + // inner item, so add it to the item itself + .list-ios .item-input.item-input-has-focus:last-child, + .list-ios .item-input.input-has-focus:last-child { + @include ios-input-highlight($text-input-ios-highlight-color); + + .item-inner { + box-shadow: none; + } + } +} + +// Show the valid highlight when it has the .ng-valid class and a value +@if ($text-input-ios-show-valid-highlight) { + .item-ios.item-input.ng-valid.item-input-has-value:not(.input-has-focus):not(.item-input-has-focus) .item-inner, + .item-ios.item-input.ng-valid.input-has-value:not(.input-has-focus):not(.item-input-has-focus) .item-inner { + @include ios-input-highlight($text-input-ios-highlight-color-valid); + } + + .list-ios .item-input.ng-valid.item-input-has-value:not(.input-has-focus):not(.item-input-has-focus):last-child, + .list-ios .item-input.ng-valid.input-has-value:not(.input-has-focus):not(.item-input-has-focus):last-child { + @include ios-input-highlight($text-input-ios-highlight-color-valid); + + .item-inner { + box-shadow: none; + } + } +} + +// Show the invalid highlight when it has the invalid class and has been touched +@if ($text-input-ios-show-invalid-highlight) { + .item-ios.item-input.ng-invalid.ng-touched:not(.input-has-focus):not(.item-input-has-focus) .item-inner { + @include ios-input-highlight($text-input-ios-highlight-color-invalid); + } + + .list-ios .item-input.ng-invalid.ng-touched:not(.input-has-focus):not(.item-input-has-focus):last-child { + @include ios-input-highlight($text-input-ios-highlight-color-invalid); + + .item-inner { + box-shadow: none; + } + } +} + + +// iOS Stacked & Floating Inputs +// -------------------------------------------------- + +.item-ios.item-label-stacked .text-input, +.item-ios.item-label-floating .text-input { + @include margin(8px, null, 8px, 0); + + width: calc(100% - #{$text-input-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); +} + +.item-label-stacked .select-ios, +.item-label-floating .select-ios { + @include padding(8px, null, 8px, 0); +} + + +// iOS Clear Input Icon +// -------------------------------------------------- + +.input-ios[clearInput] { + position: relative; +} + +.input-ios[clearInput] .text-input { + @include padding-horizontal(null, $text-input-ios-input-clear-icon-width); +} + +.input-ios .text-input-clear-icon { + @include position-horizontal(null, ($item-ios-padding-end / 2)); + @include svg-background-image($text-input-ios-input-clear-icon-svg); + + width: $text-input-ios-input-clear-icon-width; + + background-size: $text-input-ios-input-clear-icon-size; +} diff --git a/packages/core/src/components/input/input.md.scss b/packages/core/src/components/input/input.md.scss new file mode 100644 index 0000000000..a82b29429d --- /dev/null +++ b/packages/core/src/components/input/input.md.scss @@ -0,0 +1,179 @@ +@import "../../themes/ionic.globals.md"; +@import "./input"; + + +// Material Design Input +// -------------------------------------------------- + +/// @prop - Background color of the input +$text-input-md-background-color: $list-md-background-color !default; + +/// @prop - Margin top of the input +$text-input-md-margin-top: $item-md-padding-top !default; + +// deprecated +$text-input-md-margin-right: ($item-md-padding-end / 2) !default; +/// @prop - Margin end of the input +$text-input-md-margin-end: $text-input-md-margin-right !default; + +/// @prop - Margin bottom of the input +$text-input-md-margin-bottom: $item-md-padding-bottom !default; + +// deprecated +$text-input-md-margin-left: ($item-md-padding-start / 2) !default; +/// @prop - Margin start of the input +$text-input-md-margin-start: $text-input-md-margin-left !default; + +/// @prop - Width of the icon used to clear the input +$text-input-md-input-clear-icon-width: 30px !default; + +/// @prop - Color of the icon used to clear the input +$text-input-md-input-clear-icon-color: #5b5b5b !default; + +/// @prop - Icon used to clear the input +$text-input-md-input-clear-icon-svg: "" !default; + +/// @prop - Size of the icon used to clear the input +$text-input-md-input-clear-icon-size: 22px !default; + +/// @prop - Show the focus highlight when the input has focus +$text-input-md-show-focus-highlight: true !default; + +/// @prop - Show the valid highlight when it is valid and has a value +$text-input-md-show-valid-highlight: $text-input-md-show-focus-highlight !default; + +/// @prop - Show the invalid highlight when it is invalid and has value +$text-input-md-show-invalid-highlight: $text-input-md-show-focus-highlight !default; + +/// @prop - Color of the input highlight +$text-input-md-highlight-color: color($colors-md, primary) !default; + +/// @prop - Color of the input highlight when valid +$text-input-md-highlight-color-valid: $text-input-highlight-color-valid !default; + +/// @prop - Color of the input highlight when invalid +$text-input-md-highlight-color-invalid: $text-input-highlight-color-invalid !default; + + +// Material Design Default Input +// -------------------------------------------------- + +.text-input-md { + @include margin($text-input-md-margin-top, $text-input-md-margin-end, $text-input-md-margin-bottom, $text-input-md-margin-start); + @include padding(0); + + width: calc(100% - #{$text-input-md-margin-end} - #{$text-input-md-margin-start}); +} + + +// Material Design Inset Input +// -------------------------------------------------- + +.input-md .inset-input { + @include padding(($item-md-padding-top / 2), ($item-md-padding-end / 2), ($item-md-padding-bottom / 2), ($item-md-padding-start / 2)); + @include margin(($item-md-padding-top / 2), $item-md-padding-end, ($item-md-padding-bottom / 2), $item-md-padding-start); +} + + +// Material Design Highlighted Input +// -------------------------------------------------- + +// Input highlight mixin for focus, valid, and invalid states +@mixin md-input-highlight($highlight-color) { + border-bottom-color: $highlight-color; + box-shadow: inset 0 -1px 0 0 $highlight-color; +} + +// Show the focus highlight when the input has focus +@if ($text-input-md-show-focus-highlight) { + // In order to get a 2px border we need to add an inset + // box-shadow 1px (this is to avoid the div resizing) + + // TODO remove all uses of input-has-focus in v4 + .item-md.item-input.item-input-has-focus .item-inner, + .item-md.item-input.input-has-focus .item-inner { + @include md-input-highlight($text-input-md-highlight-color); + } + + // The last item in a list has a border on the item, not the + // inner item, so add it to the item itself + .list-md .item-input.item-input-has-focus:last-child, + .list-md .item-input.input-has-focus:last-child { + @include md-input-highlight($text-input-md-highlight-color); + + .item-inner { + box-shadow: none; + } + } +} + +// Show the valid highlight when it has the .ng-valid class and a value +@if ($text-input-md-show-valid-highlight) { + // TODO remove all uses of input-has-focus in v4 + // TODO remove all uses of input-has-value in v4 + .item-md.item-input.ng-valid.item-input-has-value:not(.input-has-focus):not(.item-input-has-focus) .item-inner, + .item-md.item-input.ng-valid.input-has-value:not(.input-has-focus):not(.item-input-has-focus) .item-inner { + @include md-input-highlight($text-input-md-highlight-color-valid); + } + + .list-md .item-input.ng-valid.item-input-has-value:not(.input-has-focus):not(.item-input-has-focus):last-child, + .list-md .item-input.ng-valid.input-has-value:not(.input-has-focus):not(.item-input-has-focus):last-child { + @include md-input-highlight($text-input-md-highlight-color-valid); + + .item-inner { + box-shadow: none; + } + } +} + +// Show the invalid highlight when it has the invalid class and has been touched +@if ($text-input-md-show-invalid-highlight) { + .item-md.item-input.ng-invalid.ng-touched:not(.input-has-focus):not(.item-input-has-focus) .item-inner { + @include md-input-highlight($text-input-md-highlight-color-invalid); + } + + .list-md .item-input.ng-invalid.ng-touched:not(.input-has-focus):not(.item-input-has-focus):last-child { + @include md-input-highlight($text-input-md-highlight-color-invalid); + + .item-inner { + box-shadow: none; + } + } +} + + +// Material Design Stacked & Floating Inputs +// -------------------------------------------------- + +.item-label-stacked .text-input-md, +.item-label-floating .text-input-md { + @include margin(8px, null, 8px, 0); + + width: calc(100% - #{$text-input-md-margin-end}); +} + +.item-label-stacked .select-md, +.item-label-floating .select-md { + @include padding(8px, null, 8px, 0); +} + + +// Material Design Clear Input Icon +// -------------------------------------------------- + +.input-md[clearInput] { + position: relative; +} + +.input-md[clearInput] .text-input { + @include padding-horizontal(null, $text-input-md-input-clear-icon-width); +} + +.input-md .text-input-clear-icon { + @include position-horizontal(null, ($item-md-padding-end / 2)); + @include svg-background-image($text-input-md-input-clear-icon-svg); + + width: $text-input-md-input-clear-icon-width; + + background-size: $text-input-md-input-clear-icon-size; +} diff --git a/packages/core/src/components/input/input.scss b/packages/core/src/components/input/input.scss new file mode 100644 index 0000000000..bc284ab90c --- /dev/null +++ b/packages/core/src/components/input/input.scss @@ -0,0 +1,165 @@ +@import "../../themes/ionic.globals"; + +// Input +// -------------------------------------------------- + +/// @prop - Color of the input highlight when valid +$text-input-highlight-color-valid: #32db64 !default; + +/// @prop - Color of the input highlight when invalid +$text-input-highlight-color-invalid: #f53d3d !default; + +/// @prop - Color of the input placeholder +$text-input-placeholder-color: #999 !default; + + +// Input/Textarea Wrapper +// -------------------------------------------------- + +ion-input, +ion-textarea { + position: relative; + display: block; + + flex: 1; + + width: 100%; +} + +.item-input ion-input, +.item-input ion-textarea { + position: static; +} + + +// Textarea Within An Item +// -------------------------------------------------- + +.item.item-textarea { + align-items: stretch; +} + + +// Native Text Input +// -------------------------------------------------- + +.text-input { + @include placeholder($text-input-placeholder-color); + @include appearance(none); + @include border-radius(0); + + display: inline-block; + + flex: 1; + + width: 92%; + width: calc(100% - 10px); + + border: 0; + + background: transparent; +} + +textarea.text-input { + display: block; +} + +.text-input[disabled] { + opacity: .4; +} + +input.text-input:-webkit-autofill { + background-color: transparent; +} + +.platform-mobile textarea.text-input { + resize: none; +} + + +// 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 + +.input-cover { + @include position(0, null, null, 0); + + position: absolute; + + width: 100%; + height: 100%; +} + +.input[disabled] .input-cover { + pointer-events: none; +} + + +// Input Cover: Focused +// -------------------------------------------------- +// When the input has focus, then the input cover should be hidden + +.item-input-has-focus .input-cover { + display: none; +} + +.item-input-has-focus { + pointer-events: none; +} + +.item-input-has-focus input, +.item-input-has-focus textarea, +.item-input-has-focus a, +.item-input-has-focus button { + pointer-events: auto; +} + + +// Scroll Assist Input +// -------------------------------------------------- +// This input is used to help the app handle +// Next and Previous input tabbing + +[next-input] { + @include padding(0); + + position: absolute; + bottom: 20px; + + width: 1px; + height: 1px; + + border: 0; + background: transparent; + + pointer-events: none; +} + + +// Clear Input Icon +// -------------------------------------------------- + +.text-input-clear-icon { + @include margin(0); + @include padding(0); + @include background-position(center); + + position: absolute; + top: 0; + display: none; + + height: 100%; + + background-repeat: no-repeat; +} + +// TODO remove all uses of input-has-focus in v4 +// TODO remove all uses of input-has-value in v4 +.item-input-has-focus.item-input-has-value .text-input-clear-icon { + display: block; +} diff --git a/packages/core/src/components/input/input.tsx b/packages/core/src/components/input/input.tsx new file mode 100644 index 0000000000..4e159f2f5b --- /dev/null +++ b/packages/core/src/components/input/input.tsx @@ -0,0 +1,289 @@ +import { Component, Element, Event, EventEmitter, Prop, PropDidChange } from '@stencil/core'; + +import { createThemedClasses } from '../../utils/theme'; + + +@Component({ + tag: 'ion-input', + styleUrls: { + ios: 'input.ios.scss', + md: 'input.md.scss', + wp: 'input.wp.scss' + }, + host: { + theme: 'input' + } +}) +export class Input { + mode: any; + color: any; + styleTmr: any; + didBlurAfterEdit: boolean; + + @Element() el: HTMLElement; + + /** + * @output {event} Emitted when the styles change. + */ + @Event() ionStyle: EventEmitter; + + /** + * @output {event} Emitted when the input no longer has focus. + */ + @Event() ionBlur: EventEmitter; + + /** + * @output {event} Emitted when the input has focus. + */ + @Event() ionFocus: EventEmitter; + + /** + * @input {string} Indicates whether the value of the control can be automatically completed by the browser. Defaults to `"off"`. + */ + @Prop() autocomplete: string = 'off'; + + /** + * @input {string} Whether autocorrection should be enabled when the user is entering/editing the text value. Defaults to `"off"`. + */ + @Prop() autocorrect: string = 'off'; + + /** + * @input {string} This Boolean attribute lets you specify that a form control should have input focus when the page loads. Defaults to `false`. + */ + @Prop() autofocus: boolean; + + /** + * @input {boolean} If true and the type is `checkbox` or `radio`, the control is selected by default. Defaults to `false`. + */ + @Prop() checked: boolean = false; + + /** + * @hidden + */ + @PropDidChange('checked') + setChecked() { + this.emitStyle(); + } + + + /** + * @input {boolean} If true, a clear icon will appear in the input when there is a value. Clicking it clears the input. Defaults to `false`. + */ + @Prop() clearInput: boolean = false; + + /** + * @input {boolean} If true, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types. Defaults to `false`. + */ + @Prop({state: true}) clearOnEdit: boolean; + + /** + * @input {boolean} If true, the user cannot interact with this element. Defaults to `false`. + */ + @Prop() disabled: boolean = false; + + /** + * @hidden + */ + @PropDidChange('disabled') + setDisabled() { + this.emitStyle(); + } + + /** + * @input {any} The minimum value, which must not be greater than its maximum (max attribute) value. + */ + @Prop() min: string; + + /** + * @input {any} The maximum value, which must not be less than its minimum (min attribute) value. + */ + @Prop() max: string; + + /** + * @input {string} Instructional text that shows before the input has a value. + */ + @Prop() placeholder: string; + + /** + * @input {boolean} If true, the user cannot modify the value. Defaults to `false`. + */ + @Prop() readonly: boolean = false; + + /** + * @input {string} If true, the element will have its spelling and grammar checked. Defaults to `false`. + */ + @Prop() spellcheck: boolean = false; + + /** + * @input {any} Works with the min and max attributes to limit the increments at which a value can be set. + */ + @Prop() step: string; + + /** + * @input {string} The type of control to display. The default type is text. Possible values are: `"text"`, `"password"`, `"email"`, `"number"`, `"search"`, `"tel"`, or `"url"`. + */ + @Prop() type: string = 'text'; + + /** + * @input {string} The text value of the input. + */ + @Prop({ state: true }) value: string; + + + ionViewDidLoad() { + this.emitStyle(); + + // By default, password inputs clear after focus when they have content + if (this.type === 'password' && this.clearOnEdit !== false) { + this.clearOnEdit = true; + } + } + + private emitStyle() { + clearTimeout(this.styleTmr); + + let styles = { + 'input': true, + 'input-checked': this.checked, + 'input-disabled': this.disabled, + 'input-has-value': this.hasValue(), + 'input-has-focus': this.hasFocus() + }; + + this.styleTmr = setTimeout(() => { + this.ionStyle.emit(styles); + }); + } + + /** + * @hidden + */ + hasValue(): boolean { + return (this.value !== null && this.value !== undefined && this.value !== ''); + } + + + /** + * @hidden + */ + inputBlurred(ev: any) { + this.ionBlur.emit(ev); + + this.focusChange(this.hasFocus()); + this.emitStyle(); + } + + + /** + * @hidden + */ + inputChanged(ev: any) { + this.value = ev.target && ev.target.value; + this.emitStyle(); + } + + + /** + * @hidden + */ + inputFocused(ev: any) { + this.ionFocus.emit(ev); + + this.focusChange(this.hasFocus()); + this.emitStyle(); + } + + + /** + * @hidden + */ + hasFocus(): boolean { + // check if an input has focus or not + return this.el && (this.el.querySelector(':focus') === this.el.querySelector('input')); + } + + + /** + * @hidden + */ + 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; + } + } + + + /** + * @hidden + */ + inputKeydown() { + this.checkClearOnEdit(); + } + + + /** + * Check if we need to clear the text input if clearOnEdit is enabled + * @hidden + */ + checkClearOnEdit() { + 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(); + } + + // Reset the flag + this.didBlurAfterEdit = false; + } + + + /** + * @hidden + */ + clearTextInput() { + console.debug('Should clear input', this.el); + this.value = ''; + } + + + render() { + const themedClasses = createThemedClasses(this.mode, this.color, 'text-input'); + // TODO aria-labelledby={this.item.labelId} + + // OLD RENDER + // '' + + // '' + + // '' + + // '' + + // '
', + + return ( + + ) + } +} diff --git a/packages/core/src/components/input/input.wp.scss b/packages/core/src/components/input/input.wp.scss new file mode 100644 index 0000000000..b2205cda32 --- /dev/null +++ b/packages/core/src/components/input/input.wp.scss @@ -0,0 +1,162 @@ +@import "../../themes/ionic.globals.wp"; +@import "./input"; + + +// Windows Input +// -------------------------------------------------- + +/// @prop - Background color of the input +$text-input-wp-background-color: $list-wp-background-color !default; + +/// @prop - Border color of the input +$text-input-wp-border-color: $input-wp-border-color !default; + +/// @prop - Border width of the input +$text-input-wp-border-width: 2px !default; + +/// @prop - Margin top of the input +$text-input-wp-margin-top: $item-wp-padding-top !default; + +// deprecated +$text-input-wp-margin-right: ($item-wp-padding-end / 2) !default; +/// @prop - Margin end of the input +$text-input-wp-margin-end: $text-input-wp-margin-right !default; + +/// @prop - Margin bottom of the input +$text-input-wp-margin-bottom: $item-wp-padding-bottom !default; + +// deprecated +$text-input-wp-margin-left: ($item-wp-padding-start / 2) !default; +/// @prop - Margin start of the input +$text-input-wp-margin-start: $text-input-wp-margin-left !default; + +/// @prop - Vertical padding of the input +$text-input-wp-padding-vertical: 0 !default; + +/// @prop - Horizontal padding of the input +$text-input-wp-padding-horizontal: 8px !default; + +/// @prop - Line height of the input +$text-input-wp-line-height: 3rem !default; + +/// @prop - Width of the icon used to clear the input +$text-input-wp-input-clear-icon-width: 30px !default; + +/// @prop - Color of the icon used to clear the input +$text-input-wp-input-clear-icon-color: $input-wp-border-color !default; + +/// @prop - Icon used to clear the input +$text-input-wp-input-clear-icon-svg: "" !default; + +/// @prop - Size of the icon used to clear the input +$text-input-wp-input-clear-icon-size: 22px !default; + +/// @prop - Show the focus highlight when the input has focus +$text-input-wp-show-focus-highlight: true !default; + +/// @prop - Show the valid highlight when it is valid and has a value +$text-input-wp-show-valid-highlight: $text-input-wp-show-focus-highlight !default; + +/// @prop - Show the invalid highlight when it is invalid and has value +$text-input-wp-show-invalid-highlight: $text-input-wp-show-focus-highlight !default; + +/// @prop - Color of the input highlight +$text-input-wp-highlight-color: color($colors-wp, primary) !default; + +/// @prop - Color of the input highlight when valid +$text-input-wp-highlight-color-valid: $text-input-highlight-color-valid !default; + +/// @prop - Color of the input highlight when invalid +$text-input-wp-highlight-color-invalid: $text-input-highlight-color-invalid !default; + + +// Windows Default Input +// -------------------------------------------------- + +.text-input-wp { + @include margin($text-input-wp-margin-top, $text-input-wp-margin-end, $text-input-wp-margin-bottom, $text-input-wp-margin-start); + @include padding($text-input-wp-padding-vertical, $text-input-wp-padding-horizontal); + + width: calc(100% - #{$text-input-wp-margin-end} - #{$text-input-wp-margin-start}); + + border: $text-input-wp-border-width solid $text-input-wp-border-color; + line-height: $text-input-wp-line-height; +} + + +// Windows Inset Input +// -------------------------------------------------- + +.item-wp .inset-input { + @include padding(($item-wp-padding-top / 2), ($item-wp-padding-end / 2), ($item-wp-padding-bottom / 2), ($item-wp-padding-start / 2)); + @include margin(($item-wp-padding-top / 2), $item-wp-padding-end, ($item-wp-padding-bottom / 2), $item-wp-padding-start); +} + + +// Windows Highlighted Input +// -------------------------------------------------- + +// Show the focus highlight when the input has focus +@if ($text-input-wp-show-focus-highlight) { + // TODO remove all uses of input-has-focus in v4 + // TODO remove all uses of input-has-value in v4 + .item-wp.item-input.item-input-has-focus .text-input, + .item-wp.item-input.input-has-focus .text-input { + border-color: $text-input-wp-highlight-color; + } +} + +// Show the valid highlight when it has the .ng-valid class and a value +@if ($text-input-wp-show-valid-highlight) { + .item-wp.item-input.ng-valid.item-input-has-value:not(.input-has-focus):not(.item-input-has-focus) .text-input, + .item-wp.item-input.ng-valid.input-has-value:not(.input-has-focus):not(.item-input-has-focus) .text-input { + border-color: $text-input-wp-highlight-color-valid; + } +} + +// Show the invalid highlight when it has the invalid class and has been touched +@if ($text-input-wp-show-invalid-highlight) { + .item-wp.item-input.ng-invalid.ng-touched:not(.input-has-focus):not(.item-input-has-focus) .text-input { + border-color: $text-input-wp-highlight-color-invalid; + } +} + + +// Windows Stacked & Floating Inputs +// -------------------------------------------------- + +.item-label-stacked .text-input-wp, +.item-label-floating .text-input-wp, +.item-label-stacked .select-wp, +.item-label-floating .select-wp { + @include margin(8px, null, 8px, 0); + + width: calc(100% - #{$text-input-wp-margin-end}); +} + +.item-wp.item-label-stacked [item-right], // deprecated +.item-wp.item-label-floating [item-right], // deprecated +.item-wp.item-label-stacked [item-end], +.item-wp.item-label-floating [item-end] { + align-self: flex-end; +} + +// Windows Clear Input Icon +// -------------------------------------------------- + +.input-wp[clearInput] { + position: relative; +} + +.input-wp[clearInput] .text-input { + @include padding-horizontal(null, $text-input-wp-input-clear-icon-width); +} + +.input-wp .text-input-clear-icon { + @include position-horizontal(null, ($item-wp-padding-end / 2)); + @include svg-background-image($text-input-wp-input-clear-icon-svg); + + width: $text-input-wp-input-clear-icon-width; + + background-size: $text-input-wp-input-clear-icon-size; +} diff --git a/packages/core/src/components/input/test/basic.html b/packages/core/src/components/input/test/basic.html new file mode 100644 index 0000000000..5b490a83ff --- /dev/null +++ b/packages/core/src/components/input/test/basic.html @@ -0,0 +1,208 @@ + + + + + Ionic Inputs + + + + + + + + Basic Form + + + + + + Default + + + + + Floating + + + + + Type # + + + + + Password + + + + + Placeholder + + + + + Disabled + + + + + Readonly + + + + + Toggle + + + + +
+ + Toggle Disabled + + + + Toggle Readonly + +
+ + +
+ + +
+ + + + + diff --git a/packages/core/src/components/input/textarea.tsx b/packages/core/src/components/input/textarea.tsx new file mode 100644 index 0000000000..2698e86088 --- /dev/null +++ b/packages/core/src/components/input/textarea.tsx @@ -0,0 +1,49 @@ + +// /** +// * @name TextArea +// * @description +// * +// * `ion-textarea` is used for multi-line text inputs. Ionic still +// * uses an actual `