// Copyright 2004-present Facebook. All Rights Reserved.
package com.facebook.react.uimanager;
import javax.annotation.Nullable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Use this annotation to annotate properties of native views that should be exposed to JS. This
* annotation should only be used for setter methods of subclasses of {@link ViewManager}.
*
* Each annotated method should return {@code void} and take exactly two arguments: first being
* a view instance to be updated and second a value that should be set.
*
* Allowed types of values are:
* - primitives (int, boolean, double, float)
* - {@link String}
* - {@link Boolean}
* - {@link ReadableArray}
* - {@link ReadableMap}
*
* When property gets removed from the corresponding component in React, annotated setter will be
* called with {@code null} in case of non-primitive value type or with a default value in case when
* the value type is a primitive (use appropriate default field of this annotation to customize
* default value that is going to be used: {@link #defaultBoolean}, {@link #defaultDouble}, etc.)
*
* Since in case of property removal for non-primitive value type setter will be called with value
* set to {@code null} it's required that value type is annotated with {@link Nullable}.
*
* Note: Since boolean property type can be represented both as primitive and wrapped default value
* set through {@link #defaultBoolean} is only respected for primitive type and for the wrapped type
* {@code null} will be used as a default.
*/
@Retention(RUNTIME)
@Target(ElementType.METHOD)
public @interface ReactProp {
// Used as a default value for "customType" property as "null" is not allowed. Moreover, when this
// const is used in annotation declaration compiler will actually create a copy of it, so
// comparing it using "==" with this filed doesn't work either. We need to compare using "equals"
// which means that this value needs to be unique.
String USE_DEFAULT_TYPE = "__default_type__";
/**
* Name of the property exposed to JS that will be updated using setter method annotated with
* the given instance of {@code ReactProp} annotation
*/
String name();
/**
* Type of property that will be send to JS. In most of the cases {@code customType} should not be
* set in which case default type will be send to JS based on the type of value argument from the
* setter method (e.g. for {@code int}, {@code double} default is "number", for
* {@code ReadableArray} it's "Array"). Custom type may be used when additional processing of the
* value needs to be done in JS before sending it over the brige. A good example of that would be
* backgroundColor property, which is expressed as a {@code String} in JS, but we use
* {@code processColor} JS module to convert it to {@code int} before sending over the bridge.
*/
@Nullable String customType() default USE_DEFAULT_TYPE;
/**
* Default value for property of type {@code double}. This value will be provided to property
* setter method annotated with {@link ReactProp} if property with a given name gets removed
* from the component description in JS
*/
double defaultDouble() default 0.0;
/**
* Default value for property of type {@code float}. This value will be provided to property
* setter method annotated with {@link ReactProp} if property with a given name gets removed
* from the component description in JS
*/
float defaultFloat() default 0.0f;
/**
* Default value for property of type {@code int}. This value will be provided to property
* setter method annotated with {@link ReactProp} if property with a given name gets removed
* from the component description in JS
*/
int defaultInt() default 0;
/**
* Default value for property of type {@code boolean}. This value will be provided to property
* setter method annotated with {@link ReactProp} if property with a given name gets removed
* from the component description in JS
*/
boolean defaultBoolean() default false;
}