Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UIP-1953 Sync changes from OverReact source #40

Merged
merged 3 commits into from
Jan 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,15 +495,15 @@ as shown in the examples above.

## Component Formatting
> __A note on dart_style:__
>
>
> Currently, [dart_style (dartfmt)](https://github.com/dart-lang/dart_style) decreases the readability of components
> built using [OverReact's fluent-style](#fluent-style-component-consumption).
> See https://github.com/dart-lang/dart_style/issues/549 for more info.
>
>
> We're exploring some different ideas to improve automated formatting, but for the time being, we __do not recommend__ using dart_style with OverReact.
>
>
> However, if you do choose to use dart_style, you can greatly improve its output by using trailing commas in children argument lists:
>
>
> * dart_style formatting:
> ```dart
> return (Button()
Expand Down
1 change: 1 addition & 0 deletions lib/over_react.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export 'src/util/key_constants.dart';
export 'src/util/map_util.dart';
export 'src/util/pretty_print.dart';
export 'src/util/prop_errors.dart';
export 'src/util/prop_key_util.dart';
export 'src/util/react_wrappers.dart';
export 'src/util/rem_util.dart';
export 'src/util/string_util.dart';
Expand Down
9 changes: 9 additions & 0 deletions lib/src/component/callback_typedefs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

library over_react.callback_typedefs;

import 'dart:html';

import 'package:over_react/over_react.dart' show ResizeSensorEvent;
import 'package:react/react.dart' as react;

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

/// A generic callback that takes no arguments.
typedef Callback();

// Callback for DOM elements
typedef Element ElementCallback();

// Callback for [ResizeSensorEvent]s
typedef void ResizeSensorHandler(ResizeSensorEvent event);
11 changes: 4 additions & 7 deletions lib/src/component/resize_sensor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ library resize_sensor;
import 'dart:collection';
import 'dart:html';

import 'package:browser_detect/browser_detect.dart';
import 'package:over_react/over_react.dart';
import 'package:platform_detect/platform_detect.dart';
import 'package:react/react.dart' as react;

// Callback for [ResizeSensorEvent]s
typedef void ResizeSensorHandler(ResizeSensorEvent event);
import 'package:over_react/over_react.dart';

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

// IE 10 and Safari 8 need 'special' value prefixes for 'display:flex'.
if (browser.isIe && browser.version <= '10') {
if (browser.isInternetExplorer && browser.version.major <= 10) {
wrapperStyles['display'] = '-ms-flexbox';
} else if (browser.isSafari && browser.version < '9') {
} else if (browser.isSafari && browser.version.major < 9) {
wrapperStyles['display'] = '-webkit-flex';
} else {
wrapperStyles['display'] = 'flex';
Expand Down
3 changes: 3 additions & 0 deletions lib/src/component_declaration/component_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import 'package:over_react/over_react.dart' show
prettyPrintMap,
unindent,
PropError;

import 'package:over_react/src/component_declaration/component_type_checking.dart';
import 'package:react/react.dart' as react;
import 'package:react/react_client.dart';
Expand Down Expand Up @@ -186,6 +187,7 @@ abstract class UiComponent<TProps extends UiProps> extends react.Component {
TProps typedPropsFactory(Map propsMap);

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

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

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

Expand Down
14 changes: 14 additions & 0 deletions lib/src/component_declaration/flux_component.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2016 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

library over_react.component_declaration.flux_component;

import 'dart:async';
Expand Down
1 change: 0 additions & 1 deletion lib/src/util/class_names.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ abstract class CssClassPropsMixin {
String classNameBlacklist;
}


/// A MapView with the typed getters/setters for all CSS-class-related props.
class CssClassPropsMapView extends MapView with CssClassPropsMixin {
/// Create a new instance backed by the specified map.
Expand Down
11 changes: 10 additions & 1 deletion lib/src/util/constants_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@ abstract class DebugFriendlyConstant {
String get debugDescription;

@override
String toString() => '$runtimeType.$_name ($debugDescription)';
String toString() {
var string = '$runtimeType.$_name';

var debugDescription = this.debugDescription;
if (debugDescription != null) {
string = '$string ($debugDescription)';
}

return string;
}
}

/// A named constant with a helpful string representation
Expand Down
13 changes: 6 additions & 7 deletions lib/src/util/css_value_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,14 @@ class CssValue implements Comparable<CssValue> {
unit = 'px';
} else {
var unitMatch = new RegExp(r'(?:rem|em|ex|vh|vw|vmin|vmax|%|px|cm|mm|in|pt|pc|ch)?$').firstMatch(source.toString());
try {
number = double.parse(unitMatch.input.substring(0, unitMatch.start));
unit = unitMatch.group(0);
if (unit == '') {
unit = 'px';
}
} catch(e) {
error = new ArgumentError.value(source, 'value', 'Invalid number/unit for CSS value');
if (unit == '') {
unit = 'px';
}

number = double.parse(unitMatch.input.substring(0, unitMatch.start), (_) {
error = new ArgumentError.value(source, 'value', 'Invalid number/unit for CSS value');
});
}

if (number != null && !number.isFinite) {
Expand Down
98 changes: 98 additions & 0 deletions lib/src/util/dom_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ library dom_util;

import 'dart:html';

import 'package:platform_detect/platform_detect.dart';

import './string_util.dart';
import './validation_util.dart';

/// Returns whether [root] is the same as or contains the [other] node.
///
/// Returns false if either [root] or [other] is null.
Expand Down Expand Up @@ -51,3 +56,96 @@ Element getActiveElement() {

return activeElement;
}

/// A list of the `type` attribute values for an HTML `<input>` element that implement [TextInputElementBase].
///
/// Necessary because of the circular inheritance hierarchy in Dart's [InputElement] class structure.
///
/// See: <https://github.com/dart-lang/sdk/issues/22967>
///
/// Related: [isTextInputElementBase]
const List<String> inputTypesWithSelectionRangeSupport = const [
'search',
'text',
'url',
'tel',
'email',
'password',
'number',
];

/// Returns whether the provided [element] supports `setSelectionRange`.
///
/// Necessary in part because of the circular inheritance hierarchy in Dart's [InputElement] class structure,
/// and in part because the classes do not correspond to whether setSelectionRange is supported (e.g. number inputs).
///
/// See: <https://github.com/dart-lang/sdk/issues/22967>
bool supportsSelectionRange(InputElement element) {
// Uncomment once https://github.com/dart-lang/sdk/issues/22967 is fixed.
// if (element is TextInputElementBase) return true;

final type = element.getAttribute('type');
return inputTypesWithSelectionRangeSupport.contains(type);
}

/// Custom implementation to prevent the error that [TextInputElementBase.setSelectionRange] throws when called
/// on an [EmailInputElement] or [NumberInputElement] since ONLY Chrome does not support it.
///
/// A warning will be displayed in the console instead of an error.
///
/// __Example that will throw an exception in Chrome:__
/// InputElement inputNodeRef;
///
/// // This will throw an exception in Chrome when the node is focused.
/// renderEmailInput() {
/// return (Dom.input()
/// ..type = 'email'
/// ..onFocus = (_) {
/// inputNodeRef.setSelectionRange(inputNodeRef.value.length, inputNodeRef.value.length);
/// }
/// ..ref = (instance) { inputNodeRef = instance; }
/// )();
/// }
///
/// __Example that will not throw:__
/// InputElement inputNodeRef;
///
/// // This will not throw an exception - and will work in all
/// // browsers except Chrome until
/// // https://bugs.chromium.org/p/chromium/issues/detail?id=324360
/// // is fixed.
/// renderChromeSafeEmailInput() {
/// return (Dom.input()
/// ..type = 'email'
/// ..onFocus = (_) {
/// setSelectionRange(inputNodeRef, inputNodeRef.value.length, inputNodeRef.value.length);
/// }
/// ..ref = (instance) { inputNodeRef = instance; }
/// )();
/// }
///
/// See: <https://bugs.chromium.org/p/chromium/issues/detail?id=324360>
void setSelectionRange(/* TextInputElement | TextAreaElement */Element input, int start, int end, [String direction]) {
if (input is TextAreaElement) {
input.setSelectionRange(start, end, direction);
} else if (input is InputElement && supportsSelectionRange(input)) {
if (browser.isChrome) {
final inputType = input.getAttribute('type');

if (inputType == 'email' || inputType == 'number') {
assert(ValidationUtil.warn(unindent(
'''
Google Chrome does not support `setSelectionRange` on email or number inputs.
See: https://bugs.chromium.org/p/chromium/issues/detail?id=324360
'''
)));

return;
}
}

input.setSelectionRange(start, end, direction);
} else {
throw new ArgumentError.value(input, 'input', 'must be an instance of `TextInputElementBase`, `NumberInputElement` or `TextAreaElement`');
}
}
1 change: 0 additions & 1 deletion lib/src/util/handler_chain_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ final CallbackUtil0Arg callbacks = co
/// Provides chaining utilities for [ResizeSensorHandler].
final CallbackUtil1Arg<ResizeSensorEvent> resizeEventCallbacks = const CallbackUtil1Arg<ResizeSensorEvent>();


typedef Callback0Arg();
typedef Callback1Arg<T1>(T1 arg1);
typedef Callback2Arg<T1, T2>(T1 arg1, T2 arg2);
Expand Down
13 changes: 12 additions & 1 deletion lib/src/util/map_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ library over_react.map_util;

import 'dart:collection';

import 'package:over_react/src/component/prop_mixins.dart';
import 'package:over_react/src/component_declaration/transformer_helpers.dart';
import 'package:over_react/src/component/dom_components.dart';
import 'package:over_react/src/component/prop_mixins.dart';

/// Returns a copy of the specified props map, omitting reserved React props by default,
/// in addition to any specified keys.
Expand Down Expand Up @@ -60,6 +61,16 @@ Map getPropsToForward(Map props, {bool omitReactProps: true, bool onlyCopyDomPro
return propsToForward;
}

/// Returns a copy of the style map found in [props].
///
/// Returns an empty map if [props] or its style map are null.
Map<String, dynamic> newStyleFromProps(Map props) {
if (props == null) return {};

var existingStyle = domProps(props).style;
return existingStyle == null ? {} : new Map.from(existingStyle);
}

SplayTreeSet _validDomProps = new SplayTreeSet()
..addAll(const $PropKeys(DomPropsMixin))
..addAll(const $PropKeys(SvgPropsMixin));
61 changes: 61 additions & 0 deletions lib/src/util/prop_key_util.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2016 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

library over_react.prop_key_util;

import 'dart:collection';

/// Returns the string key of the [factory] prop accessed in [accessProp].
///
/// Example usage:
///
/// var valuePropKey = getPropKey((props) => props.value, TextInput);
String getPropKey(void accessProp(Map keySpy), Map factory(Map props)) {
return _getKey((Map keySpy) {
return accessProp(factory(keySpy));
});
}

dynamic _getKey(void accessKey(Map keySpy)) {
var keySpy = new _SingleKeyAccessMapSpy(const {});

accessKey(keySpy);

return keySpy.key;
}

/// Helper class that stores the key accessed while getting a value of a map.
class _SingleKeyAccessMapSpy extends MapView {
_SingleKeyAccessMapSpy(Map map) : super(map);

bool _hasBeenAccessed = false;

dynamic _key;

dynamic get key {
if (!_hasBeenAccessed) throw new StateError('Key has not been accessed.');

return _key;
}

@override
operator[](key) {
if (_hasBeenAccessed) throw new StateError('A key has already been accessed.');

_key = key;
_hasBeenAccessed = true;

return null;
}
}
Loading