Fabric: Implemetation of <Switch> component

Summary:
This is pretty straightforward implementation uses native `UISwitch`.
Suddenly we need Switch to test a bunch of other things.

Reviewed By: fkgozali

Differential Revision: D8344055

fbshipit-source-id: cfc51b8bc11198eb9d4d5e4745b96fb3a7f14de1
This commit is contained in:
Valentin Shergin 2018-06-15 11:25:16 -07:00 committed by Facebook Github Bot
parent 8fa2d847b6
commit f65e4e0174
11 changed files with 367 additions and 0 deletions

View File

@ -0,0 +1,21 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTViewComponentView.h>
NS_ASSUME_NONNULL_BEGIN
/**
* UIView class for root <Switch> component.
*/
@interface RCTSwitchComponentView : RCTViewComponentView
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,88 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSwitchComponentView.h"
#import <fabric/components/switch/SwitchEventEmitter.h>
#import <fabric/components/switch/SwitchProps.h>
using namespace facebook::react;
@implementation RCTSwitchComponentView {
UISwitch *_switchView;
BOOL _wasOn;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
_switchView = [[UISwitch alloc] initWithFrame:self.bounds];
[_switchView addTarget:self
action:@selector(onChange:)
forControlEvents:UIControlEventValueChanged];
auto &&defaultProps = SwitchProps();
_switchView.on = defaultProps.value;
self.contentView = _switchView;
}
return self;
}
- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
{
if (!oldProps) {
oldProps = _props ?: std::make_shared<SwitchProps>();
}
_props = props;
[super updateProps:props oldProps:oldProps];
auto oldSwitchProps = *std::dynamic_pointer_cast<const SwitchProps>(oldProps);
auto newSwitchProps = *std::dynamic_pointer_cast<const SwitchProps>(props);
// `value`
if (oldSwitchProps.value != newSwitchProps.value) {
_switchView.on = newSwitchProps.value;
_wasOn = newSwitchProps.value;
}
// `disabled`
if (oldSwitchProps.disabled != newSwitchProps.disabled) {
_switchView.enabled = !newSwitchProps.disabled;
}
// `tintColor`
if (oldSwitchProps.tintColor != newSwitchProps.tintColor) {
_switchView.tintColor = [UIColor colorWithCGColor:newSwitchProps.tintColor.get()];
}
// `onTintColor
if (oldSwitchProps.onTintColor != newSwitchProps.onTintColor) {
_switchView.onTintColor = [UIColor colorWithCGColor:newSwitchProps.onTintColor.get()];
}
// `thumbTintColor`
if (oldSwitchProps.thumbTintColor != newSwitchProps.thumbTintColor) {
_switchView.thumbTintColor = [UIColor colorWithCGColor:newSwitchProps.thumbTintColor.get()];
}
}
- (void)onChange:(UISwitch *)sender
{
if (_wasOn == sender.on) {
return;
}
_wasOn = sender.on;
std::dynamic_pointer_cast<const SwitchEventEmitter>(_eventEmitter)->onChange(sender.on);
}
@end

View File

@ -0,0 +1,78 @@
load("//configurations/buck/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_application_ios_flags", "get_debug_preprocessor_flags")
load("//ReactNative:DEFS.bzl", "ANDROID", "APPLE", "IS_OSS_BUILD", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library")
APPLE_COMPILER_FLAGS = []
if not IS_OSS_BUILD:
load("@xplat//configurations/buck/apple:flag_defs.bzl", "flags", "get_static_library_ios_flags")
APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), "compiler_flags")
rn_xplat_cxx_library(
name = "switch",
srcs = glob(
["**/*.cpp"],
exclude = glob(["tests/**/*.cpp"]),
),
headers = [],
header_namespace = "",
exported_headers = subdir_glob(
[
("", "*.h"),
],
prefix = "fabric/components/switch",
),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
fbobjc_tests = [
":tests",
],
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
tests = [],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
"xplat//folly:headers_only",
"xplat//folly:memory",
"xplat//folly:molly",
"xplat//third-party/glog:glog",
"xplat//yoga:yoga",
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/core:core"),
react_native_xplat_target("fabric/graphics:graphics"),
react_native_xplat_target("fabric/view:view"),
],
)
if not IS_OSS_BUILD:
load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test")
fb_xplat_cxx_test(
name = "tests",
srcs = glob(["tests/**/*.cpp"]),
headers = glob(["tests/**/*.h"]),
contacts = ["oncall+react_native@xmail.facebook.com"],
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
platforms = APPLE,
deps = [
"xplat//folly:molly",
"xplat//third-party/gmock:gtest",
":switch",
],
)

View File

@ -0,0 +1,19 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <fabric/components/switch/SwitchShadowNode.h>
#include <fabric/core/ConcreteComponentDescriptor.h>
namespace facebook {
namespace react {
using SwitchComponentDescriptor = ConcreteComponentDescriptor<SwitchShadowNode>;
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,18 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "SwitchEventEmitter.h"
namespace facebook {
namespace react {
void SwitchEventEmitter::onChange(const bool &value) const {
dispatchEvent("change", folly::dynamic::object("value", value));
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <fabric/view/ViewEventEmitter.h>
namespace facebook {
namespace react {
class SwitchEventEmitter:
public ViewEventEmitter {
public:
using ViewEventEmitter::ViewEventEmitter;
void onChange(const bool &value) const;
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,23 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <fabric/components/switch/SwitchProps.h>
#include <fabric/core/propsConversions.h>
namespace facebook {
namespace react {
SwitchProps::SwitchProps(const SwitchProps &sourceProps, const RawProps &rawProps):
ViewProps(sourceProps, rawProps),
value(convertRawProp(rawProps, "value", sourceProps.value, value)),
disabled(convertRawProp(rawProps, "disabled", sourceProps.disabled, disabled)),
tintColor(convertRawProp(rawProps, "tintColor", sourceProps.tintColor, tintColor)),
onTintColor(convertRawProp(rawProps, "onTintColor", sourceProps.onTintColor, onTintColor)),
thumbTintColor(convertRawProp(rawProps, "thumbTintColor", sourceProps.thumbTintColor, thumbTintColor)) {}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,32 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <fabric/graphics/Color.h>
#include <fabric/view/ViewProps.h>
namespace facebook {
namespace react {
// TODO (T28334063): Consider for codegen.
class SwitchProps final:
public ViewProps {
public:
SwitchProps() = default;
SwitchProps(const SwitchProps &sourceProps, const RawProps &rawProps);
#pragma mark - Props
const bool value {false};
const bool disabled {false};
const SharedColor tintColor {};
const SharedColor onTintColor {};
const SharedColor thumbTintColor {};
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,18 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <fabric/components/switch/SwitchShadowNode.h>
namespace facebook {
namespace react {
ComponentName SwitchShadowNode::getComponentName() const {
return ComponentName("Switch");
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <fabric/components/switch/SwitchEventEmitter.h>
#include <fabric/components/switch/SwitchProps.h>
#include <fabric/view/ConcreteViewShadowNode.h>
namespace facebook {
namespace react {
/*
* `ShadowNode` for <Switch> component.
*/
class SwitchShadowNode final:
public ConcreteViewShadowNode<SwitchProps, SwitchEventEmitter> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
ComponentName getComponentName() const override;
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <memory>
#include <gtest/gtest.h>
TEST(SwitchTest, testSomething) {
// TODO
}