Skip to content

Commit 94baf47

Browse files
authored
Merge pull request #40 from clairesarsam-wf/sync_changes_2
UIP-1953 Sync changes from OverReact source
2 parents 2742bac + 030edee commit 94baf47

26 files changed

+485
-44
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -495,15 +495,15 @@ as shown in the examples above.
495495

496496
## Component Formatting
497497
> __A note on dart_style:__
498-
>
498+
>
499499
> Currently, [dart_style (dartfmt)](https://github.com/dart-lang/dart_style) decreases the readability of components
500500
> built using [OverReact's fluent-style](#fluent-style-component-consumption).
501501
> See https://github.com/dart-lang/dart_style/issues/549 for more info.
502-
>
502+
>
503503
> We're exploring some different ideas to improve automated formatting, but for the time being, we __do not recommend__ using dart_style with OverReact.
504-
>
504+
>
505505
> However, if you do choose to use dart_style, you can greatly improve its output by using trailing commas in children argument lists:
506-
>
506+
>
507507
> * dart_style formatting:
508508
> ```dart
509509
> return (Button()

lib/over_react.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export 'src/util/key_constants.dart';
3737
export 'src/util/map_util.dart';
3838
export 'src/util/pretty_print.dart';
3939
export 'src/util/prop_errors.dart';
40+
export 'src/util/prop_key_util.dart';
4041
export 'src/util/react_wrappers.dart';
4142
export 'src/util/rem_util.dart';
4243
export 'src/util/string_util.dart';

lib/src/component/callback_typedefs.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
library over_react.callback_typedefs;
1616

17+
import 'dart:html';
18+
19+
import 'package:over_react/over_react.dart' show ResizeSensorEvent;
1720
import 'package:react/react.dart' as react;
1821

1922
// Callbacks for React's DOM event system
@@ -29,3 +32,9 @@ typedef WheelEventCallback(react.SyntheticWheelEvent event);
2932

3033
/// A generic callback that takes no arguments.
3134
typedef Callback();
35+
36+
// Callback for DOM elements
37+
typedef Element ElementCallback();
38+
39+
// Callback for [ResizeSensorEvent]s
40+
typedef void ResizeSensorHandler(ResizeSensorEvent event);

lib/src/component/resize_sensor.dart

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,9 @@ library resize_sensor;
1919
import 'dart:collection';
2020
import 'dart:html';
2121

22-
import 'package:browser_detect/browser_detect.dart';
23-
import 'package:over_react/over_react.dart';
22+
import 'package:platform_detect/platform_detect.dart';
2423
import 'package:react/react.dart' as react;
25-
26-
// Callback for [ResizeSensorEvent]s
27-
typedef void ResizeSensorHandler(ResizeSensorEvent event);
24+
import 'package:over_react/over_react.dart';
2825

2926
/// A wrapper component that detects when its parent is resized.
3027
///
@@ -152,9 +149,9 @@ class ResizeSensorComponent extends UiComponent<ResizeSensorProps> {
152149
};
153150

154151
// IE 10 and Safari 8 need 'special' value prefixes for 'display:flex'.
155-
if (browser.isIe && browser.version <= '10') {
152+
if (browser.isInternetExplorer && browser.version.major <= 10) {
156153
wrapperStyles['display'] = '-ms-flexbox';
157-
} else if (browser.isSafari && browser.version < '9') {
154+
} else if (browser.isSafari && browser.version.major < 9) {
158155
wrapperStyles['display'] = '-webkit-flex';
159156
} else {
160157
wrapperStyles['display'] = 'flex';

lib/src/component_declaration/component_base.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import 'package:over_react/over_react.dart' show
2525
prettyPrintMap,
2626
unindent,
2727
PropError;
28+
2829
import 'package:over_react/src/component_declaration/component_type_checking.dart';
2930
import 'package:react/react.dart' as react;
3031
import 'package:react/react_client.dart';
@@ -186,6 +187,7 @@ abstract class UiComponent<TProps extends UiProps> extends react.Component {
186187
TProps typedPropsFactory(Map propsMap);
187188

188189
/// Returns a typed props object backed by a new Map.
190+
///
189191
/// Convenient for use with [getDefaultProps].
190192
TProps newProps() => typedPropsFactory({});
191193

@@ -237,6 +239,7 @@ abstract class UiStatefulComponent<TProps extends UiProps, TState extends UiStat
237239
TState typedStateFactory(Map stateMap);
238240

239241
/// Returns a typed state object backed by a new Map.
242+
///
240243
/// Convenient for use with [getInitialState] and [setState].
241244
TState newState() => typedStateFactory({});
242245

lib/src/component_declaration/flux_component.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright 2016 Workiva Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
library over_react.component_declaration.flux_component;
216

317
import 'dart:async';

lib/src/util/class_names.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ abstract class CssClassPropsMixin {
4242
String classNameBlacklist;
4343
}
4444

45-
4645
/// A MapView with the typed getters/setters for all CSS-class-related props.
4746
class CssClassPropsMapView extends MapView with CssClassPropsMixin {
4847
/// Create a new instance backed by the specified map.

lib/src/util/constants_base.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,16 @@ abstract class DebugFriendlyConstant {
2525
String get debugDescription;
2626

2727
@override
28-
String toString() => '$runtimeType.$_name ($debugDescription)';
28+
String toString() {
29+
var string = '$runtimeType.$_name';
30+
31+
var debugDescription = this.debugDescription;
32+
if (debugDescription != null) {
33+
string = '$string ($debugDescription)';
34+
}
35+
36+
return string;
37+
}
2938
}
3039

3140
/// A named constant with a helpful string representation

lib/src/util/css_value_util.dart

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,14 @@ class CssValue implements Comparable<CssValue> {
5757
unit = 'px';
5858
} else {
5959
var unitMatch = new RegExp(r'(?:rem|em|ex|vh|vw|vmin|vmax|%|px|cm|mm|in|pt|pc|ch)?$').firstMatch(source.toString());
60-
try {
61-
number = double.parse(unitMatch.input.substring(0, unitMatch.start));
6260
unit = unitMatch.group(0);
63-
if (unit == '') {
64-
unit = 'px';
65-
}
66-
} catch(e) {
67-
error = new ArgumentError.value(source, 'value', 'Invalid number/unit for CSS value');
61+
if (unit == '') {
62+
unit = 'px';
6863
}
64+
65+
number = double.parse(unitMatch.input.substring(0, unitMatch.start), (_) {
66+
error = new ArgumentError.value(source, 'value', 'Invalid number/unit for CSS value');
67+
});
6968
}
7069

7170
if (number != null && !number.isFinite) {

lib/src/util/dom_util.dart

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ library dom_util;
1616

1717
import 'dart:html';
1818

19+
import 'package:platform_detect/platform_detect.dart';
20+
21+
import './string_util.dart';
22+
import './validation_util.dart';
23+
1924
/// Returns whether [root] is the same as or contains the [other] node.
2025
///
2126
/// Returns false if either [root] or [other] is null.
@@ -51,3 +56,96 @@ Element getActiveElement() {
5156

5257
return activeElement;
5358
}
59+
60+
/// A list of the `type` attribute values for an HTML `<input>` element that implement [TextInputElementBase].
61+
///
62+
/// Necessary because of the circular inheritance hierarchy in Dart's [InputElement] class structure.
63+
///
64+
/// See: <https://github.com/dart-lang/sdk/issues/22967>
65+
///
66+
/// Related: [isTextInputElementBase]
67+
const List<String> inputTypesWithSelectionRangeSupport = const [
68+
'search',
69+
'text',
70+
'url',
71+
'tel',
72+
'email',
73+
'password',
74+
'number',
75+
];
76+
77+
/// Returns whether the provided [element] supports `setSelectionRange`.
78+
///
79+
/// Necessary in part because of the circular inheritance hierarchy in Dart's [InputElement] class structure,
80+
/// and in part because the classes do not correspond to whether setSelectionRange is supported (e.g. number inputs).
81+
///
82+
/// See: <https://github.com/dart-lang/sdk/issues/22967>
83+
bool supportsSelectionRange(InputElement element) {
84+
// Uncomment once https://github.com/dart-lang/sdk/issues/22967 is fixed.
85+
// if (element is TextInputElementBase) return true;
86+
87+
final type = element.getAttribute('type');
88+
return inputTypesWithSelectionRangeSupport.contains(type);
89+
}
90+
91+
/// Custom implementation to prevent the error that [TextInputElementBase.setSelectionRange] throws when called
92+
/// on an [EmailInputElement] or [NumberInputElement] since ONLY Chrome does not support it.
93+
///
94+
/// A warning will be displayed in the console instead of an error.
95+
///
96+
/// __Example that will throw an exception in Chrome:__
97+
/// InputElement inputNodeRef;
98+
///
99+
/// // This will throw an exception in Chrome when the node is focused.
100+
/// renderEmailInput() {
101+
/// return (Dom.input()
102+
/// ..type = 'email'
103+
/// ..onFocus = (_) {
104+
/// inputNodeRef.setSelectionRange(inputNodeRef.value.length, inputNodeRef.value.length);
105+
/// }
106+
/// ..ref = (instance) { inputNodeRef = instance; }
107+
/// )();
108+
/// }
109+
///
110+
/// __Example that will not throw:__
111+
/// InputElement inputNodeRef;
112+
///
113+
/// // This will not throw an exception - and will work in all
114+
/// // browsers except Chrome until
115+
/// // https://bugs.chromium.org/p/chromium/issues/detail?id=324360
116+
/// // is fixed.
117+
/// renderChromeSafeEmailInput() {
118+
/// return (Dom.input()
119+
/// ..type = 'email'
120+
/// ..onFocus = (_) {
121+
/// setSelectionRange(inputNodeRef, inputNodeRef.value.length, inputNodeRef.value.length);
122+
/// }
123+
/// ..ref = (instance) { inputNodeRef = instance; }
124+
/// )();
125+
/// }
126+
///
127+
/// See: <https://bugs.chromium.org/p/chromium/issues/detail?id=324360>
128+
void setSelectionRange(/* TextInputElement | TextAreaElement */Element input, int start, int end, [String direction]) {
129+
if (input is TextAreaElement) {
130+
input.setSelectionRange(start, end, direction);
131+
} else if (input is InputElement && supportsSelectionRange(input)) {
132+
if (browser.isChrome) {
133+
final inputType = input.getAttribute('type');
134+
135+
if (inputType == 'email' || inputType == 'number') {
136+
assert(ValidationUtil.warn(unindent(
137+
'''
138+
Google Chrome does not support `setSelectionRange` on email or number inputs.
139+
See: https://bugs.chromium.org/p/chromium/issues/detail?id=324360
140+
'''
141+
)));
142+
143+
return;
144+
}
145+
}
146+
147+
input.setSelectionRange(start, end, direction);
148+
} else {
149+
throw new ArgumentError.value(input, 'input', 'must be an instance of `TextInputElementBase`, `NumberInputElement` or `TextAreaElement`');
150+
}
151+
}

0 commit comments

Comments
 (0)