ComponentKit/Components/CKTransitionComponent.h (80 lines of code) (raw):
/*
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import <ComponentKit/CKDefines.h>
#if CK_NOT_SWIFT
#import <ComponentKit/ComponentBuilder.h>
#import <ComponentKit/CKIdValueWrapper.h>
namespace CK {
namespace BuilderDetails {
namespace TransitionComponentPropId {
constexpr static auto component = BuilderBasePropId::__max << 1;
constexpr static auto hasTransition = component << 1;
constexpr static auto hasTrigger = hasTransition << 1;
constexpr static auto __max = hasTransition;
}
namespace TransitionComponentDetails {
auto factory(CKComponent *, const Optional<Animation::Initial> &, const Optional<Animation::Final> &, id<NSObject>) -> CKComponent *;
}
template <PropsBitmapType PropsBitmap = 0>
class __attribute__((__may_alias__)) TransitionComponentBuilder
: public BuilderBase<TransitionComponentBuilder, PropsBitmap> {
public:
TransitionComponentBuilder() = default;
TransitionComponentBuilder(const CK::ComponentSpecContext &context) : BuilderBase<TransitionComponentBuilder, PropsBitmap>{context} { }
~TransitionComponentBuilder() = default;
/**
A child component that will transition between states in an animated fashion.
*/
auto &component(NS_RELEASES_ARGUMENT CKComponent *c)
{
constexpr auto componentIsNotSet = !PropBitmap::isSet(PropsBitmap, TransitionComponentPropId::component);
static_assert(componentIsNotSet, "Property 'component' is already set.");
_component = c;
return reinterpret_cast<
TransitionComponentBuilder<PropsBitmap | TransitionComponentPropId::component> &>(*this);
}
/**
An animation to apply to the new generation of the child component.
*/
auto &transitioningIn(Animation::Initial i)
{
_initial = std::move(i);
return reinterpret_cast<
TransitionComponentBuilder<PropsBitmap | TransitionComponentPropId::hasTransition> &>(*this);
}
/**
An animation to apply to the previous generation of the child component.
*/
auto &transitioningOut(Animation::Final f)
{
_final = std::move(f);
return reinterpret_cast<
TransitionComponentBuilder<PropsBitmap | TransitionComponentPropId::hasTransition> &>(*this);
}
/**
A value changes in which are used to trigger the transition.
@note @c RCObjectIsEqual is used to compare the previous and the new value.
*/
auto &triggerValue(NS_RELEASES_ARGUMENT id<NSObject> triggerValue)
{
_triggerValue = triggerValue;
return reinterpret_cast<
TransitionComponentBuilder<PropsBitmap | TransitionComponentPropId::hasTrigger> &>(*this);
}
/**
A value changes in which are used to trigger the transition.
@note @c T::operator == is used to compare the previous and the new value.
*/
template <typename T>
auto &triggerValue(T triggerValue)
{
_triggerValue = CKIdValueWrapperCreate<T>(triggerValue);
return reinterpret_cast<
TransitionComponentBuilder<PropsBitmap | TransitionComponentPropId::hasTrigger> &>(*this);
}
private:
friend BuilderBase<TransitionComponentBuilder, PropsBitmap>;
/**
Creates a new component instance with specified properties.
@note This method must @b not be called more than once on a given component builder instance.
*/
NS_RETURNS_RETAINED auto _build() noexcept -> CKComponent *
{
constexpr auto componentIsSet = PropBitmap::isSet(PropsBitmap, TransitionComponentPropId::component);
static_assert(componentIsSet, "Required property 'component' is not set.");
constexpr auto hasTransition = PropBitmap::isSet(PropsBitmap, TransitionComponentPropId::hasTransition);
static_assert(hasTransition, "At least one transition must be specified using 'transitioningIn' or 'transitioningOut'.");
constexpr auto hasTrigger = PropBitmap::isSet(PropsBitmap, TransitionComponentPropId::hasTrigger);
static_assert(hasTrigger, "At least one trigger must be specified using 'triggerValue'.");
return TransitionComponentDetails::factory(_component, _initial, _final, _triggerValue);
}
private:
CKComponent *_component;
Optional<Animation::Initial> _initial{};
Optional<Animation::Final> _final{};
id<NSObject> _triggerValue;
};
}
using TransitionComponentBuilderEmpty = BuilderDetails::TransitionComponentBuilder<>;
using TransitionComponentBuilderContext = BuilderDetails::TransitionComponentBuilder<BuilderDetails::BuilderBasePropId::context>;
/**
The component that allows its child component to transition to a new state in an animated fashion when a specified trigger value changes. The previous and the
current visual appearance can be animated independently of each other by passing both \c transitioningIn and \c transitioningOut .
@example A text component that, when the text is changed, fades the previous text out and slides the new text from the bottom:
@code
TransitionComponentBuilder()
.component(textComponent)
.transitionIn(Animation::parallel(Animation::alphaFrom(0), Animation::transitionYFrom(30)))
.transitionOut(Animation::alphaTo(0))
.triggerValue(text)
.build()
*/
auto TransitionComponentBuilder() -> TransitionComponentBuilderEmpty;
/**
The component that allows its child component to transition to a new state in an animated fashion when a specified trigger value changes. The previous and the
current visual appearance can be animated independently of each other by passing both @c transitioningIn and @c transitioningOut .
@param c The spec context to use.
@note This factory overload is to be used when a key is required to reference the built component in a spec from the
@c CK_ANIMATION function.
@example A text component that, when the text is changed, fades the previous text out and slides the new text from the bottom:
@code
TransitionComponentBuilder()
.component(textComponent)
.transitionIn(Animation::parallel(Animation::alphaFrom(0), Animation::transitionYFrom(30)))
.transitionOut(Animation::alphaTo(0))
.triggerValue(text)
.build()
*/
auto TransitionComponentBuilder(const CK::ComponentSpecContext &c) -> TransitionComponentBuilderContext;
}
#endif