Make a material design Input component We don't yet have a focus controller, which means once this control becomes focused there's no way for it to lose focus. R=eseidel@chromium.org Review URL: https://codereview.chromium.org/999553002
diff --git a/sky/examples/editor/editable_string.dart b/sky/examples/editor/editable_string.dart index aa60b40..79ff081 100644 --- a/sky/examples/editor/editable_string.dart +++ b/sky/examples/editor/editable_string.dart
@@ -4,7 +4,7 @@ import 'package:sky/services/keyboard/keyboard.mojom.dart'; -typedef void StringChangedCallback(EditableString updated); +typedef void StringUpdated(); class TextRange { final int start; @@ -23,11 +23,11 @@ TextRange composing = const TextRange.empty(); TextRange selection = const TextRange.empty(); - final StringChangedCallback onChanged; + final StringUpdated onUpdated; KeyboardClientStub stub; - EditableString({this.text: '', this.onChanged}) { + EditableString({this.text: '', this.onUpdated}) { stub = new KeyboardClientStub.unbound()..impl = this; } @@ -85,7 +85,7 @@ TextRange committedRange = _replaceOrAppend(composing, text); selection = new TextRange.collapsed(committedRange.end); composing = const TextRange.empty(); - onChanged(this); + onUpdated(); } void deleteSurroundingText(int beforeLength, int afterLength) { @@ -97,23 +97,23 @@ _delete(beforeRange); selection = new TextRange(start: selection.start - beforeLength, end: selection.end - beforeLength); - onChanged(this); + onUpdated(); } void setComposingRegion(int start, int end) { composing = new TextRange(start: start, end: end); - onChanged(this); + onUpdated(); } void setComposingText(String text, int newCursorPosition) { // TODO(abarth): Why is |newCursorPosition| always 1? composing = _replaceOrAppend(composing, text); selection = new TextRange.collapsed(composing.end); - onChanged(this); + onUpdated(); } void setSelection(int start, int end) { selection = new TextRange(start: start, end: end); - onChanged(this); + onUpdated(); } }
diff --git a/sky/examples/editor/editable_text.dart b/sky/examples/editor/editable_text.dart index 6e2c89d..d752972 100644 --- a/sky/examples/editor/editable_text.dart +++ b/sky/examples/editor/editable_text.dart
@@ -3,73 +3,35 @@ // found in the LICENSE file. import '../../framework/fn.dart'; -import '../../framework/shell.dart' as shell; +import '../../framework/theme/colors.dart'; import 'dart:async'; -import 'dart:math'; import 'editable_string.dart'; -import 'package:sky/services/keyboard/keyboard.mojom.dart'; class EditableText extends Component { - static Style _style = new Style(''' - display: paragraph; - white-space: pre-wrap; - padding: 10px; - height: 200px; - background-color: lightblue;''' + static final Style _style = new Style(''' + display: inline;''' ); - static Style _cusorStyle = new Style(''' + static final Style _cusorStyle = new Style(''' display: inline-block; width: 2px; height: 1.2em; vertical-align: top; - background-color: blue;''' + background-color: ${Blue[500]};''' ); - static Style _composingStyle = new Style(''' + static final Style _composingStyle = new Style(''' display: inline; text-decoration: underline;''' ); - KeyboardServiceProxy _service; - - EditableString _string; + EditableString value; + bool focused; Timer _cursorTimer; bool _showCursor = false; - EditableText({Object key}) : super(key: key, stateful: true) { - _string = new EditableString(text: '', onChanged: _handleTextChanged); - events.listen('click', _handleClick); - events.listen('focus', _handleFocus); - events.listen('blur', _handleBlur); - } - - void _handleTextChanged(EditableString string) { - setState(() { - _string = string; - _showCursor = true; - _restartCursorTimer(); - }); - } - - void _handleClick(_) { - if (_service != null) - return; - _service = new KeyboardServiceProxy.unbound(); - shell.requestService(_service); - _service.ptr.show(_string.stub); - _restartCursorTimer(); - setState(() { - _showCursor = true; - }); - } - - void _handleFocus(_) { - print("_handleFocus"); - } - - void _handleBlur(_) { - print("_handleBlur"); + EditableText({Object key, this.value, this.focused}) + : super(key: key, stateful: true) { } void _cursorTick(Timer timer) { @@ -78,28 +40,39 @@ }); } - void _restartCursorTimer() { - if (_cursorTimer != null) - _cursorTimer.cancel(); + void _startCursorTimer() { + _showCursor = true; _cursorTimer = new Timer.periodic( new Duration(milliseconds: 500), _cursorTick); } - void didUnmount() { + void _stopCursorTimer() { _cursorTimer.cancel(); + _cursorTimer = null; + _showCursor = false; + } + + void didUnmount() { + if (_cursorTimer != null) + _stopCursorTimer(); } Node build() { + if (focused && _cursorTimer == null) + _startCursorTimer(); + else if (!focused && _cursorTimer != null) + _stopCursorTimer(); + List<Node> children = new List<Node>(); - if (!_string.composing.isValid) { - children.add(new Text(_string.text)); + if (!value.composing.isValid) { + children.add(new Text(value.text)); } else { - String beforeComposing = _string.textBefore(_string.composing); + String beforeComposing = value.textBefore(value.composing); if (!beforeComposing.isEmpty) children.add(new Text(beforeComposing)); - String composing = _string.textInside(_string.composing); + String composing = value.textInside(value.composing); if (!composing.isEmpty) { children.add(new Container( key: 'composing', @@ -108,7 +81,7 @@ )); } - String afterComposing = _string.textAfter(_string.composing); + String afterComposing = value.textAfter(value.composing); if (!afterComposing.isEmpty) children.add(new Text(afterComposing)); }
diff --git a/sky/examples/editor/editor_app.dart b/sky/examples/editor/editor_app.dart index 376aa43..58239c9 100644 --- a/sky/examples/editor/editor_app.dart +++ b/sky/examples/editor/editor_app.dart
@@ -3,10 +3,10 @@ // found in the LICENSE file. import '../../framework/fn.dart'; -import 'editable_text.dart'; +import 'input.dart'; class EditorApp extends App { Node build() { - return new EditableText(); + return new Input(); } }
diff --git a/sky/examples/editor/input.dart b/sky/examples/editor/input.dart new file mode 100644 index 0000000..0c5b499 --- /dev/null +++ b/sky/examples/editor/input.dart
@@ -0,0 +1,66 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../../framework/fn.dart'; +import '../../framework/theme/colors.dart'; +import 'editable_string.dart'; +import 'editable_text.dart'; +import 'keyboard.dart'; + +typedef void ValueChanged(value); + +class Input extends Component { + static final Style _style = new Style(''' + display: paragraph; + margin: 8px; + padding: 8px; + border-bottom: 1px solid ${Grey[200]}; + align-self: center; + height: 1.2em; + white-space: pre; + overflow: hidden;''' + ); + + static final String _focusedInlineStyle = ''' + padding: 7px; + border-bottom: 2px solid ${Blue[500]};'''; + + ValueChanged onChanged; + String value; + + bool _focused = false; + EditableString _editableValue; + + Input({Object key, this.value: ''}) : super(key: key, stateful: true) { + _editableValue = new EditableString(text: value, + onUpdated: _handleTextUpdated); + events.listen('click', _handleClick); + } + + void _handleClick(_) { + keyboard.show(_editableValue.stub); + setState(() { + _focused = true; + }); + } + + void _handleTextUpdated() { + setState(() {}); + if (value != _editableValue.text) { + value = _editableValue.text; + if (onChanged != null) + onChanged(value); + } + } + + Node build() { + return new Container( + style: _style, + inlineStyle: _focused ? _focusedInlineStyle : null, + children: [ + new EditableText(value: _editableValue, focused: _focused), + ] + ); + } +}
diff --git a/sky/examples/editor/keyboard.dart b/sky/examples/editor/keyboard.dart new file mode 100644 index 0000000..c958e48 --- /dev/null +++ b/sky/examples/editor/keyboard.dart
@@ -0,0 +1,20 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../../framework/shell.dart' as shell; +import 'package:sky/services/keyboard/keyboard.mojom.dart'; + +class _KeyboardConnection { + KeyboardServiceProxy proxy; + + _KeyboardConnection() { + proxy = new KeyboardServiceProxy.unbound(); + shell.requestService(proxy); + } + + KeyboardService get keyboard => proxy.ptr; +} + +final _KeyboardConnection _connection = new _KeyboardConnection(); +final KeyboardService keyboard = _connection.keyboard;