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;