From 9c37a0032ab90ae9fa0fc0c0c816954c64fec264 Mon Sep 17 00:00:00 2001 From: BartoszKlonowski Date: Fri, 10 Apr 2026 13:04:47 +0200 Subject: [PATCH 1/7] Rewrite Android implementation to be using Kotlin --- package/android/build.gradle | 3 + .../slider/ReactSlider.java | 398 ------------------ .../slider/ReactSlider.kt | 364 ++++++++++++++++ .../slider/ReactSliderEvent.java | 56 --- .../slider/ReactSliderEvent.kt | 31 ++ .../slider/ReactSliderManager.java | 243 ----------- .../slider/ReactSliderManager.kt | 192 +++++++++ .../slider/ReactSliderManagerImpl.java | 147 ------- .../slider/ReactSliderManagerImpl.kt | 156 +++++++ .../slider/ReactSliderPackage.java | 29 -- .../slider/ReactSliderPackage.kt | 22 + .../slider/ReactSlidingCompleteEvent.java | 54 --- .../slider/ReactSlidingCompleteEvent.kt | 31 ++ .../slider/ReactSlidingStartEvent.java | 54 --- .../slider/ReactSlidingStartEvent.kt | 31 ++ 15 files changed, 830 insertions(+), 981 deletions(-) delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.java create mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.java create mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.java create mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.java create mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.java create mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.java create mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.java create mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.kt diff --git a/package/android/build.gradle b/package/android/build.gradle index 362ad4a5..97fdd133 100644 --- a/package/android/build.gradle +++ b/package/android/build.gradle @@ -9,10 +9,12 @@ buildscript { classpath("com.android.tools.build:gradle:7.1.1") classpath("com.facebook.react:react-native-gradle-plugin") classpath("de.undercouch:gradle-download-task:5.0.1") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21") } } apply plugin: 'com.android.library' +apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'com.facebook.react' def getExtOrDefault(name) { @@ -59,5 +61,6 @@ repositories { dependencies { //noinspection GradleDynamicVersion api 'com.facebook.react:react-native:+' + implementation 'org.jetbrains.kotlin:kotlin-stdlib' } diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.java b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.java deleted file mode 100644 index 19808941..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.java +++ /dev/null @@ -1,398 +0,0 @@ -package com.reactnativecommunity.slider; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.drawable.BitmapDrawable; -import android.os.Build; -import android.util.Log; -import android.util.AttributeSet; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; -import androidx.appcompat.widget.AppCompatSeekBar; - -import java.net.URL; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import javax.annotation.Nullable; -import com.facebook.react.modules.i18nmanager.I18nUtil; -/** - * Slider that behaves more like the iOS one, for consistency. - * - *

On iOS, the value is 0..1. Android SeekBar only supports integer values. For consistency, we - * pretend in JS that the value is 0..1 but set the SeekBar value to 0..100. - * - *

Note that the slider is _not_ a controlled component (setValue isn't called during dragging). - */ -public class ReactSlider extends AppCompatSeekBar { - - /** - * If step is 0 (unset) we default to this total number of steps. Don't use 100 which leads to - * rounding errors (0.200000000001). - */ - private static int DEFAULT_TOTAL_STEPS = 128; - - /** - * We want custom min..max range. Android only supports 0..max range so we implement this - * ourselves. - */ - private double mMinValue = 0; - - private double mMaxValue = 0; - - /** - * Value sent from JS (setState). Doesn't get updated during drag (slider is not a controlled - * component). - */ - private double mValue = 0; - - private boolean isSliding = false; - - /** If zero it's determined automatically. */ - private double mStep = 0; - - private double mStepCalculated = 0; - - private String mAccessibilityUnits; - - private List mAccessibilityIncrements; - - /** Real limit value based on min and max values. This comes from props */ - private double mRealLowerLimit = Long.MIN_VALUE; - - /** Lower limit based on the SeekBar progress 0..total steps */ - private int mLowerLimit; - - /** Real limit value based on min and max values. This comes from props */ - private double mRealUpperLimit = Long.MAX_VALUE; - - /** Upper limit based on the SeekBar progress 0..total steps */ - private int mUpperLimit; - - /** Thumb size in pixels (0 = default) */ - private int mThumbSizePx = 0; - - /** Original thumb drawable URI */ - @Nullable private String mThumbImageUri = null; - - /** Cached thumb tint color */ - @Nullable private Integer mThumbTintColor = null; - - public ReactSlider(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance(); - super.setLayoutDirection(sharedI18nUtilInstance.isRTL(context) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR); - disableStateListAnimatorIfNeeded(); - } - - private void disableStateListAnimatorIfNeeded() { - // We disable the state list animator for Android 6 and 7; this is a hack to prevent T37452851 - // and https://github.com/facebook/react-native/issues/9979 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - super.setStateListAnimator(null); - } - } - - /* package */ void setMaxValue(double max) { - mMaxValue = max; - updateAll(); - } - - /* package */ void setMinValue(double min) { - mMinValue = min; - updateAll(); - } - - /*package*/ int getValidProgressValue(int progress) { - if (progress < getLowerLimit()) { - progress = getLowerLimit(); - } else if (progress > getUpperLimit()) { - progress = getUpperLimit(); - } - return progress; - } - - /* package */ void setValue(double value) { - mValue = value; - updateValue(); - } - - /* package */ void setStep(double step) { - mStep = step; - updateAll(); - } - - /* package */ void setLowerLimit(double value) { - mRealLowerLimit = value; - updateLowerLimit(); - } - - /* package */ void setUpperLimit(double value) { - mRealUpperLimit = value; - updateUpperLimit(); - } - - int getLowerLimit() { - return this.mLowerLimit; - } - - int getUpperLimit() { - return this.mUpperLimit; - } - - boolean isSliding() { - return isSliding; - } - - void isSliding(boolean isSliding) { - this.isSliding = isSliding; - } - - void setAccessibilityUnits(String accessibilityUnits) { - mAccessibilityUnits = accessibilityUnits; - } - - void setAccessibilityIncrements(List accessibilityIncrements) { - mAccessibilityIncrements = accessibilityIncrements; - } - - @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(event); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED || - (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SELECTED && this.isAccessibilityFocused())) { - this.setupAccessibility((int)mValue); - } - } - } - - @Override - public void announceForAccessibility(CharSequence text) { - Context ctx = this.getContext(); - final AccessibilityManager manager = (AccessibilityManager) ctx.getSystemService(Context.ACCESSIBILITY_SERVICE); - - if (manager.isEnabled()) { - final AccessibilityEvent e = AccessibilityEvent.obtain(); - e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT); - e.setClassName(this.getClass().getName()); - e.setPackageName(ctx.getPackageName()); - e.getText().add(text); - - TimerTask task = new TimerTask() { - @Override - public void run() { - manager.sendAccessibilityEvent(e); - } - }; - - Timer timer = new Timer(); - timer.schedule(task, 1000); - } - } - - public void setupAccessibility(int index) { - if (mAccessibilityUnits != null && mAccessibilityIncrements != null && mAccessibilityIncrements.size() - 1 == (int)mMaxValue) { - String sliderValue = mAccessibilityIncrements.get(index); - int stringLength = mAccessibilityUnits.length(); - - String spokenUnits = mAccessibilityUnits; - if (sliderValue != null && Integer.parseInt(sliderValue) == 1) { - spokenUnits = spokenUnits.substring(0, stringLength - 1); - } - - this.announceForAccessibility(String.format("%s %s", sliderValue, spokenUnits)); - } - } - - - - /** - * Convert SeekBar's native progress value (e.g. 0..100) to a value passed to JS (e.g. -1.0..2.5). - */ - public double toRealProgress(int seekBarProgress) { - if (seekBarProgress == getMax()) { - return mMaxValue; - } - return seekBarProgress * getStepValue() + mMinValue; - } - - /** Update underlying native SeekBar's values. */ - private void updateAll() { - if (mStep == 0) { - mStepCalculated = (mMaxValue - mMinValue) / (double) DEFAULT_TOTAL_STEPS; - } - setMax(getTotalSteps()); - setKeyProgressIncrement(1); - updateLowerLimit(); - updateUpperLimit(); - updateValue(); - } - - /** Update limit based on props limit, max and min - * Fallback to upper limit if invalid configuration provided - */ - private void updateLowerLimit() { - double limit = Math.max(mRealLowerLimit, mMinValue); - int lowerLimit = (int) Math.round((limit - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps()); - if(lowerLimit > mUpperLimit) { - Log.d("Invalid configuration", "upperLimit < lowerLimit; lowerLimit not set"); - }else { - mLowerLimit = Math.min(lowerLimit, mUpperLimit); - } - } - - /** Update limit based on props limit, max and min - */ - private void updateUpperLimit() { - double limit = Math.min(mRealUpperLimit, mMaxValue); - int upperLimit = (int) Math.round((limit - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps()); - if (mLowerLimit > upperLimit) { - Log.d("Invalid configuration", "upperLimit < lowerLimit; upperLimit not set"); - } else { - mUpperLimit = upperLimit; - } - } - - /** Update value only (optimization in case only value is set). */ - private void updateValue() { - setProgress((int) Math.round((mValue - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps())); - } - - private int getTotalSteps() { - return (int) Math.ceil((mMaxValue - mMinValue) / getStepValue()); - } - - private double getStepValue() { - return mStep > 0 ? mStep : mStepCalculated; - } - - private BitmapDrawable getBitmapDrawable(final String uri) { - BitmapDrawable bitmapDrawable = null; - ExecutorService executorService = Executors.newSingleThreadExecutor(); - Future future = executorService.submit(new Callable() { - @Override - public BitmapDrawable call() { - BitmapDrawable bitmapDrawable = null; - try { - Bitmap bitmap = null; - if (uri.startsWith("http://") || uri.startsWith("https://") || - uri.startsWith("file://") || uri.startsWith("asset://") || uri.startsWith("data:")) { - bitmap = BitmapFactory.decodeStream(new URL(uri).openStream()); - } else { - int drawableId = getResources() - .getIdentifier(uri, "drawable", getContext() - .getPackageName()); - bitmap = BitmapFactory.decodeResource(getResources(), drawableId); - } - - bitmapDrawable = new BitmapDrawable(getResources(), bitmap); - } catch (Exception e) { - e.printStackTrace(); - } - return bitmapDrawable; - } - }); - try { - bitmapDrawable = future.get(); - } catch (Exception e) { - e.printStackTrace(); - } - return bitmapDrawable; - } - - public void setThumbImage(@Nullable final String uri) { - mThumbImageUri = uri; - refreshThumb(); - } - - public void setThumbSize(final float size) { - float density = getResources().getDisplayMetrics().density; - mThumbSizePx = size > 0 ? Math.round(size * density) : 0; - refreshThumb(); - } - - public void setThumbTintColor(@Nullable final Integer color) { - mThumbTintColor = color; - if (mThumbImageUri != null || mThumbSizePx > 0) { - refreshThumb(); - } else { - applyThumbTintColorFilter(); - } - } - - private void applyThumbTintColorFilter() { - if (getThumb() == null) { - return; - } - - if (mThumbTintColor != null) { - getThumb().setColorFilter(mThumbTintColor, PorterDuff.Mode.SRC_IN); - } else { - getThumb().clearColorFilter(); - } - } - - private void refreshThumb() { - if (mThumbImageUri != null) { - BitmapDrawable drawable = getBitmapDrawable(mThumbImageUri); - if (drawable != null) { - if (mThumbSizePx > 0) { - Bitmap originalBitmap = drawable.getBitmap(); - Bitmap scaledBitmap = - Bitmap.createScaledBitmap(originalBitmap, mThumbSizePx, mThumbSizePx, true); - setThumb(new BitmapDrawable(getResources(), scaledBitmap)); - } else { - setThumb(drawable); - } - applyThumbTintColorFilter(); - // Enable alpha channel for the thumbImage - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - setSplitTrack(false); - } - return; - } - } - - if (mThumbSizePx > 0) { - Bitmap bitmap = Bitmap.createBitmap(mThumbSizePx, mThumbSizePx, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - - int fillColor = - mThumbTintColor != null - ? mThumbTintColor - : (getThumbTintList() != null ? getThumbTintList().getDefaultColor() : 0xFFFFFFFF); - - Paint fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - fillPaint.setStyle(Paint.Style.FILL); - fillPaint.setColor(fillColor); - float radius = mThumbSizePx / 2f; - canvas.drawCircle(radius, radius, radius, fillPaint); - - Paint strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - strokePaint.setStyle(Paint.Style.STROKE); - strokePaint.setStrokeWidth(1); - strokePaint.setColor(0x1A000000); - canvas.drawCircle(radius, radius, radius - 0.5f, strokePaint); - - setThumb(new BitmapDrawable(getResources(), bitmap)); - applyThumbTintColorFilter(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - setSplitTrack(false); - } - } else { - // No special sizing; keep existing thumb, only apply tint if needed. - applyThumbTintColorFilter(); - } - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt new file mode 100644 index 00000000..0a8a2149 --- /dev/null +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt @@ -0,0 +1,364 @@ +package com.reactnativecommunity.slider + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.PorterDuff +import android.graphics.drawable.BitmapDrawable +import android.os.Build +import android.util.AttributeSet +import android.util.Log +import android.view.accessibility.AccessibilityEvent +import android.view.accessibility.AccessibilityManager +import androidx.appcompat.widget.AppCompatSeekBar +import com.facebook.react.modules.i18nmanager.I18nUtil +import java.net.URL +import java.util.Timer +import java.util.TimerTask +import java.util.concurrent.Executors + +/** + * Slider that behaves more like the iOS one, for consistency. + * + * On iOS, the value is 0..1. Android SeekBar only supports integer values. For consistency, we + * pretend in JS that the value is 0..1 but set the SeekBar value to 0..100. + * + * Note that the slider is _not_ a controlled component (setValue isn't called during dragging). + */ +class ReactSlider @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, +) : AppCompatSeekBar(context, attrs) { + + /** + * If step is 0 (unset) we default to this total number of steps. Don't use 100 which leads to + * rounding errors (0.200000000001). + */ + private val defaultTotalSteps = 128 + + /** + * We want custom min..max range. Android only supports 0..max range so we implement this + * ourselves. + */ + private var minValue = 0.0 + private var maxValue = 0.0 + + /** + * Value sent from JS (setState). Doesn't get updated during drag (slider is not a controlled + * component). + */ + private var value = 0.0 + + internal var isSliding = false + + /** If zero it's determined automatically. */ + private var step = 0.0 + private var stepCalculated = 0.0 + private var accessibilityUnits: String? = null + private var accessibilityIncrements: List? = null + + /** Real limit value based on min and max values. This comes from props */ + private var realLowerLimit = Long.MIN_VALUE.toDouble() + + /** Lower limit based on the SeekBar progress 0..total steps */ + internal var lowerLimit = 0 + private set + + /** Real limit value based on min and max values. This comes from props */ + private var realUpperLimit = Long.MAX_VALUE.toDouble() + + /** Upper limit based on the SeekBar progress 0..total steps */ + internal var upperLimit = 0 + private set + + /** Thumb size in pixels (0 = default) */ + private var thumbSizePx = 0 + + /** Original thumb drawable URI */ + private var thumbImageUri: String? = null + + /** Cached thumb tint color */ + private var thumbTintColor: Int? = null + + init { + val sharedI18nUtilInstance = I18nUtil.getInstance() + layoutDirection = + if (sharedI18nUtilInstance.isRTL(context)) LAYOUT_DIRECTION_RTL else LAYOUT_DIRECTION_LTR + disableStateListAnimatorIfNeeded() + } + + private fun disableStateListAnimatorIfNeeded() { + // We disable the state list animator for Android 6 and 7; this is a hack to prevent T37452851 + // and https://github.com/facebook/react-native/issues/9979 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && + Build.VERSION.SDK_INT < Build.VERSION_CODES.O + ) { + stateListAnimator = null + } + } + + internal fun setMaxValue(max: Double) { + maxValue = max + updateAll() + } + + internal fun setMinValue(min: Double) { + minValue = min + updateAll() + } + + internal fun getValidProgressValue(progress: Int): Int { + return when { + progress < lowerLimit -> lowerLimit + progress > upperLimit -> upperLimit + else -> progress + } + } + + internal fun setValue(value: Double) { + this.value = value + updateValue() + } + + internal fun setStep(step: Double) { + this.step = step + updateAll() + } + + internal fun setLowerLimit(value: Double) { + realLowerLimit = value + updateLowerLimit() + } + + internal fun setUpperLimit(value: Double) { + realUpperLimit = value + updateUpperLimit() + } + + internal fun setAccessibilityUnits(accessibilityUnits: String?) { + this.accessibilityUnits = accessibilityUnits + } + + internal fun setAccessibilityIncrements(accessibilityIncrements: List?) { + this.accessibilityIncrements = accessibilityIncrements + } + + override fun onPopulateAccessibilityEvent(event: AccessibilityEvent) { + super.onPopulateAccessibilityEvent(event) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (event.eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED || + (event.eventType == AccessibilityEvent.TYPE_VIEW_SELECTED && isAccessibilityFocused) + ) { + setupAccessibility(value.toInt()) + } + } + } + + override fun announceForAccessibility(text: CharSequence?) { + val ctx = context + val manager = ctx.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager + + if (manager.isEnabled && text != null) { + val e = AccessibilityEvent.obtain() + e.eventType = AccessibilityEvent.TYPE_ANNOUNCEMENT + e.className = javaClass.name + e.packageName = ctx.packageName + e.text.add(text) + + val task = object : TimerTask() { + override fun run() { + manager.sendAccessibilityEvent(e) + } + } + + Timer().schedule(task, 1000) + } + } + + fun setupAccessibility(index: Int) { + val units = accessibilityUnits + val increments = accessibilityIncrements + if (units != null && increments != null && increments.size - 1 == maxValue.toInt()) { + val sliderValue = increments[index] + val stringLength = units.length + var spokenUnits = units + if (sliderValue.toInt() == 1) { + spokenUnits = spokenUnits.substring(0, stringLength - 1) + } + announceForAccessibility(String.format("%s %s", sliderValue, spokenUnits)) + } + } + + /** + * Convert SeekBar's native progress value (e.g. 0..100) to a value passed to JS (e.g. -1.0..2.5). + */ + fun toRealProgress(seekBarProgress: Int): Double { + return if (seekBarProgress == max) { + maxValue + } else { + seekBarProgress * getStepValue() + minValue + } + } + + /** Update underlying native SeekBar's values. */ + private fun updateAll() { + if (step == 0.0) { + stepCalculated = (maxValue - minValue) / defaultTotalSteps.toDouble() + } + max = totalSteps + keyProgressIncrement = 1 + updateLowerLimit() + updateUpperLimit() + updateValue() + } + + /** + * Update limit based on props limit, max and min Fallback to upper limit if invalid configuration + * provided + */ + private fun updateLowerLimit() { + val limit = maxOf(realLowerLimit, minValue) + val lower = kotlin.math.round((limit - minValue) / (maxValue - minValue) * totalSteps).toInt() + if (lower > upperLimit) { + Log.d("Invalid configuration", "upperLimit < lowerLimit; lowerLimit not set") + } else { + lowerLimit = minOf(lower, upperLimit) + } + } + + /** Update limit based on props limit, max and min */ + private fun updateUpperLimit() { + val limit = minOf(realUpperLimit, maxValue) + val upper = kotlin.math.round((limit - minValue) / (maxValue - minValue) * totalSteps).toInt() + if (lowerLimit > upper) { + Log.d("Invalid configuration", "upperLimit < lowerLimit; upperLimit not set") + } else { + upperLimit = upper + } + } + + /** Update value only (optimization in case only value is set). */ + private fun updateValue() { + progress = + kotlin.math.round((value - minValue) / (maxValue - minValue) * totalSteps).toInt() + } + + private val totalSteps: Int + get() = kotlin.math.ceil((maxValue - minValue) / getStepValue()).toInt() + + private fun getStepValue(): Double = if (step > 0) step else stepCalculated + + private fun getBitmapDrawable(uri: String): BitmapDrawable? { + val executorService = Executors.newSingleThreadExecutor() + val future = executorService.submit { + try { + val bitmap: Bitmap? = + if (uri.startsWith("http://") || uri.startsWith("https://") || + uri.startsWith("file://") || uri.startsWith("asset://") || uri.startsWith("data:") + ) { + BitmapFactory.decodeStream(URL(uri).openStream()) + } else { + val drawableId = + resources.getIdentifier(uri, "drawable", context.packageName) + BitmapFactory.decodeResource(resources, drawableId) + } + BitmapDrawable(resources, bitmap) + } catch (e: Exception) { + e.printStackTrace() + null + } + } + return try { + future.get() + } catch (e: Exception) { + e.printStackTrace() + null + } + } + + fun setThumbImage(uri: String?) { + thumbImageUri = uri + refreshThumb() + } + + fun setThumbSize(size: Float) { + val density = resources.displayMetrics.density + thumbSizePx = if (size > 0) kotlin.math.round(size * density).toInt() else 0 + refreshThumb() + } + + fun setThumbTintColor(color: Int?) { + thumbTintColor = color + if (thumbImageUri != null || thumbSizePx > 0) { + refreshThumb() + } else { + applyThumbTintColorFilter() + } + } + + private fun applyThumbTintColorFilter() { + val thumbDrawable = getThumb() ?: return + val tint = thumbTintColor + if (tint != null) { + thumbDrawable.setColorFilter(tint, PorterDuff.Mode.SRC_IN) + } else { + thumbDrawable.clearColorFilter() + } + } + + private fun refreshThumb() { + val uri = thumbImageUri + if (uri != null) { + val drawable = getBitmapDrawable(uri) + if (drawable != null) { + if (thumbSizePx > 0) { + val originalBitmap = drawable.bitmap + val scaledBitmap = + Bitmap.createScaledBitmap(originalBitmap, thumbSizePx, thumbSizePx, true) + setThumb(BitmapDrawable(resources, scaledBitmap)) + } else { + setThumb(drawable) + } + applyThumbTintColorFilter() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + splitTrack = false + } + return + } + } + + if (thumbSizePx > 0) { + val bitmap = Bitmap.createBitmap(thumbSizePx, thumbSizePx, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + + val fillColor = + thumbTintColor + ?: (thumbTintList?.defaultColor ?: 0xFFFFFFFF.toInt()) + + val fillPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.FILL + color = fillColor + } + val radius = thumbSizePx / 2f + canvas.drawCircle(radius, radius, radius, fillPaint) + + val strokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.STROKE + strokeWidth = 1f + color = 0x1A000000 + } + canvas.drawCircle(radius, radius, radius - 0.5f, strokePaint) + + setThumb(BitmapDrawable(resources, bitmap)) + applyThumbTintColorFilter() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + splitTrack = false + } + } else { + applyThumbTintColorFilter() + } + } +} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.java b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.java deleted file mode 100644 index 1fe33f6c..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.reactnativecommunity.slider; - -import androidx.annotation.Nullable; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.uimanager.events.Event; - -/** - * Event emitted by a ReactSliderManager when user changes slider position. - */ -public class ReactSliderEvent extends Event { - - public static final String EVENT_NAME = "topChange"; - - private final double mValue; - private final boolean mFromUser; - - public ReactSliderEvent(int viewId, double value, boolean fromUser) { - super(viewId); - mValue = value; - mFromUser = fromUser; - } - - public double getValue() { - return mValue; - } - - public boolean isFromUser() { - return mFromUser; - } - - - @Override - public String getEventName() { - return EVENT_NAME; - } - - @Override - public short getCoalescingKey() { - return 0; - } - - @Nullable - @Override - protected WritableMap getEventData() { - return serializeEventData(); - } - - private WritableMap serializeEventData() { - WritableMap eventData = Arguments.createMap(); - eventData.putInt("target", getViewTag()); - eventData.putDouble("value", getValue()); - eventData.putBoolean("fromUser", isFromUser()); - return eventData; - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.kt new file mode 100644 index 00000000..c25d835b --- /dev/null +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.kt @@ -0,0 +1,31 @@ +package com.reactnativecommunity.slider + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +/** Event emitted by a ReactSliderManager when user changes slider position. */ +class ReactSliderEvent( + viewId: Int, + private val value: Double, + private val fromUser: Boolean, +) : Event(viewId) { + + override fun getEventName(): String = EVENT_NAME + + override fun getCoalescingKey(): Short = 0 + + override fun getEventData(): WritableMap? = serializeEventData() + + private fun serializeEventData(): WritableMap { + val eventData = Arguments.createMap() + eventData.putInt("target", viewTag) + eventData.putDouble("value", value) + eventData.putBoolean("fromUser", fromUser) + return eventData + } + + companion object { + const val EVENT_NAME = "topChange" + } +} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.java b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.java deleted file mode 100644 index bdd08f18..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.reactnativecommunity.slider; - -import android.content.Context; -import android.view.View; -import android.widget.SeekBar; -import androidx.annotation.Nullable; - -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.uimanager.PixelUtil; -import com.facebook.react.uimanager.SimpleViewManager; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.UIManagerHelper; -import com.facebook.react.uimanager.ViewManagerDelegate; -import com.facebook.react.uimanager.ViewProps; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.uimanager.events.EventDispatcher; -import java.util.Map; -import com.facebook.react.viewmanagers.RNCSliderManagerInterface; -import com.facebook.react.viewmanagers.RNCSliderManagerDelegate; -import com.facebook.react.module.annotations.ReactModule; -import com.facebook.yoga.YogaMeasureMode; -import com.facebook.yoga.YogaMeasureOutput; - -/** - * Manages instances of {@code ReactSlider}. - */ -@ReactModule(name = ReactSliderManagerImpl.REACT_CLASS) -public class ReactSliderManager extends SimpleViewManager implements RNCSliderManagerInterface { - - private final ViewManagerDelegate mDelegate; - - public ReactSliderManager() { - mDelegate = new RNCSliderManagerDelegate<>(this); - } - - @Nullable - @Override - protected ViewManagerDelegate getDelegate() { - return mDelegate; - } - - private static final SeekBar.OnSeekBarChangeListener ON_CHANGE_LISTENER = - new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) { - ReactSlider slider = (ReactSlider)seekbar; - - progress = slider.getValidProgressValue(progress); - seekbar.setProgress(progress); - - ReactContext reactContext = (ReactContext) seekbar.getContext(); - if (fromUser) { - int reactTag = seekbar.getId(); - UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) - .dispatchEvent(new ReactSliderEvent(reactTag, slider.toRealProgress(progress), true)); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekbar) { - ReactContext reactContext = (ReactContext) seekbar.getContext(); - int reactTag = seekbar.getId(); - ((ReactSlider)seekbar).isSliding(true); - UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) - .dispatchEvent(new ReactSlidingStartEvent( - reactTag, - ((ReactSlider)seekbar).toRealProgress(seekbar.getProgress()))); - } - - @Override - public void onStopTrackingTouch(SeekBar seekbar) { - ReactContext reactContext = (ReactContext) seekbar.getContext(); - ((ReactSlider)seekbar).isSliding(false); - int reactTag = seekbar.getId(); - - EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag); - - eventDispatcher.dispatchEvent( - new ReactSlidingCompleteEvent( - reactTag, - ((ReactSlider)seekbar).toRealProgress(seekbar.getProgress())) - ); - } - }; - - @Override - public String getName() { - return ReactSliderManagerImpl.REACT_CLASS; - } - - @Override - protected ReactSlider createViewInstance(ThemedReactContext context) { - return ReactSliderManagerImpl.createViewInstance(context); - } - - @Override - @ReactProp(name = "disabled", defaultBoolean = false) - public void setDisabled(ReactSlider view, boolean disabled) { - ReactSliderManagerImpl.setDisabled(view, disabled); - } - - @Override - @ReactProp(name = "value", defaultFloat = 0f) - public void setValue(ReactSlider view, float value) { - ReactSliderManagerImpl.setValue(view, value); - } - - @Override - @ReactProp(name = "minimumValue", defaultFloat = 0f) - public void setMinimumValue(ReactSlider view, double value) { - ReactSliderManagerImpl.setMinimumValue(view, value); - } - - @Override - @ReactProp(name = "maximumValue", defaultFloat = 0f) - public void setMaximumValue(ReactSlider view, double value) { - ReactSliderManagerImpl.setMaximumValue(view, value); - } - - @Override - @ReactProp(name = "step", defaultFloat = 0f) - public void setStep(ReactSlider view, double value) { - ReactSliderManagerImpl.setStep(view, value); - } - - @Override - @ReactProp(name = "thumbTintColor", customType = "Color") - public void setThumbTintColor(ReactSlider view, Integer color) { - ReactSliderManagerImpl.setThumbTintColor(view, color); - } - - @Override - @ReactProp(name = "thumbSize", defaultFloat = 0f) - public void setThumbSize(ReactSlider view, float size) { - ReactSliderManagerImpl.setThumbSize(view, size); - } - - @Override - @ReactProp(name = "minimumTrackTintColor", customType = "Color") - public void setMinimumTrackTintColor(ReactSlider view, Integer color) { - ReactSliderManagerImpl.setMinimumTrackTintColor(view, color); - } - - @Override - @ReactProp(name = "maximumTrackTintColor", customType = "Color") - public void setMaximumTrackTintColor(ReactSlider view, Integer color) { - ReactSliderManagerImpl.setMaximumTrackTintColor(view, color); - } - - @Override - @ReactProp(name = "inverted", defaultBoolean = false) - public void setInverted(ReactSlider view, boolean inverted) { - ReactSliderManagerImpl.setInverted(view, inverted); - } - - @Override - @ReactProp(name = "accessibilityUnits") - public void setAccessibilityUnits(ReactSlider view, String accessibilityUnits) { - ReactSliderManagerImpl.setAccessibilityUnits(view, accessibilityUnits); - } - - @Override - @ReactProp(name = "accessibilityIncrements") - public void setAccessibilityIncrements(ReactSlider view, ReadableArray accessibilityIncrements) { - ReactSliderManagerImpl.setAccessibilityIncrements(view, accessibilityIncrements); - } - - @ReactProp(name = "lowerLimit") - public void setLowerLimit(ReactSlider view, float value) { - ReactSliderManagerImpl.setLowerLimit(view, value); - } - - @ReactProp(name = "upperLimit") - public void setUpperLimit(ReactSlider view, float value) { - ReactSliderManagerImpl.setUpperLimit(view, value); - } - - @Override - @ReactProp(name = "thumbImage") - public void setThumbImage(ReactSlider view, @androidx.annotation.Nullable ReadableMap source) { - ReactSliderManagerImpl.setThumbImage(view, source); - } - - @Override - public void setTestID(ReactSlider view, @Nullable String value) { - super.setTestId(view, value); - } - - @Override - protected void addEventEmitters(final ThemedReactContext reactContext, final ReactSlider view) { - view.setOnSeekBarChangeListener(ON_CHANGE_LISTENER); - } - - // these props are not available on Android, however we must override their setters - @Override - public void setMinimumTrackImage(ReactSlider view, @Nullable ReadableMap readableMap) {} - - @Override - public void setMaximumTrackImage(ReactSlider view, @Nullable ReadableMap readableMap) {} - - @Override - public void setTrackImage(ReactSlider view, @Nullable ReadableMap value) {} - - @Override - public void setTapToSeek(ReactSlider view, boolean value) {} - - @Override - public void setVertical(ReactSlider view, boolean value) {} - - @Override - public long measure( - Context context, - ReadableMap localData, - ReadableMap props, - ReadableMap state, - float width, - YogaMeasureMode widthMode, - float height, - YogaMeasureMode heightMode, - @Nullable float[] attachmentsPositions) { - ReactSlider view = new ReactSlider(context, null); - int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - view.measure(measureSpec, measureSpec); - return YogaMeasureOutput.make( - PixelUtil.toDIPFromPixel(view.getMeasuredWidth()), - PixelUtil.toDIPFromPixel(view.getMeasuredHeight())); - } - - @Nullable - @Override - public Map getExportedCustomBubblingEventTypeConstants() { - return ReactSliderManagerImpl.getExportedCustomBubblingEventTypeConstants(); - } - - @Nullable - @Override - public Map getExportedCustomDirectEventTypeConstants() { - return ReactSliderManagerImpl.getExportedCustomDirectEventTypeConstants(); - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt new file mode 100644 index 00000000..b638845a --- /dev/null +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt @@ -0,0 +1,192 @@ +package com.reactnativecommunity.slider + +import android.content.Context +import android.view.View +import android.widget.SeekBar +import com.facebook.react.bridge.ReactContext +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.PixelUtil +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.ViewManagerDelegate +import com.facebook.react.uimanager.annotations.ReactProp +import com.facebook.react.viewmanagers.RNCSliderManagerDelegate +import com.facebook.react.viewmanagers.RNCSliderManagerInterface +import com.facebook.yoga.YogaMeasureMode +import com.facebook.yoga.YogaMeasureOutput + +/** Manages instances of [ReactSlider]. */ +@ReactModule(name = ReactSliderManagerImpl.REACT_CLASS) +class ReactSliderManager : SimpleViewManager(), RNCSliderManagerInterface { + + private val delegate: ViewManagerDelegate = RNCSliderManagerDelegate(this) + + override fun getDelegate(): ViewManagerDelegate? = delegate + + override fun getName(): String = ReactSliderManagerImpl.REACT_CLASS + + override fun createViewInstance(context: ThemedReactContext): ReactSlider = + ReactSliderManagerImpl.createViewInstance(context) + + @ReactProp(name = "disabled", defaultBoolean = false) + override fun setDisabled(view: ReactSlider, disabled: Boolean) { + ReactSliderManagerImpl.setDisabled(view, disabled) + } + + @ReactProp(name = "value", defaultFloat = 0f) + override fun setValue(view: ReactSlider, value: Float) { + ReactSliderManagerImpl.setValue(view, value.toDouble()) + } + + @ReactProp(name = "minimumValue", defaultFloat = 0f) + override fun setMinimumValue(view: ReactSlider, value: Double) { + ReactSliderManagerImpl.setMinimumValue(view, value) + } + + @ReactProp(name = "maximumValue", defaultFloat = 0f) + override fun setMaximumValue(view: ReactSlider, value: Double) { + ReactSliderManagerImpl.setMaximumValue(view, value) + } + + @ReactProp(name = "step", defaultFloat = 0f) + override fun setStep(view: ReactSlider, value: Double) { + ReactSliderManagerImpl.setStep(view, value) + } + + @ReactProp(name = "thumbTintColor", customType = "Color") + override fun setThumbTintColor(view: ReactSlider, color: Int?) { + ReactSliderManagerImpl.setThumbTintColor(view, color) + } + + @ReactProp(name = "thumbSize", defaultFloat = 0f) + override fun setThumbSize(view: ReactSlider, size: Float) { + ReactSliderManagerImpl.setThumbSize(view, size) + } + + @ReactProp(name = "minimumTrackTintColor", customType = "Color") + override fun setMinimumTrackTintColor(view: ReactSlider, color: Int?) { + ReactSliderManagerImpl.setMinimumTrackTintColor(view, color) + } + + @ReactProp(name = "maximumTrackTintColor", customType = "Color") + override fun setMaximumTrackTintColor(view: ReactSlider, color: Int?) { + ReactSliderManagerImpl.setMaximumTrackTintColor(view, color) + } + + @ReactProp(name = "inverted", defaultBoolean = false) + override fun setInverted(view: ReactSlider, inverted: Boolean) { + ReactSliderManagerImpl.setInverted(view, inverted) + } + + @ReactProp(name = "accessibilityUnits") + override fun setAccessibilityUnits(view: ReactSlider, accessibilityUnits: String?) { + ReactSliderManagerImpl.setAccessibilityUnits(view, accessibilityUnits) + } + + @ReactProp(name = "accessibilityIncrements") + override fun setAccessibilityIncrements(view: ReactSlider, accessibilityIncrements: ReadableArray?) { + ReactSliderManagerImpl.setAccessibilityIncrements(view, accessibilityIncrements) + } + + @ReactProp(name = "lowerLimit") + override fun setLowerLimit(view: ReactSlider, value: Float) { + ReactSliderManagerImpl.setLowerLimit(view, value.toDouble()) + } + + @ReactProp(name = "upperLimit") + override fun setUpperLimit(view: ReactSlider, value: Float) { + ReactSliderManagerImpl.setUpperLimit(view, value.toDouble()) + } + + @ReactProp(name = "thumbImage") + override fun setThumbImage(view: ReactSlider, source: ReadableMap?) { + ReactSliderManagerImpl.setThumbImage(view, source) + } + + override fun setTestID(view: ReactSlider, value: String?) { + super.setTestId(view, value) + } + + override fun addEventEmitters(reactContext: ThemedReactContext, view: ReactSlider) { + view.setOnSeekBarChangeListener(ON_CHANGE_LISTENER) + } + + // these props are not available on Android, however we must override their setters + override fun setMinimumTrackImage(view: ReactSlider, readableMap: ReadableMap?) {} + + override fun setMaximumTrackImage(view: ReactSlider, readableMap: ReadableMap?) {} + + override fun setTrackImage(view: ReactSlider, value: ReadableMap?) {} + + override fun setTapToSeek(view: ReactSlider, value: Boolean) {} + + override fun setVertical(view: ReactSlider, value: Boolean) {} + + override fun measure( + context: Context, + localData: ReadableMap?, + props: ReadableMap?, + state: ReadableMap?, + width: Float, + widthMode: YogaMeasureMode, + height: Float, + heightMode: YogaMeasureMode, + attachmentsPositions: FloatArray?, + ): Long { + val view = ReactSlider(context, null) + val measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + view.measure(measureSpec, measureSpec) + return YogaMeasureOutput.make( + PixelUtil.toDIPFromPixel(view.measuredWidth.toFloat()), + PixelUtil.toDIPFromPixel(view.measuredHeight.toFloat()), + ) + } + + override fun getExportedCustomBubblingEventTypeConstants(): Map? = + ReactSliderManagerImpl.getExportedCustomBubblingEventTypeConstants() + + override fun getExportedCustomDirectEventTypeConstants(): Map? = + ReactSliderManagerImpl.getExportedCustomDirectEventTypeConstants() + + companion object { + private val ON_CHANGE_LISTENER = + object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekbar: SeekBar, progress: Int, fromUser: Boolean) { + val slider = seekbar as ReactSlider + val p = slider.getValidProgressValue(progress) + seekbar.progress = p + + val reactContext = seekbar.context as ReactContext + if (fromUser) { + val reactTag = seekbar.id + UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) + ?.dispatchEvent(ReactSliderEvent(reactTag, slider.toRealProgress(p), true)) + } + } + + override fun onStartTrackingTouch(seekbar: SeekBar) { + val reactContext = seekbar.context as ReactContext + val reactTag = seekbar.id + (seekbar as ReactSlider).isSliding = true + UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) + ?.dispatchEvent( + ReactSlidingStartEvent(reactTag, seekbar.toRealProgress(seekbar.progress)), + ) + } + + override fun onStopTrackingTouch(seekbar: SeekBar) { + val reactContext = seekbar.context as ReactContext + (seekbar as ReactSlider).isSliding = false + val reactTag = seekbar.id + val eventDispatcher = + UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) + eventDispatcher?.dispatchEvent( + ReactSlidingCompleteEvent(reactTag, seekbar.toRealProgress(seekbar.progress)), + ) + } + } + } +} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.java b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.java deleted file mode 100644 index 4d76b983..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.reactnativecommunity.slider; - -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.os.Build; - -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.uimanager.ThemedReactContext; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nullable; - -public class ReactSliderManagerImpl { - - public static final String REACT_CLASS = "RNCSlider"; - - public static ReactSlider createViewInstance(ThemedReactContext context) { - ReactSlider slider = new ReactSlider(context, null); - - if (Build.VERSION.SDK_INT >= 21) { - /** - * The "splitTrack" parameter should have "false" value, - * otherwise the SeekBar progress line doesn't appear when it is rotated. - */ - slider.setSplitTrack(false); - } - - return slider; - } - - public static void setValue(ReactSlider view, double value) { - if (view.isSliding() == false) { - view.setValue(value); - if (view.isAccessibilityFocused() && Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) { - view.setupAccessibility((int)value); - } - } - } - - public static void setMinimumValue(ReactSlider view, double value) { - view.setMinValue(value); - } - - public static void setMaximumValue(ReactSlider view, double value) { - view.setMaxValue(value); - } - - public static void setLowerLimit(ReactSlider view, double value) { - view.setLowerLimit(value); - } - - public static void setUpperLimit(ReactSlider view, double value) { - view.setUpperLimit(value); - } - - public static void setStep(ReactSlider view, double value) { - view.setStep(value); - } - - public static void setDisabled(ReactSlider view, boolean disabled) { - view.setEnabled(!disabled); - } - - public static void setThumbTintColor(ReactSlider view, Integer color) { - view.setThumbTintColor(color); - } - - public static void setMinimumTrackTintColor(ReactSlider view, Integer color) { - LayerDrawable drawable = (LayerDrawable) view.getProgressDrawable().getCurrent(); - Drawable progress = drawable.findDrawableByLayerId(android.R.id.progress); - if (color == null) { - progress.clearColorFilter(); - } else { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - progress.setColorFilter(new PorterDuffColorFilter((int)color, PorterDuff.Mode.SRC_IN)); - } - else { - progress.setColorFilter(color, PorterDuff.Mode.SRC_IN); - } - } - } - - public static void setThumbImage(ReactSlider view, @Nullable ReadableMap source) { - String uri = null; - if (source != null) { - uri = source.getString("uri"); - } - view.setThumbImage(uri); - } - - public static void setThumbSize(ReactSlider view, float size) { - view.setThumbSize(size); - } - - public static void setMaximumTrackTintColor(ReactSlider view, Integer color) { - LayerDrawable drawable = (LayerDrawable) view.getProgressDrawable().getCurrent(); - Drawable background = drawable.findDrawableByLayerId(android.R.id.background); - if (color == null) { - background.clearColorFilter(); - } else { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - background.setColorFilter(new PorterDuffColorFilter((int)color, PorterDuff.Mode.SRC_IN)); - } - else { - background.setColorFilter(color, PorterDuff.Mode.SRC_IN); - } - } - } - - public static void setInverted(ReactSlider view, boolean inverted) { - if (inverted) view.setScaleX(-1f); - else view.setScaleX(1f); - } - - public static void setAccessibilityUnits(ReactSlider view, String accessibilityUnits) { - view.setAccessibilityUnits(accessibilityUnits); - } - - public static void setAccessibilityIncrements(ReactSlider view, ReadableArray accessibilityIncrements) { - List objectList = accessibilityIncrements.toArrayList(); - List stringList = new ArrayList<>(); - for(Object item: objectList) { - stringList.add((String)item); - } - view.setAccessibilityIncrements(stringList); - } - - public static Map getExportedCustomBubblingEventTypeConstants() { - return MapBuilder.of( - ReactSliderEvent.EVENT_NAME, MapBuilder.of("registrationName", ReactSliderEvent.EVENT_NAME) - ); - } - - public static Map getExportedCustomDirectEventTypeConstants() { - return MapBuilder.of( - ReactSlidingStartEvent.EVENT_NAME, MapBuilder.of("registrationName", ReactSlidingStartEvent.EVENT_NAME), - ReactSlidingCompleteEvent.EVENT_NAME, MapBuilder.of("registrationName", ReactSlidingCompleteEvent.EVENT_NAME) - ); - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt new file mode 100644 index 00000000..f1899b31 --- /dev/null +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt @@ -0,0 +1,156 @@ +package com.reactnativecommunity.slider + +import android.graphics.PorterDuff +import android.graphics.PorterDuffColorFilter +import android.graphics.drawable.LayerDrawable +import android.os.Build +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.common.MapBuilder +import com.facebook.react.uimanager.ThemedReactContext + +object ReactSliderManagerImpl { + const val REACT_CLASS = "RNCSlider" + + @JvmStatic + fun createViewInstance(context: ThemedReactContext): ReactSlider { + val slider = ReactSlider(context, null) + if (Build.VERSION.SDK_INT >= 21) { + /** + * The "splitTrack" parameter should have "false" value, otherwise the SeekBar progress line + * doesn't appear when it is rotated. + */ + slider.splitTrack = false + } + return slider + } + + @JvmStatic + fun setValue(view: ReactSlider, value: Double) { + if (!view.isSliding) { + view.setValue(value) + if (view.isAccessibilityFocused && Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) { + view.setupAccessibility(value.toInt()) + } + } + } + + @JvmStatic + fun setMinimumValue(view: ReactSlider, value: Double) { + view.setMinValue(value) + } + + @JvmStatic + fun setMaximumValue(view: ReactSlider, value: Double) { + view.setMaxValue(value) + } + + @JvmStatic + fun setLowerLimit(view: ReactSlider, value: Double) { + view.setLowerLimit(value) + } + + @JvmStatic + fun setUpperLimit(view: ReactSlider, value: Double) { + view.setUpperLimit(value) + } + + @JvmStatic + fun setStep(view: ReactSlider, value: Double) { + view.setStep(value) + } + + @JvmStatic + fun setDisabled(view: ReactSlider, disabled: Boolean) { + view.isEnabled = !disabled + } + + @JvmStatic + fun setThumbTintColor(view: ReactSlider, color: Int?) { + view.setThumbTintColor(color) + } + + @JvmStatic + fun setMinimumTrackTintColor(view: ReactSlider, color: Int?) { + val drawable = view.progressDrawable.current as LayerDrawable + val progress = drawable.findDrawableByLayerId(android.R.id.progress) + if (color == null) { + progress.clearColorFilter() + } else { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + progress.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN) + } else { + @Suppress("DEPRECATION") + progress.setColorFilter(color, PorterDuff.Mode.SRC_IN) + } + } + } + + @JvmStatic + fun setThumbImage(view: ReactSlider, source: ReadableMap?) { + val uri = source?.getString("uri") + view.setThumbImage(uri) + } + + @JvmStatic + fun setThumbSize(view: ReactSlider, size: Float) { + view.setThumbSize(size) + } + + @JvmStatic + fun setMaximumTrackTintColor(view: ReactSlider, color: Int?) { + val drawable = view.progressDrawable.current as LayerDrawable + val background = drawable.findDrawableByLayerId(android.R.id.background) + if (color == null) { + background.clearColorFilter() + } else { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + background.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN) + } else { + @Suppress("DEPRECATION") + background.setColorFilter(color, PorterDuff.Mode.SRC_IN) + } + } + } + + @JvmStatic + fun setInverted(view: ReactSlider, inverted: Boolean) { + view.scaleX = if (inverted) -1f else 1f + } + + @JvmStatic + fun setAccessibilityUnits(view: ReactSlider, accessibilityUnits: String?) { + view.setAccessibilityUnits(accessibilityUnits) + } + + @JvmStatic + fun setAccessibilityIncrements(view: ReactSlider, accessibilityIncrements: ReadableArray?) { + if (accessibilityIncrements == null) { + return + } + val objectList = accessibilityIncrements.toArrayList() + val stringList = ArrayList(objectList.size) + for (item in objectList) { + stringList.add(item as String) + } + view.setAccessibilityIncrements(stringList) + } + + @JvmStatic + fun getExportedCustomBubblingEventTypeConstants(): Map { + return MapBuilder.of( + ReactSliderEvent.EVENT_NAME, + MapBuilder.of("registrationName", ReactSliderEvent.EVENT_NAME), + ) + } + + @JvmStatic + fun getExportedCustomDirectEventTypeConstants(): Map { + return MapBuilder.of( + ReactSlidingStartEvent.EVENT_NAME, + MapBuilder.of("registrationName", ReactSlidingStartEvent.EVENT_NAME), + ReactSlidingCompleteEvent.EVENT_NAME, + MapBuilder.of("registrationName", ReactSlidingCompleteEvent.EVENT_NAME), + ) + } +} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.java b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.java deleted file mode 100644 index 38a3f1f7..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.reactnativecommunity.slider; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.uimanager.ViewManager; -import com.facebook.react.bridge.JavaScriptModule; - -public class ReactSliderPackage implements ReactPackage { - @Override - public List createNativeModules(ReactApplicationContext reactContext) { - return Collections.emptyList(); - } - - // Deprecated from RN 0.47 - public List> createJSModules() { - return Collections.emptyList(); - } - - @Override - @SuppressWarnings("rawtypes") - public List createViewManagers(ReactApplicationContext reactContext) { - return Arrays.asList(new ReactSliderManager()); - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.kt new file mode 100644 index 00000000..60aa6324 --- /dev/null +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.kt @@ -0,0 +1,22 @@ +package com.reactnativecommunity.slider + +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.JavaScriptModule +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.uimanager.ViewManager + +class ReactSliderPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return emptyList() + } + + // Deprecated from RN 0.47 + fun createJSModules(): List> { + return emptyList() + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return listOf(ReactSliderManager()) + } +} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.java b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.java deleted file mode 100644 index b6e2a0e3..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.reactnativecommunity.slider; - -import androidx.annotation.Nullable; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.uimanager.events.Event; - -/** - * Event emitted when the user finishes dragging the slider. - */ -public class ReactSlidingCompleteEvent extends Event { - - public static final String EVENT_NAME = "onRNCSliderSlidingComplete"; - - private final double mValue; - - public ReactSlidingCompleteEvent(int viewId, double value) { - super(viewId); - mValue = value; - } - - public double getValue() { - return mValue; - } - - @Override - public String getEventName() { - return EVENT_NAME; - } - - @Override - public short getCoalescingKey() { - return 0; - } - - @Override - public boolean canCoalesce() { - return false; - } - - @Nullable - @Override - protected WritableMap getEventData() { - return serializeEventData(); - } - - private WritableMap serializeEventData() { - WritableMap eventData = Arguments.createMap(); - eventData.putInt("target", getViewTag()); - eventData.putDouble("value", getValue()); - return eventData; - } - -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.kt new file mode 100644 index 00000000..a54441b3 --- /dev/null +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.kt @@ -0,0 +1,31 @@ +package com.reactnativecommunity.slider + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +/** Event emitted when the user finishes dragging the slider. */ +class ReactSlidingCompleteEvent( + viewId: Int, + private val value: Double, +) : Event(viewId) { + + override fun getEventName(): String = EVENT_NAME + + override fun getCoalescingKey(): Short = 0 + + override fun canCoalesce(): Boolean = false + + override fun getEventData(): WritableMap? = serializeEventData() + + private fun serializeEventData(): WritableMap { + val eventData = Arguments.createMap() + eventData.putInt("target", viewTag) + eventData.putDouble("value", value) + return eventData + } + + companion object { + const val EVENT_NAME = "onRNCSliderSlidingComplete" + } +} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.java b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.java deleted file mode 100644 index fe07d8b2..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.reactnativecommunity.slider; - -import androidx.annotation.Nullable; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.uimanager.events.Event; - -/** - * Event emitted when the user starts dragging the slider. - */ - -public class ReactSlidingStartEvent extends Event { - public static final String EVENT_NAME = "onRNCSliderSlidingStart"; - - private final double mValue; - - public ReactSlidingStartEvent(int viewId, double value) { - super(viewId); - mValue = value; - } - - public double getValue() { - return mValue; - } - - @Override - public String getEventName() { - return EVENT_NAME; - } - - @Override - public short getCoalescingKey() { - return 0; - } - - @Override - public boolean canCoalesce() { - return false; - } - - @Nullable - @Override - protected WritableMap getEventData() { - return serializeEventData(); - } - - private WritableMap serializeEventData() { - WritableMap eventData = Arguments.createMap(); - eventData.putInt("target", getViewTag()); - eventData.putDouble("value", getValue()); - return eventData; - } - -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.kt new file mode 100644 index 00000000..7cc1fe65 --- /dev/null +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.kt @@ -0,0 +1,31 @@ +package com.reactnativecommunity.slider + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +/** Event emitted when the user starts dragging the slider. */ +class ReactSlidingStartEvent( + viewId: Int, + private val value: Double, +) : Event(viewId) { + + override fun getEventName(): String = EVENT_NAME + + override fun getCoalescingKey(): Short = 0 + + override fun canCoalesce(): Boolean = false + + override fun getEventData(): WritableMap? = serializeEventData() + + private fun serializeEventData(): WritableMap { + val eventData = Arguments.createMap() + eventData.putInt("target", viewTag) + eventData.putDouble("value", value) + return eventData + } + + companion object { + const val EVENT_NAME = "onRNCSliderSlidingStart" + } +} From 7cfd1687ab7a4ca37a5979298bda6b411cba3722 Mon Sep 17 00:00:00 2001 From: BartoszKlonowski Date: Fri, 17 Apr 2026 12:49:28 +0200 Subject: [PATCH 2/7] Introduce Jetpack Compose for Android implementation of Slider --- package/android/build.gradle | 15 + .../slider/ReactSlider.kt | 522 +++++++++++------- .../slider/ReactSliderEventListener.kt | 9 + .../slider/ReactSliderManager.kt | 63 +-- .../slider/ReactSliderManagerImpl.kt | 45 +- 5 files changed, 380 insertions(+), 274 deletions(-) create mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEventListener.kt diff --git a/package/android/build.gradle b/package/android/build.gradle index 97fdd133..c391ca61 100644 --- a/package/android/build.gradle +++ b/package/android/build.gradle @@ -13,6 +13,10 @@ buildscript { } } +plugins { + id 'org.jetbrains.kotlin.plugin.compose' version '2.0.21' +} + apply plugin: 'com.android.library' apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'com.facebook.react' @@ -35,6 +39,11 @@ android { namespace "com.reactnativecommunity.slider" buildFeatures { buildConfig true + compose true + } + } else { + buildFeatures { + compose true } } @@ -62,5 +71,11 @@ dependencies { //noinspection GradleDynamicVersion api 'com.facebook.react:react-native:+' implementation 'org.jetbrains.kotlin:kotlin-stdlib' + implementation platform('androidx.compose:compose-bom:2025.02.00') + implementation 'androidx.compose.ui:ui' + implementation 'androidx.compose.material3:material3' + implementation 'androidx.compose.ui:ui-tooling-preview' + debugImplementation 'androidx.compose.ui:ui-tooling' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0' } diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt index 0a8a2149..8bf735a1 100644 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt @@ -1,102 +1,156 @@ +@file:OptIn(androidx.compose.material3.ExperimentalMaterial3Api::class) + package com.reactnativecommunity.slider import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.PorterDuff -import android.graphics.drawable.BitmapDrawable import android.os.Build import android.util.AttributeSet import android.util.Log import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityManager -import androidx.appcompat.widget.AppCompatSeekBar +import androidx.compose.foundation.Image +import androidx.compose.foundation.interaction.DragInteraction +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Slider +import androidx.compose.material3.SliderDefaults +import androidx.compose.material3.SliderState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.Recomposer +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.AbstractComposeView +import androidx.compose.ui.platform.AndroidUiDispatcher +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp import com.facebook.react.modules.i18nmanager.I18nUtil import java.net.URL import java.util.Timer import java.util.TimerTask -import java.util.concurrent.Executors +import kotlin.math.ceil +import kotlin.math.max +import kotlin.math.min +import kotlin.math.round +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext /** * Slider that behaves more like the iOS one, for consistency. * * On iOS, the value is 0..1. Android SeekBar only supports integer values. For consistency, we - * pretend in JS that the value is 0..1 but set the SeekBar value to 0..100. + * pretend in JS that the value is 0..1 but use discrete steps internally. * * Note that the slider is _not_ a controlled component (setValue isn't called during dragging). + * + * UI is implemented with Jetpack Compose (Material 3 [Slider]) inside an [AbstractComposeView]. */ class ReactSlider @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, -) : AppCompatSeekBar(context, attrs) { +) : AbstractComposeView(context, attrs) { - /** - * If step is 0 (unset) we default to this total number of steps. Don't use 100 which leads to - * rounding errors (0.200000000001). - */ private val defaultTotalSteps = 128 - /** - * We want custom min..max range. Android only supports 0..max range so we implement this - * ourselves. - */ private var minValue = 0.0 private var maxValue = 0.0 - - /** - * Value sent from JS (setState). Doesn't get updated during drag (slider is not a controlled - * component). - */ private var value = 0.0 - - internal var isSliding = false - - /** If zero it's determined automatically. */ private var step = 0.0 private var stepCalculated = 0.0 private var accessibilityUnits: String? = null private var accessibilityIncrements: List? = null - /** Real limit value based on min and max values. This comes from props */ private var realLowerLimit = Long.MIN_VALUE.toDouble() - - /** Lower limit based on the SeekBar progress 0..total steps */ internal var lowerLimit = 0 private set - - /** Real limit value based on min and max values. This comes from props */ private var realUpperLimit = Long.MAX_VALUE.toDouble() - - /** Upper limit based on the SeekBar progress 0..total steps */ internal var upperLimit = 0 private set - /** Thumb size in pixels (0 = default) */ private var thumbSizePx = 0 - - /** Original thumb drawable URI */ private var thumbImageUri: String? = null - - /** Cached thumb tint color */ private var thumbTintColor: Int? = null + private var minimumTrackTintColor: Int? = null + private var maximumTrackTintColor: Int? = null + private var inverted = false + + private val propsVersion = mutableIntStateOf(0) + private val isUserDragging = mutableStateOf(false) + + internal val isSliding: Boolean + get() = isUserDragging.value + + private var eventListener: ReactSliderEventListener? = null + + /** Latest value shown on the slider; used for sliding-start events and accessibility. */ + private var latestDisplayedValue = 0.0 + + /** + * React Native can measure and update this view before it is attached to a window. The default + * Compose path looks up a [androidx.compose.ui.platform.WindowRecomposer] from the view root, which + * throws if the view has no window. A dedicated [Recomposer] avoids that lookup. + * Use [AndroidUiDispatcher.Main] so [Recomposer.runRecomposeAndApplyChanges] has a + * [androidx.compose.runtime.MonotonicFrameClock]. + */ + private val recomposer = Recomposer(AndroidUiDispatcher.Main) + private val recomposerScope = CoroutineScope(SupervisorJob() + AndroidUiDispatcher.Main) + private var recomposerRunJob: Job? = null init { - val sharedI18nUtilInstance = I18nUtil.getInstance() - layoutDirection = - if (sharedI18nUtilInstance.isRTL(context)) LAYOUT_DIRECTION_RTL else LAYOUT_DIRECTION_LTR - disableStateListAnimatorIfNeeded() - } - - private fun disableStateListAnimatorIfNeeded() { - // We disable the state list animator for Android 6 and 7; this is a hack to prevent T37452851 - // and https://github.com/facebook/react-native/issues/9979 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && - Build.VERSION.SDK_INT < Build.VERSION_CODES.O - ) { - stateListAnimator = null - } + setParentCompositionContext(recomposer) + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow) + startRecomposerIfNeeded() + } + + private fun startRecomposerIfNeeded() { + if (recomposerRunJob?.isActive == true) return + recomposerRunJob = + recomposerScope.launch { + recomposer.runRecomposeAndApplyChanges() + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + startRecomposerIfNeeded() + } + + override fun onDetachedFromWindow() { + recomposerRunJob?.cancel() + recomposerRunJob = null + super.onDetachedFromWindow() + } + + internal fun setEventListener(listener: ReactSliderEventListener?) { + eventListener = listener + } + + private fun bumpProps() { + propsVersion.intValue++ } internal fun setMaxValue(max: Double) { @@ -119,7 +173,9 @@ class ReactSlider @JvmOverloads constructor( internal fun setValue(value: Double) { this.value = value - updateValue() + if (!isSliding) { + bumpProps() + } } internal fun setStep(step: Double) { @@ -130,11 +186,13 @@ class ReactSlider @JvmOverloads constructor( internal fun setLowerLimit(value: Double) { realLowerLimit = value updateLowerLimit() + bumpProps() } internal fun setUpperLimit(value: Double) { realUpperLimit = value updateUpperLimit() + bumpProps() } internal fun setAccessibilityUnits(accessibilityUnits: String?) { @@ -145,83 +203,63 @@ class ReactSlider @JvmOverloads constructor( this.accessibilityIncrements = accessibilityIncrements } - override fun onPopulateAccessibilityEvent(event: AccessibilityEvent) { - super.onPopulateAccessibilityEvent(event) + internal fun setThumbImageUri(uri: String?) { + thumbImageUri = uri + bumpProps() + } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (event.eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED || - (event.eventType == AccessibilityEvent.TYPE_VIEW_SELECTED && isAccessibilityFocused) - ) { - setupAccessibility(value.toInt()) - } - } + internal fun setThumbSize(sizeDp: Float) { + val density = resources.displayMetrics.density + thumbSizePx = if (sizeDp > 0) round(sizeDp * density).toInt() else 0 + bumpProps() } - override fun announceForAccessibility(text: CharSequence?) { - val ctx = context - val manager = ctx.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager + internal fun setThumbTintColor(color: Int?) { + thumbTintColor = color + bumpProps() + } - if (manager.isEnabled && text != null) { - val e = AccessibilityEvent.obtain() - e.eventType = AccessibilityEvent.TYPE_ANNOUNCEMENT - e.className = javaClass.name - e.packageName = ctx.packageName - e.text.add(text) + internal fun setMinimumTrackTintColor(color: Int?) { + minimumTrackTintColor = color + bumpProps() + } - val task = object : TimerTask() { - override fun run() { - manager.sendAccessibilityEvent(e) - } - } + internal fun setMaximumTrackTintColor(color: Int?) { + maximumTrackTintColor = color + bumpProps() + } - Timer().schedule(task, 1000) - } + internal fun applyDisabledProp(disabled: Boolean) { + isEnabled = !disabled + bumpProps() } - fun setupAccessibility(index: Int) { - val units = accessibilityUnits - val increments = accessibilityIncrements - if (units != null && increments != null && increments.size - 1 == maxValue.toInt()) { - val sliderValue = increments[index] - val stringLength = units.length - var spokenUnits = units - if (sliderValue.toInt() == 1) { - spokenUnits = spokenUnits.substring(0, stringLength - 1) - } - announceForAccessibility(String.format("%s %s", sliderValue, spokenUnits)) - } + internal fun setInverted(inverted: Boolean) { + this.inverted = inverted + bumpProps() } - /** - * Convert SeekBar's native progress value (e.g. 0..100) to a value passed to JS (e.g. -1.0..2.5). - */ fun toRealProgress(seekBarProgress: Int): Double { - return if (seekBarProgress == max) { + return if (seekBarProgress == totalSteps) { maxValue } else { seekBarProgress * getStepValue() + minValue } } - /** Update underlying native SeekBar's values. */ private fun updateAll() { if (step == 0.0) { stepCalculated = (maxValue - minValue) / defaultTotalSteps.toDouble() } - max = totalSteps - keyProgressIncrement = 1 updateLowerLimit() updateUpperLimit() - updateValue() + bumpProps() } - /** - * Update limit based on props limit, max and min Fallback to upper limit if invalid configuration - * provided - */ private fun updateLowerLimit() { + if (maxValue <= minValue) return val limit = maxOf(realLowerLimit, minValue) - val lower = kotlin.math.round((limit - minValue) / (maxValue - minValue) * totalSteps).toInt() + val lower = round((limit - minValue) / (maxValue - minValue) * totalSteps).toInt() if (lower > upperLimit) { Log.d("Invalid configuration", "upperLimit < lowerLimit; lowerLimit not set") } else { @@ -229,10 +267,10 @@ class ReactSlider @JvmOverloads constructor( } } - /** Update limit based on props limit, max and min */ private fun updateUpperLimit() { + if (maxValue <= minValue) return val limit = minOf(realUpperLimit, maxValue) - val upper = kotlin.math.round((limit - minValue) / (maxValue - minValue) * totalSteps).toInt() + val upper = round((limit - minValue) / (maxValue - minValue) * totalSteps).toInt() if (lowerLimit > upper) { Log.d("Invalid configuration", "upperLimit < lowerLimit; upperLimit not set") } else { @@ -240,125 +278,221 @@ class ReactSlider @JvmOverloads constructor( } } - /** Update value only (optimization in case only value is set). */ - private fun updateValue() { - progress = - kotlin.math.round((value - minValue) / (maxValue - minValue) * totalSteps).toInt() - } - private val totalSteps: Int - get() = kotlin.math.ceil((maxValue - minValue) / getStepValue()).toInt() + get() { + if (maxValue <= minValue) return 0 + return ceil((maxValue - minValue) / getStepValue()).toInt() + } private fun getStepValue(): Double = if (step > 0) step else stepCalculated - private fun getBitmapDrawable(uri: String): BitmapDrawable? { - val executorService = Executors.newSingleThreadExecutor() - val future = executorService.submit { - try { - val bitmap: Bitmap? = - if (uri.startsWith("http://") || uri.startsWith("https://") || - uri.startsWith("file://") || uri.startsWith("asset://") || uri.startsWith("data:") - ) { - BitmapFactory.decodeStream(URL(uri).openStream()) - } else { - val drawableId = - resources.getIdentifier(uri, "drawable", context.packageName) - BitmapFactory.decodeResource(resources, drawableId) + private fun progressForReal(real: Double): Int { + if (maxValue <= minValue || totalSteps <= 0) return 0 + return round((real - minValue) / (maxValue - minValue) * totalSteps).toInt() + } + + private fun clampedRealToFloat(real: Double): Float { + val p = getValidProgressValue(progressForReal(real)) + return toRealProgress(p).toFloat() + } + + override fun onPopulateAccessibilityEvent(event: AccessibilityEvent) { + super.onPopulateAccessibilityEvent(event) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (event.eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED || + (event.eventType == AccessibilityEvent.TYPE_VIEW_SELECTED && isAccessibilityFocused) + ) { + setupAccessibility(latestDisplayedValue.toInt()) + } + } + } + + override fun announceForAccessibility(text: CharSequence?) { + val ctx = context + val manager = ctx.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager + if (manager.isEnabled && text != null) { + val e = AccessibilityEvent.obtain() + e.eventType = AccessibilityEvent.TYPE_ANNOUNCEMENT + e.className = javaClass.name + e.packageName = ctx.packageName + e.text.add(text) + val task = + object : TimerTask() { + override fun run() { + manager.sendAccessibilityEvent(e) } - BitmapDrawable(resources, bitmap) - } catch (e: Exception) { - e.printStackTrace() - null + } + Timer().schedule(task, 1000) + } + } + + fun setupAccessibility(index: Int) { + val units = accessibilityUnits + val increments = accessibilityIncrements + if (units != null && increments != null && increments.size - 1 == maxValue.toInt()) { + val sliderValue = increments[index] + val stringLength = units.length + var spokenUnits = units + if (sliderValue.toInt() == 1) { + spokenUnits = spokenUnits.substring(0, stringLength - 1) } + announceForAccessibility(String.format("%s %s", sliderValue, spokenUnits)) } + } + + private fun loadBitmap(uri: String): Bitmap? { return try { - future.get() + if (uri.startsWith("http://") || uri.startsWith("https://") || + uri.startsWith("file://") || uri.startsWith("asset://") || uri.startsWith("data:") + ) { + BitmapFactory.decodeStream(URL(uri).openStream()) + } else { + val drawableId = resources.getIdentifier(uri, "drawable", context.packageName) + BitmapFactory.decodeResource(resources, drawableId) + } } catch (e: Exception) { e.printStackTrace() null } } - fun setThumbImage(uri: String?) { - thumbImageUri = uri - refreshThumb() - } + @Composable + override fun Content() { + val _propsTick = propsVersion.intValue + @Suppress("DEPRECATION") + val isRtl = I18nUtil.getInstance().isRTL(context) + val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr - fun setThumbSize(size: Float) { - val density = resources.displayMetrics.density - thumbSizePx = if (size > 0) kotlin.math.round(size * density).toInt() else 0 - refreshThumb() - } + val minV = minValue.toFloat() + val maxV = maxValue.toFloat() + val rangeEmptyOrInvalid = maxV <= minV + val valueRange = minV..maxV + val materialSteps = if (rangeEmptyOrInvalid) 0 else maxOf(totalSteps - 1, 0) - fun setThumbTintColor(color: Int?) { - thumbTintColor = color - if (thumbImageUri != null || thumbSizePx > 0) { - refreshThumb() - } else { - applyThumbTintColorFilter() - } - } + val interactionSource = remember { MutableInteractionSource() } - private fun applyThumbTintColorFilter() { - val thumbDrawable = getThumb() ?: return - val tint = thumbTintColor - if (tint != null) { - thumbDrawable.setColorFilter(tint, PorterDuff.Mode.SRC_IN) - } else { - thumbDrawable.clearColorFilter() + var localValue by remember(minV, maxV, _propsTick) { + mutableFloatStateOf(clampedRealToFloat(value)) } - } - private fun refreshThumb() { - val uri = thumbImageUri - if (uri != null) { - val drawable = getBitmapDrawable(uri) - if (drawable != null) { - if (thumbSizePx > 0) { - val originalBitmap = drawable.bitmap - val scaledBitmap = - Bitmap.createScaledBitmap(originalBitmap, thumbSizePx, thumbSizePx, true) - setThumb(BitmapDrawable(resources, scaledBitmap)) - } else { - setThumb(drawable) - } - applyThumbTintColorFilter() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - splitTrack = false - } - return + val dragging = isUserDragging.value + LaunchedEffect(value, _propsTick, dragging) { + if (!dragging) { + localValue = clampedRealToFloat(value) } } - if (thumbSizePx > 0) { - val bitmap = Bitmap.createBitmap(thumbSizePx, thumbSizePx, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) + val valueAtGesture = remember { mutableFloatStateOf(0f) } - val fillColor = - thumbTintColor - ?: (thumbTintList?.defaultColor ?: 0xFFFFFFFF.toInt()) + LaunchedEffect(interactionSource) { + interactionSource.interactions.collect { interaction -> + when (interaction) { + is DragInteraction.Start -> { + isUserDragging.value = true + eventListener?.onSlidingStart(valueAtGesture.floatValue.toDouble()) + } + is DragInteraction.Stop, is DragInteraction.Cancel -> { + isUserDragging.value = false + } + } + } + } - val fillPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - style = Paint.Style.FILL - color = fillColor + val thumbUri = thumbImageUri + var thumbBitmap by remember(thumbUri, _propsTick) { mutableStateOf(null) } + LaunchedEffect(thumbUri, _propsTick) { + if (thumbUri == null) { + thumbBitmap = null + return@LaunchedEffect } - val radius = thumbSizePx / 2f - canvas.drawCircle(radius, radius, radius, fillPaint) + val bmp = withContext(Dispatchers.IO) { loadBitmap(thumbUri) } + thumbBitmap = bmp + } - val strokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - style = Paint.Style.STROKE - strokeWidth = 1f - color = 0x1A000000 + val density = LocalDensity.current + val thumbDp = + if (thumbSizePx > 0) { + with(density) { thumbSizePx.toDp() } + } else { + 0.dp } - canvas.drawCircle(radius, radius, radius - 0.5f, strokePaint) + val thumbSizeDp = if (thumbSizePx > 0) DpSize(thumbDp, thumbDp) else DpSize(20.dp, 20.dp) + + val baseColors = SliderDefaults.colors() + val sliderColors = + SliderDefaults.colors( + thumbColor = thumbTintColor?.let { Color(it) } ?: baseColors.thumbColor, + activeTrackColor = minimumTrackTintColor?.let { Color(it) } ?: baseColors.activeTrackColor, + inactiveTrackColor = maximumTrackTintColor?.let { Color(it) } ?: baseColors.inactiveTrackColor, + ) + + SideEffect { + valueAtGesture.floatValue = localValue + latestDisplayedValue = localValue.toDouble() + } - setThumb(BitmapDrawable(resources, bitmap)) - applyThumbTintColorFilter() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - splitTrack = false + androidx.compose.runtime.CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) { + Box( + modifier = + Modifier + .fillMaxWidth() + .height(48.dp) + .then(if (inverted) Modifier.scale(scaleX = -1f, scaleY = 1f) else Modifier), + contentAlignment = Alignment.Center, + ) { + if (!rangeEmptyOrInvalid) { + Slider( + value = localValue, + onValueChange = { newVal -> + val clamped = clampedRealToFloat(newVal.toDouble()) + if (clamped != localValue) { + localValue = clamped + } + eventListener?.onSliderValueChange(clamped.toDouble(), true) + }, + modifier = Modifier.fillMaxWidth(), + enabled = isEnabled, + onValueChangeFinished = { + eventListener?.onSlidingComplete(localValue.toDouble()) + isUserDragging.value = false + }, + colors = sliderColors, + interactionSource = interactionSource, + steps = materialSteps, + thumb = { _: SliderState -> + val bmp = thumbBitmap + if (bmp != null) { + val sizeForImage = + if (thumbSizePx > 0) Modifier.size(thumbDp) else Modifier.size(ThumbImageFallbackDp) + Image( + bitmap = bmp.asImageBitmap(), + contentDescription = null, + modifier = sizeForImage, + contentScale = ContentScale.Fit, + ) + } else if (thumbSizePx > 0) { + SliderDefaults.Thumb( + interactionSource = interactionSource, + colors = sliderColors, + enabled = isEnabled, + thumbSize = thumbSizeDp, + ) + } else { + SliderDefaults.Thumb( + interactionSource = interactionSource, + colors = sliderColors, + enabled = isEnabled, + ) + } + }, + valueRange = valueRange, + ) + } } - } else { - applyThumbTintColorFilter() } } + + companion object { + private val ThumbImageFallbackDp = 24.dp + } } diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEventListener.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEventListener.kt new file mode 100644 index 00000000..a9d49ec9 --- /dev/null +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEventListener.kt @@ -0,0 +1,9 @@ +package com.reactnativecommunity.slider + +internal interface ReactSliderEventListener { + fun onSliderValueChange(value: Double, fromUser: Boolean) + + fun onSlidingStart(value: Double) + + fun onSlidingComplete(value: Double) +} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt index b638845a..d355a64b 100644 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt @@ -2,8 +2,6 @@ package com.reactnativecommunity.slider import android.content.Context import android.view.View -import android.widget.SeekBar -import com.facebook.react.bridge.ReactContext import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.module.annotations.ReactModule @@ -111,7 +109,28 @@ class ReactSliderManager : SimpleViewManager(), RNCSliderManagerInt } override fun addEventEmitters(reactContext: ThemedReactContext, view: ReactSlider) { - view.setOnSeekBarChangeListener(ON_CHANGE_LISTENER) + view.setEventListener( + object : ReactSliderEventListener { + override fun onSliderValueChange(value: Double, fromUser: Boolean) { + if (!fromUser) return + val reactTag = view.id + UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) + ?.dispatchEvent(ReactSliderEvent(reactTag, value, true)) + } + + override fun onSlidingStart(value: Double) { + val reactTag = view.id + UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) + ?.dispatchEvent(ReactSlidingStartEvent(reactTag, value)) + } + + override fun onSlidingComplete(value: Double) { + val reactTag = view.id + UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) + ?.dispatchEvent(ReactSlidingCompleteEvent(reactTag, value)) + } + }, + ) } // these props are not available on Android, however we must override their setters @@ -151,42 +170,4 @@ class ReactSliderManager : SimpleViewManager(), RNCSliderManagerInt override fun getExportedCustomDirectEventTypeConstants(): Map? = ReactSliderManagerImpl.getExportedCustomDirectEventTypeConstants() - companion object { - private val ON_CHANGE_LISTENER = - object : SeekBar.OnSeekBarChangeListener { - override fun onProgressChanged(seekbar: SeekBar, progress: Int, fromUser: Boolean) { - val slider = seekbar as ReactSlider - val p = slider.getValidProgressValue(progress) - seekbar.progress = p - - val reactContext = seekbar.context as ReactContext - if (fromUser) { - val reactTag = seekbar.id - UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) - ?.dispatchEvent(ReactSliderEvent(reactTag, slider.toRealProgress(p), true)) - } - } - - override fun onStartTrackingTouch(seekbar: SeekBar) { - val reactContext = seekbar.context as ReactContext - val reactTag = seekbar.id - (seekbar as ReactSlider).isSliding = true - UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) - ?.dispatchEvent( - ReactSlidingStartEvent(reactTag, seekbar.toRealProgress(seekbar.progress)), - ) - } - - override fun onStopTrackingTouch(seekbar: SeekBar) { - val reactContext = seekbar.context as ReactContext - (seekbar as ReactSlider).isSliding = false - val reactTag = seekbar.id - val eventDispatcher = - UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) - eventDispatcher?.dispatchEvent( - ReactSlidingCompleteEvent(reactTag, seekbar.toRealProgress(seekbar.progress)), - ) - } - } - } } diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt index f1899b31..9d8aac6f 100644 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt +++ b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt @@ -1,8 +1,5 @@ package com.reactnativecommunity.slider -import android.graphics.PorterDuff -import android.graphics.PorterDuffColorFilter -import android.graphics.drawable.LayerDrawable import android.os.Build import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap @@ -14,15 +11,7 @@ object ReactSliderManagerImpl { @JvmStatic fun createViewInstance(context: ThemedReactContext): ReactSlider { - val slider = ReactSlider(context, null) - if (Build.VERSION.SDK_INT >= 21) { - /** - * The "splitTrack" parameter should have "false" value, otherwise the SeekBar progress line - * doesn't appear when it is rotated. - */ - slider.splitTrack = false - } - return slider + return ReactSlider(context, null) } @JvmStatic @@ -62,7 +51,7 @@ object ReactSliderManagerImpl { @JvmStatic fun setDisabled(view: ReactSlider, disabled: Boolean) { - view.isEnabled = !disabled + view.applyDisabledProp(disabled) } @JvmStatic @@ -72,24 +61,13 @@ object ReactSliderManagerImpl { @JvmStatic fun setMinimumTrackTintColor(view: ReactSlider, color: Int?) { - val drawable = view.progressDrawable.current as LayerDrawable - val progress = drawable.findDrawableByLayerId(android.R.id.progress) - if (color == null) { - progress.clearColorFilter() - } else { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - progress.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN) - } else { - @Suppress("DEPRECATION") - progress.setColorFilter(color, PorterDuff.Mode.SRC_IN) - } - } + view.setMinimumTrackTintColor(color) } @JvmStatic fun setThumbImage(view: ReactSlider, source: ReadableMap?) { val uri = source?.getString("uri") - view.setThumbImage(uri) + view.setThumbImageUri(uri) } @JvmStatic @@ -99,23 +77,12 @@ object ReactSliderManagerImpl { @JvmStatic fun setMaximumTrackTintColor(view: ReactSlider, color: Int?) { - val drawable = view.progressDrawable.current as LayerDrawable - val background = drawable.findDrawableByLayerId(android.R.id.background) - if (color == null) { - background.clearColorFilter() - } else { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - background.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN) - } else { - @Suppress("DEPRECATION") - background.setColorFilter(color, PorterDuff.Mode.SRC_IN) - } - } + view.setMaximumTrackTintColor(color) } @JvmStatic fun setInverted(view: ReactSlider, inverted: Boolean) { - view.scaleX = if (inverted) -1f else 1f + view.setInverted(inverted) } @JvmStatic From fe49110cfc8d255f2ed2202e90acab2d7f35b2ac Mon Sep 17 00:00:00 2001 From: BartoszKlonowski Date: Fri, 24 Apr 2026 14:43:24 +0200 Subject: [PATCH 3/7] Update Example app to the latest react-native version --- example/.bundle/config | 2 + example/.eslintrc.js | 14 +- example/.gitignore | 75 + example/.prettierrc.js | 5 + example/.prettierrc.json | 7 - example/.watchmanconfig | 1 + example/App.tsx | 70 + example/Gemfile | 3 +- example/Gemfile.lock | 117 - example/README.md | 97 + example/__tests__/App.test.tsx | 13 + example/android/app/build.gradle | 23 +- .../android/app/src/debug/AndroidManifest.xml | 9 - .../android/app/src/main/AndroidManifest.xml | 4 +- .../main/java/com/example/MainApplication.kt | 41 +- .../res/drawable/rn_edit_text_material.xml | 3 +- example/android/build.gradle | 8 +- example/android/gradle.properties | 9 +- .../gradle/gradle-daemon-jvm.properties | 12 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 43705 -> 46175 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/gradlew | 7 +- example/android/gradlew.bat | 8 +- example/index.js | 9 + example/index.ts | 9 - example/ios/Podfile | 4 +- example/ios/Podfile.lock | 2037 ----------------- example/ios/example.xcodeproj/project.pbxproj | 21 +- .../contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - example/ios/example/AppDelegate.swift | 18 +- example/ios/example/Info.plist | 9 +- example/jest.config.js | 2 +- example/metro.config.js | 2 +- example/package.json | 42 +- example/src/App.tsx | 119 - example/src/Examples.tsx | 764 ------- example/src/Props.tsx | 199 -- example/src/resources/ck-icon.png | Bin 2809 -> 0 bytes example/src/resources/empty.png | Bin 1723 -> 0 bytes example/src/resources/slider-left.png | Bin 1395 -> 0 bytes example/src/resources/slider-right.png | Bin 1398 -> 0 bytes example/src/resources/slider.png | Bin 1562 -> 0 bytes example/src/resources/twitter-small.png | Bin 4052 -> 0 bytes example/src/resources/twitter.png | Bin 21556 -> 0 bytes example/src/resources/uie_thumb_big.png | Bin 6752 -> 0 bytes example/tsconfig.json | 7 +- example/windows/.gitignore | 92 - example/windows/ExperimentalFeatures.props | 32 - example/windows/NuGet.Config | 14 - example/windows/example.sln | 171 -- example/windows/example/.gitignore | 1 - example/windows/example/App.cpp | 93 - example/windows/example/App.h | 21 - example/windows/example/App.idl | 3 - example/windows/example/App.xaml | 10 - .../Assets/LockScreenLogo.scale-200.png | Bin 1430 -> 0 bytes .../example/Assets/SplashScreen.scale-200.png | Bin 7700 -> 0 bytes .../Assets/Square150x150Logo.scale-200.png | Bin 2937 -> 0 bytes .../Assets/Square44x44Logo.scale-200.png | Bin 1647 -> 0 bytes ...x44Logo.targetsize-24_altform-unplated.png | Bin 1255 -> 0 bytes example/windows/example/Assets/StoreLogo.png | Bin 1451 -> 0 bytes .../Assets/Wide310x150Logo.scale-200.png | Bin 3204 -> 0 bytes .../example/AutolinkedNativeModules.g.cpp | 18 - .../example/AutolinkedNativeModules.g.h | 10 - .../example/AutolinkedNativeModules.g.props | 6 - .../example/AutolinkedNativeModules.g.targets | 10 - example/windows/example/MainPage.cpp | 20 - example/windows/example/MainPage.h | 19 - example/windows/example/MainPage.idl | 10 - example/windows/example/MainPage.xaml | 16 - example/windows/example/Package.appxmanifest | 50 - example/windows/example/PropertySheet.props | 16 - .../windows/example/ReactPackageProvider.cpp | 15 - .../windows/example/ReactPackageProvider.h | 13 - example/windows/example/example.vcxproj | 173 -- .../windows/example/example.vcxproj.filters | 62 - example/windows/example/packages.lock.json | 128 -- example/windows/example/pch.cpp | 1 - example/windows/example/pch.h | 24 - 80 files changed, 385 insertions(+), 4433 deletions(-) create mode 100644 example/.bundle/config create mode 100644 example/.gitignore create mode 100644 example/.prettierrc.js delete mode 100644 example/.prettierrc.json create mode 100644 example/.watchmanconfig create mode 100644 example/App.tsx delete mode 100644 example/Gemfile.lock create mode 100644 example/README.md create mode 100644 example/__tests__/App.test.tsx delete mode 100644 example/android/app/src/debug/AndroidManifest.xml create mode 100644 example/android/gradle/gradle-daemon-jvm.properties create mode 100644 example/index.js delete mode 100644 example/index.ts delete mode 100644 example/ios/Podfile.lock delete mode 100644 example/ios/example.xcworkspace/contents.xcworkspacedata delete mode 100644 example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/src/App.tsx delete mode 100644 example/src/Examples.tsx delete mode 100644 example/src/Props.tsx delete mode 100644 example/src/resources/ck-icon.png delete mode 100644 example/src/resources/empty.png delete mode 100644 example/src/resources/slider-left.png delete mode 100644 example/src/resources/slider-right.png delete mode 100644 example/src/resources/slider.png delete mode 100644 example/src/resources/twitter-small.png delete mode 100644 example/src/resources/twitter.png delete mode 100644 example/src/resources/uie_thumb_big.png delete mode 100644 example/windows/.gitignore delete mode 100644 example/windows/ExperimentalFeatures.props delete mode 100644 example/windows/NuGet.Config delete mode 100644 example/windows/example.sln delete mode 100644 example/windows/example/.gitignore delete mode 100644 example/windows/example/App.cpp delete mode 100644 example/windows/example/App.h delete mode 100644 example/windows/example/App.idl delete mode 100644 example/windows/example/App.xaml delete mode 100644 example/windows/example/Assets/LockScreenLogo.scale-200.png delete mode 100644 example/windows/example/Assets/SplashScreen.scale-200.png delete mode 100644 example/windows/example/Assets/Square150x150Logo.scale-200.png delete mode 100644 example/windows/example/Assets/Square44x44Logo.scale-200.png delete mode 100644 example/windows/example/Assets/Square44x44Logo.targetsize-24_altform-unplated.png delete mode 100644 example/windows/example/Assets/StoreLogo.png delete mode 100644 example/windows/example/Assets/Wide310x150Logo.scale-200.png delete mode 100644 example/windows/example/AutolinkedNativeModules.g.cpp delete mode 100644 example/windows/example/AutolinkedNativeModules.g.h delete mode 100644 example/windows/example/AutolinkedNativeModules.g.props delete mode 100644 example/windows/example/AutolinkedNativeModules.g.targets delete mode 100644 example/windows/example/MainPage.cpp delete mode 100644 example/windows/example/MainPage.h delete mode 100644 example/windows/example/MainPage.idl delete mode 100644 example/windows/example/MainPage.xaml delete mode 100644 example/windows/example/Package.appxmanifest delete mode 100644 example/windows/example/PropertySheet.props delete mode 100644 example/windows/example/ReactPackageProvider.cpp delete mode 100644 example/windows/example/ReactPackageProvider.h delete mode 100644 example/windows/example/example.vcxproj delete mode 100644 example/windows/example/example.vcxproj.filters delete mode 100644 example/windows/example/packages.lock.json delete mode 100644 example/windows/example/pch.cpp delete mode 100644 example/windows/example/pch.h diff --git a/example/.bundle/config b/example/.bundle/config new file mode 100644 index 00000000..848943bb --- /dev/null +++ b/example/.bundle/config @@ -0,0 +1,2 @@ +BUNDLE_PATH: "vendor/bundle" +BUNDLE_FORCE_RUBY_PLATFORM: 1 diff --git a/example/.eslintrc.js b/example/.eslintrc.js index dcf0be08..187894b6 100644 --- a/example/.eslintrc.js +++ b/example/.eslintrc.js @@ -1,16 +1,4 @@ module.exports = { root: true, - extends: '@react-native-community', - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - '@typescript-eslint/no-shadow': ['error'], - 'no-shadow': 'off', - 'no-undef': 'off', - }, - }, - ], + extends: '@react-native', }; diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 00000000..de999559 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,75 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +**/.xcode.env.local + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml +*.hprof +.cxx/ +*.keystore +!debug.keystore +.kotlin/ + +# node.js +# +node_modules/ +npm-debug.log +yarn-error.log + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ + +**/fastlane/report.xml +**/fastlane/Preview.html +**/fastlane/screenshots +**/fastlane/test_output + +# Bundle artifact +*.jsbundle + +# Ruby / CocoaPods +**/Pods/ +/vendor/bundle/ + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* + +# testing +/coverage + +# Yarn +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions diff --git a/example/.prettierrc.js b/example/.prettierrc.js new file mode 100644 index 00000000..06860c8d --- /dev/null +++ b/example/.prettierrc.js @@ -0,0 +1,5 @@ +module.exports = { + arrowParens: 'avoid', + singleQuote: true, + trailingComma: 'all', +}; diff --git a/example/.prettierrc.json b/example/.prettierrc.json deleted file mode 100644 index fe440a6a..00000000 --- a/example/.prettierrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "arrowParens": "avoid", - "bracketSameLine": true, - "bracketSpacing": false, - "singleQuote": true, - "trailingComma": "all" -} diff --git a/example/.watchmanconfig b/example/.watchmanconfig new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/example/.watchmanconfig @@ -0,0 +1 @@ +{} diff --git a/example/App.tsx b/example/App.tsx new file mode 100644 index 00000000..a001944c --- /dev/null +++ b/example/App.tsx @@ -0,0 +1,70 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + * + * @format + */ + +import Slider from '@react-native-community/slider'; +import { NewAppScreen } from '@react-native/new-app-screen'; +import { useState } from 'react'; +import { SafeAreaView, StatusBar, StyleSheet, Text, useColorScheme, View } from 'react-native'; +import { + SafeAreaProvider, + useSafeAreaInsets, +} from 'react-native-safe-area-context'; + +function App() { + const isDarkMode = useColorScheme() === 'dark'; + + return ( + + + + + ); +} + +function AppContent() { + const [sliderValue, setSliderValue] = useState(0); + const safeAreaInsets = useSafeAreaInsets(); + + console.log("BLA"); + return ( + + { + console.log('value', value); + }} + /> + {sliderValue} + + ); +} + +const styles = StyleSheet.create({ + container: { + padding: 10, + gap: 10, + justifyContent: 'center', + alignItems: 'center', + flex: 1, + }, + stepMarker: { + backgroundColor: 'red', + width: 10, + height: 10, + }, + slider: { + color: 'red', + width: '70%', + height: 40, + }, +}); + +export default App; diff --git a/example/Gemfile b/example/Gemfile index 60770b18..51515233 100644 --- a/example/Gemfile +++ b/example/Gemfile @@ -8,9 +8,10 @@ gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' gem 'xcodeproj', '< 1.26.0' gem 'concurrent-ruby', '< 1.3.4' - + # Ruby 3.4.0 has removed some libraries from the standard library. gem 'bigdecimal' gem 'logger' gem 'benchmark' gem 'mutex_m' +gem 'nkf' diff --git a/example/Gemfile.lock b/example/Gemfile.lock deleted file mode 100644 index ebdbf97b..00000000 --- a/example/Gemfile.lock +++ /dev/null @@ -1,117 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - CFPropertyList (3.0.7) - base64 - nkf - rexml - activesupport (7.1.3.4) - base64 - bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) - algoliasearch (1.27.5) - httpclient (~> 2.8, >= 2.8.3) - json (>= 1.5.1) - atomos (0.1.3) - base64 (0.2.0) - bigdecimal (3.1.1) - claide (1.1.0) - cocoapods (1.15.2) - addressable (~> 2.8) - claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.15.2) - cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 2.1, < 3.0) - cocoapods-plugins (>= 1.0.0, < 2.0) - cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.6.0, < 2.0) - cocoapods-try (>= 1.1.0, < 2.0) - colored2 (~> 3.1) - escape (~> 0.0.4) - fourflusher (>= 2.3.0, < 3.0) - gh_inspector (~> 1.0) - molinillo (~> 0.8.0) - nap (~> 1.0) - ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.15.2) - activesupport (>= 5.0, < 8) - addressable (~> 2.8) - algoliasearch (~> 1.0) - concurrent-ruby (~> 1.1) - fuzzy_match (~> 2.0.4) - nap (~> 1.0) - netrc (~> 0.11) - public_suffix (~> 4.0) - typhoeus (~> 1.0) - cocoapods-deintegrate (1.0.5) - cocoapods-downloader (2.1) - cocoapods-plugins (1.0.0) - nap - cocoapods-search (1.0.1) - cocoapods-trunk (1.6.0) - nap (>= 0.8, < 2.0) - netrc (~> 0.11) - cocoapods-try (1.2.0) - colored2 (3.1.2) - concurrent-ruby (1.3.4) - connection_pool (2.4.1) - drb (2.1.0) - ruby2_keywords - escape (0.0.4) - ethon (0.16.0) - ffi (>= 1.15.0) - ffi (1.17.0-arm64-darwin) - ffi (1.17.0-x86_64-linux-gnu) - fourflusher (2.3.1) - fuzzy_match (2.0.4) - gh_inspector (1.1.3) - httpclient (2.8.3) - i18n (1.14.5) - concurrent-ruby (~> 1.0) - json (2.7.2) - minitest (5.25.1) - molinillo (0.8.0) - mutex_m (0.1.1) - nanaimo (0.3.0) - nap (1.1.0) - netrc (0.11.0) - nkf (0.2.0) - public_suffix (4.0.7) - rexml (3.3.9) - ruby-macho (2.5.1) - ruby2_keywords (0.0.5) - typhoeus (1.4.1) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - xcodeproj (1.25.0) - CFPropertyList (>= 2.3.3, < 4.0) - atomos (~> 0.1.3) - claide (>= 1.0.2, < 2.0) - colored2 (~> 3.1) - nanaimo (~> 0.3.0) - rexml (>= 3.3.2, < 4.0) - -PLATFORMS - arm64-darwin - x86_64-linux - -DEPENDENCIES - activesupport (>= 6.1.7.5, != 7.1.0) - cocoapods (>= 1.13, != 1.15.1, != 1.15.0) - xcodeproj (< 1.26.0) - -RUBY VERSION - ruby 3.1.2p20 - -BUNDLED WITH - 2.5.17 diff --git a/example/README.md b/example/README.md new file mode 100644 index 00000000..3e2c3f85 --- /dev/null +++ b/example/README.md @@ -0,0 +1,97 @@ +This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). + +# Getting Started + +> **Note**: Make sure you have completed the [Set Up Your Environment](https://reactnative.dev/docs/set-up-your-environment) guide before proceeding. + +## Step 1: Start Metro + +First, you will need to run **Metro**, the JavaScript build tool for React Native. + +To start the Metro dev server, run the following command from the root of your React Native project: + +```sh +# Using npm +npm start + +# OR using Yarn +yarn start +``` + +## Step 2: Build and run your app + +With Metro running, open a new terminal window/pane from the root of your React Native project, and use one of the following commands to build and run your Android or iOS app: + +### Android + +```sh +# Using npm +npm run android + +# OR using Yarn +yarn android +``` + +### iOS + +For iOS, remember to install CocoaPods dependencies (this only needs to be run on first clone or after updating native deps). + +The first time you create a new project, run the Ruby bundler to install CocoaPods itself: + +```sh +bundle install +``` + +Then, and every time you update your native dependencies, run: + +```sh +bundle exec pod install +``` + +For more information, please visit [CocoaPods Getting Started guide](https://guides.cocoapods.org/using/getting-started.html). + +```sh +# Using npm +npm run ios + +# OR using Yarn +yarn ios +``` + +If everything is set up correctly, you should see your new app running in the Android Emulator, iOS Simulator, or your connected device. + +This is one way to run your app — you can also build it directly from Android Studio or Xcode. + +## Step 3: Modify your app + +Now that you have successfully run the app, let's make changes! + +Open `App.tsx` in your text editor of choice and make some changes. When you save, your app will automatically update and reflect these changes — this is powered by [Fast Refresh](https://reactnative.dev/docs/fast-refresh). + +When you want to forcefully reload, for example to reset the state of your app, you can perform a full reload: + +- **Android**: Press the R key twice or select **"Reload"** from the **Dev Menu**, accessed via Ctrl + M (Windows/Linux) or Cmd ⌘ + M (macOS). +- **iOS**: Press R in iOS Simulator. + +## Congratulations! :tada: + +You've successfully run and modified your React Native App. :partying_face: + +### Now what? + +- If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). +- If you're curious to learn more about React Native, check out the [docs](https://reactnative.dev/docs/getting-started). + +# Troubleshooting + +If you're having issues getting the above steps to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. + +# Learn More + +To learn more about React Native, take a look at the following resources: + +- [React Native Website](https://reactnative.dev) - learn more about React Native. +- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. +- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. +- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. +- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. diff --git a/example/__tests__/App.test.tsx b/example/__tests__/App.test.tsx new file mode 100644 index 00000000..e532f701 --- /dev/null +++ b/example/__tests__/App.test.tsx @@ -0,0 +1,13 @@ +/** + * @format + */ + +import React from 'react'; +import ReactTestRenderer from 'react-test-renderer'; +import App from '../App'; + +test('renders correctly', async () => { + await ReactTestRenderer.act(() => { + ReactTestRenderer.create(); + }); +}); diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 004ae422..b5663008 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -8,20 +8,20 @@ apply plugin: "com.facebook.react" */ react { /* Folders */ - // The root of your project, i.e. where "package.json" lives. Default is '..' - // root = file("../") - // The folder where the react-native NPM package is. Default is ../node_modules/react-native - // reactNativeDir = file("../node_modules/react-native") - // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen - // codegenDir = file("../node_modules/@react-native/codegen") - // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js - // cliFile = file("../node_modules/react-native/cli.js") + // The root of your project, i.e. where "package.json" lives. Default is '../..' + // root = file("../../") + // The folder where the react-native NPM package is. Default is ../../node_modules/react-native + // reactNativeDir = file("../../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen + // codegenDir = file("../../node_modules/@react-native/codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js + // cliFile = file("../../node_modules/react-native/cli.js") /* Variants */ // The list of variants to that are debuggable. For those we're going to - // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // skip the bundling of the JS bundle and the assets. Default is "debug", "debugOptimized". // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. - // debuggableVariants = ["liteDebug", "prodDebug"] + // debuggableVariants = ["liteDebug", "liteDebugOptimized", "prodDebug", "prodDebugOptimized"] /* Bundling */ // A list containing the node command and its flags. Default is just 'node'. @@ -49,8 +49,9 @@ react { // // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" // hermesFlags = ["-O", "-output-source-map"] + /* Autolinking */ - autolinkLibrariesWithApp() + autolinkLibrariesWithApp() } /** diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index eb98c01a..00000000 --- a/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 4122f36a..fb78f397 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -8,7 +8,9 @@ android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme" + android:usesCleartextTraffic="${usesCleartextTraffic}" + android:supportsRtl="true"> = - PackageList(this).packages.apply { - // Packages that cannot be autolinked yet can be added manually here, for example: - // add(MyReactNativePackage()) - } - - override fun getJSMainModuleName(): String = "index" - - override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG - - override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED - override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED - } - - override val reactHost: ReactHost - get() = getDefaultReactHost(this.applicationContext, reactNativeHost) + override val reactHost: ReactHost by lazy { + getDefaultReactHost( + context = applicationContext, + packageList = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + }, + ) + } override fun onCreate() { super.onCreate() - SoLoader.init(this, OpenSourceMergedSoMapping) - if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { - // If you opted-in for the New Architecture, we load the native entry point for this app. - load() - } + loadReactNative(this) } } diff --git a/example/android/app/src/main/res/drawable/rn_edit_text_material.xml b/example/android/app/src/main/res/drawable/rn_edit_text_material.xml index 73b37e4d..5c25e728 100644 --- a/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +++ b/example/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -17,7 +17,8 @@ android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material" android:insetRight="@dimen/abc_edit_text_inset_horizontal_material" android:insetTop="@dimen/abc_edit_text_inset_top_material" - android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"> + android:insetBottom="@dimen/abc_edit_text_inset_bottom_material" + > - - - - true - - - false - - true - - - - diff --git a/example/windows/NuGet.Config b/example/windows/NuGet.Config deleted file mode 100644 index c7612b0b..00000000 --- a/example/windows/NuGet.Config +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/example/windows/example.sln b/example/windows/example.sln deleted file mode 100644 index 02ad0d4a..00000000 --- a/example/windows/example.sln +++ /dev/null @@ -1,171 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.3.32929.385 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example\example.vcxproj", "{B18DBFA9-1510-4CC9-801D-E3DA5168024E}" - ProjectSection(ProjectDependencies) = postProject - {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\node_modules\react-native-windows\fmt\fmt.vcxproj", "{14B93DC8-FD93-4A6D-81CB-8BC96644501C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" - ProjectSection(ProjectDependencies) = postProject - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\node_modules\react-native-windows\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Shared", "..\node_modules\react-native-windows\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\node_modules\react-native-windows\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Include", "..\node_modules\react-native-windows\include\Include.vcxitems", "{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SliderWindows", "..\node_modules\@react-native-community\slider\windows\SliderWindows\SliderWindows.vcxproj", "{685A83AE-36BC-4E9D-BDC6-417EBF168463}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM64 = Debug|ARM64 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|ARM64 = Release|ARM64 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Debug|ARM64.Build.0 = Debug|ARM64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Debug|ARM64.Deploy.0 = Debug|ARM64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Debug|x64.ActiveCfg = Debug|x64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Debug|x64.Build.0 = Debug|x64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Debug|x64.Deploy.0 = Debug|x64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Debug|x86.ActiveCfg = Debug|Win32 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Debug|x86.Build.0 = Debug|Win32 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Debug|x86.Deploy.0 = Debug|Win32 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Release|ARM64.ActiveCfg = Release|ARM64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Release|ARM64.Build.0 = Release|ARM64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Release|ARM64.Deploy.0 = Release|ARM64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Release|x64.ActiveCfg = Release|x64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Release|x64.Build.0 = Release|x64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Release|x64.Deploy.0 = Release|x64 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Release|x86.ActiveCfg = Release|Win32 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Release|x86.Build.0 = Release|Win32 - {B18DBFA9-1510-4CC9-801D-E3DA5168024E}.Release|x86.Deploy.0 = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.Build.0 = Debug|ARM64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.ActiveCfg = Debug|x64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.Build.0 = Debug|x64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.ActiveCfg = Debug|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Build.0 = Debug|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Deploy.0 = Debug|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.ActiveCfg = Release|ARM64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.Build.0 = Release|ARM64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.ActiveCfg = Release|x64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.Build.0 = Release|x64 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.ActiveCfg = Release|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Build.0 = Release|Win32 - {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Deploy.0 = Release|Win32 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32 - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32 - {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32 - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Debug|ARM64.Build.0 = Debug|ARM64 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Debug|x64.ActiveCfg = Debug|x64 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Debug|x64.Build.0 = Debug|x64 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Debug|x86.ActiveCfg = Debug|Win32 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Debug|x86.Build.0 = Debug|Win32 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Release|ARM64.ActiveCfg = Release|ARM64 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Release|ARM64.Build.0 = Release|ARM64 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Release|x64.ActiveCfg = Release|x64 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Release|x64.Build.0 = Release|x64 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Release|x86.ActiveCfg = Release|Win32 - {685A83AE-36BC-4E9D-BDC6-417EBF168463}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {14B93DC8-FD93-4A6D-81CB-8BC96644501C} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - {EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A} - EndGlobalSection - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{685a83ae-36bc-4e9d-bdc6-417ebf168463}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\include\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 - EndGlobalSection -EndGlobal diff --git a/example/windows/example/.gitignore b/example/windows/example/.gitignore deleted file mode 100644 index cd828d9f..00000000 --- a/example/windows/example/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/Bundle diff --git a/example/windows/example/App.cpp b/example/windows/example/App.cpp deleted file mode 100644 index e8efa1fd..00000000 --- a/example/windows/example/App.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "pch.h" - -#include "App.h" - -#include "AutolinkedNativeModules.g.h" -#include "ReactPackageProvider.h" - -using namespace winrt; -using namespace xaml; -using namespace xaml::Controls; -using namespace xaml::Navigation; - -using namespace Windows::ApplicationModel; -namespace winrt::example::implementation -{ -///

-/// Initializes the singleton application object. This is the first line of -/// authored code executed, and as such is the logical equivalent of main() or -/// WinMain(). -/// -App::App() noexcept -{ -#if BUNDLE - JavaScriptBundleFile(L"index.windows"); - InstanceSettings().UseFastRefresh(false); -#else - JavaScriptBundleFile(L"index"); - InstanceSettings().UseFastRefresh(true); -#endif - -#if _DEBUG - InstanceSettings().UseDirectDebugger(true); - InstanceSettings().UseDeveloperSupport(true); -#else - InstanceSettings().UseDirectDebugger(false); - InstanceSettings().UseDeveloperSupport(false); -#endif - - RegisterAutolinkedNativeModulePackages(PackageProviders()); // Includes any autolinked modules - - PackageProviders().Append(make()); // Includes all modules in this project - - InitializeComponent(); -} - -/// -/// Invoked when the application is launched normally by the end user. Other entry points -/// will be used such as when the application is launched to open a specific file. -/// -/// Details about the launch request and process. -void App::OnLaunched(activation::LaunchActivatedEventArgs const& e) -{ - super::OnLaunched(e); - - Frame rootFrame = Window::Current().Content().as(); - rootFrame.Navigate(xaml_typename(), box_value(e.Arguments())); -} - -/// -/// Invoked when the application is activated by some means other than normal launching. -/// -void App::OnActivated(Activation::IActivatedEventArgs const &e) { - auto preActivationContent = Window::Current().Content(); - super::OnActivated(e); - if (!preActivationContent && Window::Current()) { - Frame rootFrame = Window::Current().Content().as(); - rootFrame.Navigate(xaml_typename(), nullptr); - } -} - -/// -/// Invoked when application execution is being suspended. Application state is saved -/// without knowing whether the application will be terminated or resumed with the contents -/// of memory still intact. -/// -/// The source of the suspend request. -/// Details about the suspend request. -void App::OnSuspending([[maybe_unused]] IInspectable const& sender, [[maybe_unused]] SuspendingEventArgs const& e) -{ - // Save application state and stop any background activity -} - -/// -/// Invoked when Navigation to a certain page fails -/// -/// The Frame which failed navigation -/// Details about the navigation failure -void App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e) -{ - throw hresult_error(E_FAIL, hstring(L"Failed to load Page ") + e.SourcePageType().Name); -} - -} // namespace winrt::example::implementation diff --git a/example/windows/example/App.h b/example/windows/example/App.h deleted file mode 100644 index eb2d5a58..00000000 --- a/example/windows/example/App.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "App.xaml.g.h" - -#include - -namespace activation = winrt::Windows::ApplicationModel::Activation; - -namespace winrt::example::implementation -{ - struct App : AppT - { - App() noexcept; - void OnLaunched(activation::LaunchActivatedEventArgs const&); - void OnActivated(Windows::ApplicationModel::Activation::IActivatedEventArgs const &e); - void OnSuspending(IInspectable const&, Windows::ApplicationModel::SuspendingEventArgs const&); - void OnNavigationFailed(IInspectable const&, xaml::Navigation::NavigationFailedEventArgs const&); - private: - using super = AppT; - }; -} // namespace winrt::example::implementation diff --git a/example/windows/example/App.idl b/example/windows/example/App.idl deleted file mode 100644 index ad6a721d..00000000 --- a/example/windows/example/App.idl +++ /dev/null @@ -1,3 +0,0 @@ -namespace example -{ -} diff --git a/example/windows/example/App.xaml b/example/windows/example/App.xaml deleted file mode 100644 index bda9267c..00000000 --- a/example/windows/example/App.xaml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/example/windows/example/Assets/LockScreenLogo.scale-200.png b/example/windows/example/Assets/LockScreenLogo.scale-200.png deleted file mode 100644 index 735f57adb5dfc01886d137b4e493d7e97cf13af3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1430 zcmaJ>TTC2P7~aKltDttVHYH6u8Io4i*}3fO&d$gd*bA_<3j~&e7%8(eXJLfhS!M@! zKrliY>>6yT4+Kr95$!DoD(Qn-5TP|{V_KS`k~E6(LGS@#`v$hQo&^^BKsw3HIsZBT z_y6C2n`lK@apunKojRQ^(_P}Mgewt$(^BBKCTZ;*xa?J3wQ7~@S0lUvbcLeq1Bg4o zH-bvQi|wt~L7q$~a-gDFP!{&TQfc3fX*6=uHv* zT&1&U(-)L%Xp^djI2?~eBF2cxC@YOP$+9d?P&h?lPy-9M2UT9fg5jKm1t$m#iWE{M zIf%q9@;fyT?0UP>tcw-bLkz;s2LlKl2qeP0w zECS7Ate+Awk|KQ+DOk;fl}Xsy4o^CY=pwq%QAAKKl628_yNPsK>?A>%D8fQG6IgdJ ztnxttBz#NI_a@fk7SU`WtrpsfZsNs9^0(2a z@C3#YO3>k~w7?2hipBf{#b6`}Xw1hlG$yi?;1dDs7k~xDAw@jiI*+tc;t2Lflg&bM)0!Y;0_@=w%`LW^8DsYpS#-bLOklX9r?Ei}TScw|4DbpW%+7 zFgAI)f51s}{y-eWb|vrU-Ya!GuYKP)J7z#*V_k^Xo>4!1Yqj*m)x&0L^tg3GJbVAJ zJ-Pl$R=NAabouV=^z_t;^K*0AvFs!vYU>_<|I^#c?>>CR<(T?=%{;U=aI*SbZADLH z&(f2wz_Y0??Tf|g;?|1Znw6}6U43Q#qNRwv1vp9uFn1)V#*4p&%$mP9x&15^OaBiDS(XppT|z^>;B{PLVEbS3IFYV yGvCsSX*m diff --git a/example/windows/example/Assets/SplashScreen.scale-200.png b/example/windows/example/Assets/SplashScreen.scale-200.png deleted file mode 100644 index 023e7f1feda78d5100569825acedfd213a0d84e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7700 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 diff --git a/example/windows/example/Assets/Square150x150Logo.scale-200.png b/example/windows/example/Assets/Square150x150Logo.scale-200.png deleted file mode 100644 index af49fec1a5484db1d52a7f9b5ec90a27c7030186..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2937 zcma)84OCO-8BSud5)jwMLRVKgX(S?$n?Ld|vrsm<$CF7)&zTbyy1FE5bU`Q17MRv`9ue$;R(@8kR;#vJ*IM0>cJIAOte!d7oRgdH zd%ySjdB6L9=gX^A6)VzH7p2l@v~3zJAMw|DFy#^)F@@F*`mqUn=Il>l)8_+ab;nOW{%+iPx z+s{Eu|&pIs)Z7{La9~?xKfyl z#43?gjEL15d4WbOZo#SiP%>DB^+BcnJ=7dHEe;r#G=tuw|ka z%q@}##Uh7;tc%L_64m(kHtw74ty%BJMb)_1)#S0j`)F8_1jF7vScpsnH=0V19bO8y zR`0SjIdCUo&=>JwMQF8KHA<{ODHTiQh}0^@5QRmCA?gOH6_H3K^-_sNB^RrdNuK-R zOO*vOrKCVvDwgUck`kF(E7j{I#iiN;b*ZdCt4m@HPA`EuEqGGf4%!K<;(=I=&Vyrw z%TwcWtxa}8mCZ%Cyf&ActJ6_$ox5z6-D!0-dvnRx6t7y3d+h6QYpKWO;8OdnvERo7 zuEf>ih5`wqY)~o@OeVt-wM?Q!>QzdGRj!bz6fzYrfw$hZfAKzr2-M+D+R>}~oT574c;_3zquHcElqKIsryILt3g8n3jcMb+j?i?-L3FpZJ z2WRVBRdDPc+G5aaYg#5hpE+6nQ|(VSoxT3|biF;BUq#==-27Xi=gihDPYP$7?=9cP zYKE$jeQ|3~_L0VG-(F~2ZPyD0=k{J4Q~h(t__{-mz_w8{JDY9{`1ouzz!Vr5!ECdE z6U~O1k8c}24V7~zzXWTV-Pe4)y}wQJS&q%H5`Fo_f_JvIU489aCX$;P`u#!I-=^4ijC2{&9!O&h>mi?9oYD=GC#%)6{GzN6nQYw+Fal50!#x^asjBBR50i`+mho*ttoqV)ubM2KD9S~k7+FR4>{29?6 z{!l6kDdyTN0YJ9LgkPWeXm|gyi@zM3?0@{&pXT12w|78&W-q!RRF)&iLCEZVH<|fR zN0fr2^t8H(>L?>K#>^+jWROLral(Qy-xoBq1U7A&DV||wClb)Otd9?(gZ|8znMF}D zf<1haWz^s0qgecz;RFGt0C-B4g`jNGHsFU+;{<%t65v^sjk^h$lmWn#B0#_)9ij&d z-~lc`A)YYExi^7sBuPM^Y|wA2g*5?`K?#7tzELQYNxGo$UB$4J8RJp1k(8Jj+~hMT zlN~>M@KTTh^--8y3PK_NZ@AC!{PT=CziBzGd+wTJ^@icH!Bd}%)g8V)%K?|c&WTUk zy}qv1C%(fjRoZ4ozC3{O%@5?)XzH35zHns$pgU*Q?fj4v?fp1Qbm+j;3l;9jam9Da zXVcKjPlQ73x78QPu|Ffm6x?`~e3oD=gl=4kYK?={kD5j~QCXU)`HSdduNNENzA*2$ zOm3PzF!lN5e*06-f1Uot67wY#{o-S1!KZ7E=!~7ynnk9_iJR#kFoNbAOT#^2Gd17F zMmvU6>lndZQGd|ax9kUoXXO+$N?|j@6qpsF&_j7YXvwo_C{JpmLw5&#e6k>atv%es z5)7r*Wvv_JkUpT}M!_o!nVlEk1Zbl=a*2hQ*<|%*K1Glj^FcF`6kTzGQ3lz~2tCc@ z&x|tj;aH&1&9HwcJBcT`;{?a+pnej;M1HO(6Z{#J!cZA04hnFl;NXA+&`=7bjW_^o zfC40u3LMG?NdPtwGl>Tq6u}*QG)}-y;)lu-_>ee3kibW(69n0$0Zy!}9rQz%*v1iO zT9_H>99yIrSPYVy6^);rR}7Yo=J_T@hi+qhTZXnVWyf;JDYm5#eYLTxr*?kiNn!+Y zQ+LUkBafNJ#rH#C(?d5^;gw9o#%daEI{mA*LHPIHPU`#|H$hD zwm>0&+kahQ)E#%~k>&5@&#Vg82H?s%71=)(soi@174pi9--2{w{1$}Sz4zGn3Du&x bht0Iza^2ykEt4(epJ78uh5nDlX8(TxzDYwP diff --git a/example/windows/example/Assets/Square44x44Logo.scale-200.png b/example/windows/example/Assets/Square44x44Logo.scale-200.png deleted file mode 100644 index ce342a2ec8a61291ba76c54604aea7e9d20af11b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1647 zcmaJ?eM}Q)7(e+G1Q(|`V9JhTI2>MkceK4;p;PR&$Pi?ejk3YQ_3o`S&|W_dsOZ8# zWPTt69g`t$ab`0cj-Y0yiBSOqmd)tG7G(}M5aP0_%&9TijB#&)I{zSE^4@#z^FF`l z`8{8`o%wlL(UI|y2!cdsuVamHH~H86F!*-15em4)NqUpCQM5?aoC_eCf@lV4wvF2a zjDQn1JBL69f&@2M3rvzJcfE!eZ8FZUBlFlC5RD)it33{mF9#B82AiyQE%w)`vlwa> zv{<1sm&kSKK$&%2jSFn7$t&P%%6Ue>R=EAnG8N7fqynWG8L3p!4801a;8{+nliO(qd(jNJ_?+9W3#hLIDLoT6~3fx9=`CC-D}-AMrpEO7HK zt3$GicGPc?GmDjy7K2P@La;eu4!$zWCZ`ym{Z$b zu-O6RM&K4JT|BIZB`E-gxqG%FzanI#+2FFmqHqXG7yxWB=w55RGOM)$xMb(>kSNR z2w=1AZi%z=AmG~yea~XaXJR!v7vLn(RUnELfiB1|6D84ICOS}^Zo2AdN}<&*h}G_u z{xZ!(%>tLT3J3<5XhWy-tg+6)0nmUUENLW8TWA{R6bgVd3X;anYFZ^IRis*_P-C-r z;i>%1^eL3UI2-{w8nuFFcs0e~7J{O2k^~Ce%+Ly4U?|=!0LH=t6()xi<^I-rs+9sF z*q{E-CxZbGPeu#a;XJwE;9S1?#R&uns>^0G3p`hEUF*v`M?@h%T%J%RChmD|EVydq zmHWh*_=S%emRC*mhxaVLzT@>Z2SX0u9v*DIJ@WC^kLVdlGV6LpK$KIrlJqc zpJ921)+3JJdTx|<`G&kXpKkjGJv=76R`yYIQ{#c-`%+`#V(7}Q;&@6U8!Td1`d;?N z_9mnI#?AA}4J!r)LN4!E-@H5eXauuB7TOawS>Y|{-P?NNx-lq+z1W-+y(;39P&&LP zL{N80?&=C*qKmdA^moMZRuPcD!B<*mq$ch=0Cnlitw#txRWhb3%TQvPqjkC`F69G4b! ze7z9MZ#+;_#l?H37UqUhDFb^l&s2{oM$3I0o^Q!yx;;V)QmCMo)Tb_ui|mit8MS?U zm##6$sZZ1$@|s%?l@>4Z<*Q}sRBSKMhb4I{e5LdEhsHIHTe8Bod5c>6QtT>$XgUBz z6MK`kO$=jmt@FqggOhJ5j~e@ygRbG;<{Vu)*+nn9aQeo0;$#j;|MS=S$&L?BeV25z xs3B`@=#`5TF{^6(A1rvdY@|-RtQ|iS5{tyX+wH?;n8E)G$kykv-D^wh{{!TZT%7;_ diff --git a/example/windows/example/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/example/windows/example/Assets/Square44x44Logo.targetsize-24_altform-unplated.png deleted file mode 100644 index f6c02ce97e0a802b85f6021e822c89f8bf57d5cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1255 zcmaJ>TWs4@7*5+{G#S+&C!qC#> zf>5N3P6jO*Cz>ug*(_DmW=)kea&m$gZ^+nyiF`;j%w@}y8)>p*SH}C`m?DXeieF2U zyQHecc_L%Gh!7GMt+hG06y;+|p4>m~}PjA}rKViGiEnn7G0ZO<>G|7q;2?NwGCM3s?eued6%hd$B+ z*kQJ{#~$S=DFE(%=E+UkmlEI*%3llUf~8Ja9YU1Vui0IbGBkW_gHB%Rd&!!ioX zs40O?i9I{};kle7GMvE7(rk`la=gTI)47=>%?q@^iL-nUo3}h4S}N-KHn8t5mVP8w z&bSErwp+37 zNJJ8?a|{r5Q3R0Z5s-LB1WHOwYC@7pCHWND#cL1cZ?{kJ368_*(UDWUDyb<}0y@o# zfMF016iMWPCb6obAxT$JlB6(2DrlXDTB&!0`!m??4F(qWMhjVZo?JXQmz`1*58Z=& zcDmB|S-E@j?BoFGix0flckqdS4jsPNzhfWyWIM98GxcLs89C(~dw%$_t;JjX-SD}E zfiGV;{8Q%8r}w9x>EEigW81>`kvnU@pK)4+xk9@+bNj9L!AAZ@SZ@q|)&BmY3+HZx zul~BeG4|}-;L%cHViQGQX?^zFfO0&#cHwel=d`lH9sJ-@Sl@n*(8J2>%Ac`IxyY?Q z{=GhWvC#gu-~Ia7*n{=+;qM?Ul_wy1+u7ho;=`>EwP^g~R@{unBds`!#@}tluZQpS zm)M~nYEifJWJGx?_6DcTy>#uh%>!H9=hb^(v`=m3F1{L>db=<5_tm+_&knAQ2EU$s Mu9UqpbNZeC0BbUo^Z)<= diff --git a/example/windows/example/Assets/StoreLogo.png b/example/windows/example/Assets/StoreLogo.png deleted file mode 100644 index 7385b56c0e4d3c6b0efe3324aa1194157d837826..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1451 zcmaJ>eN5D57_Z|bH;{0+1#mbl)eTU3{h)Wf7EZV?;HD@XL@{B`Ui%(2aMxQ~xdXSv z5nzWi(LW)U2=Vc-cY@s7nPt{i0hc6!7xN4NNHI#EQl>YNBy8l4%x9gr_W-j zEZMQmmTIy(>;lblRfh`dIyTgc9W5d!VP$L4(kKrN1c5G~(O_#xG zAJCNTstD^5SeXFB+&$h=ToJP2H>xr$iqPs-#O*;4(!Fjw25-!gEb*)mU}=)J;Iu>w zxK(5XoD0wrPSKQ~rbL^Cw6O_03*l*}i=ydbu7adJ6y;%@tjFeXIXT+ms30pmbOP%Q zX}S;+LBh8Tea~TSkHzvX6$rYb)+n&{kSbIqh|c7hmlxmwSiq5iVhU#iEQ<>a18|O^Sln-8t&+t`*{qBWo5M?wFM(JuimAOb5!K#D}XbslM@#1ZVz_;!9U zpfEpLAOz=0g@bd6Xj_ILi-x^!M}73h^o@}hM$1jflTs|Yuj9AL@A3<-?MV4!^4q`e z)fO@A;{9K^?W?DbnesnPr6kK>$zaKo&;FhFd(GYFCIU^T+OIMb%Tqo+P%oq(IdX7S zf6+HLO?7o0m+p>~Tp5UrXWh!UH!wZ5kv!E`_w)PTpI(#Iw{AS`gH4^b(bm^ZCq^FZ zY9DD7bH}rq9mg88+KgA$Zp!iWncuU2n1AuIa@=sWvUR-s`Qb{R*kk(SPU^`$6BXz8 zn#7yaFOIK%qGxyi`dYtm#&qqox0$h=pNi#u=M8zUG@bpiZ=3sT=1}Trr}39cC)H|v zbL?W)=&s4zrh)7>L(|cc%$1#!zfL?HjpeP%T+x_a+jZ16b^iKOHxFEX$7d|8${H-* zIrOJ5w&i$>*D>AKaIoYg`;{L@jM((Kt?$N$5OnuPqVvq**Nm}(f0wwOF%iX_Pba;V z;m@wxX&NcV3?<1+u?A{y_DIj7#m3Af1rCE)o`D&Y3}0%7E;iX1yMDiS)sh0wKi!36 zL!Wmq?P^Ku&rK~HJd97KkLTRl>ScGFYZNlYytWnhmuu|)L&ND8_PmkayQb{HOY640 bno1(wj@u8DCVuFR|31B*4ek@pZJqxCDDe1x diff --git a/example/windows/example/Assets/Wide310x150Logo.scale-200.png b/example/windows/example/Assets/Wide310x150Logo.scale-200.png deleted file mode 100644 index 288995b397fdbef1fb7e85afd71445d5de1952c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3204 zcmbVPeQXow8NYmBd90>}0NP?GhXW~VaeThm=a0tV#EwJMI!)6M3}|c4_Bl3=Kd>G0 z(GHx1wl<7(tP?FsOQkTilSo*iIvF%uArExJ73~P zSv1xEy!U(Wd4A9D`FQV@W3@F^qJ@PEF$@z`Z!*BbFsS(^?B zyiAzJ+q})bkgiQHWqEb*jJD-coHYr1^iocg)l!Qa{Xqs-l~6J}p-|##ZHYofskQ3$ zI0;xzXyhazBeXhIsg5A=%ufo@f)1yy&ScKS0;HF^!r_2UE^lpZEom(+@duma3awTv zCrCL-%D_SvYWIcdHkmI}#50(fkUi)Qgx!80ju>g1za^}ff>JI8Z@^-iCiaCgg@TgF z+vtE?Q9{VQUX&MW9SYYmGcxA14%N2@7FwBTD4N<(2{nWgV8$e3?-F=L^&FrtWn~(U_Q~~^uYiyeY6-KoTnfh9AWz@ zIKje0)u!_Lw)E}G!#kEfwKVdNt(UAf9*f>tEL_(=xco-T%jTi@7YlC3hs2ik%Le0H ztj}RTeCF(5mwvi3_56>-yB?l;J>-1%!9~=fs|QcNG3J~a@JCu`4SB460s0ZO+##4fFUSGLcj_ja^fL4&BKALfb#$6$O?>P@qx2Agl^x0i&ugt zsy5Pyu=()`7HRMG3IB7F1@`_ z+-!J%#i6e^U$e#+C%Q>_qVRzWRsG^W_n+@OcX@vzI&z;mzHNb!GQ?LWA(wtpqHqTM z1OFw_{Zn?fD)p)`c`kOgv{de=v@suGRqY{N^U7gI1VF3*F=obwaXI6ob5__Yn zVTguS!%(NI09J8x#AO_aW!9W7k*UvB;IWDFC3srwftr{kHj%g)fvnAm;&h_dnl~

MY- zf+K}sCe8qU6Ujs`3ua{U0Of$R_gVQBuUA za0v=mu#vIOqiiAZOr&h*$WyOw&k-xr$;G4Ixa!#TJNr>95(h>l%)PUy4p+^SgR(uR zta%k*?ny-+nAr8spEk1fo{J4i!b^Fia`N{_F6@zidA2ZTTrjl#^5Z-2KfB@Cu}l9s z(*|Z2jc?p~vn2f)3y9i*7zJV1L{$?|&q)4oaT;uXi6>1GkRXVTOzAz(RHEmr=eFIi z`}<>-Q?K0GN8!IYxeP1XKXO+jsJbp~o^);Bc;%b7Flpe7;1`Ny@3r7ZR;?R)aJt8C ziNlEC<@3f_lIV4TwV}&e;D!Ee5_|e#g0LUh=5vmYWYm7&2h*M>QPKvGh9-)wfMMW3 z8J9b%1k7dzPzO0_NGQy92BZ^FR6R~6;^6?lqO;-QUP4BY%cG%3vEhbm#>4vIhPBh3 z-+pZGjh$x%Hp{?=FHsMp0&wNPlj00us{&`1ZOZTqs8%4X&xH=UDr*xyBW(Zp&Em94 zf)ZSfn#yg0N)>!1kWdkqJ^S*z0FF5|fj&qcE#Na|%OY0$uO>!&hP+1ywfD_WXk@4J(?MBftK7>$Nvqh@tDuarN%PrTLQ2Uzysx>UV=V zk^RrDSvdQ?0;=hY67EgII-f4`t=+i*yS=Y~!XlqIy_4x&%+OdfbKOFPXS2X5%4R{N z$SQMX^AK6(fA - -namespace winrt::Microsoft::ReactNative -{ - -void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders) -{ - // IReactPackageProviders from @react-native-community/slider - packageProviders.Append(winrt::SliderWindows::ReactPackageProvider()); -} - -} diff --git a/example/windows/example/AutolinkedNativeModules.g.h b/example/windows/example/AutolinkedNativeModules.g.h deleted file mode 100644 index 95343bbd..00000000 --- a/example/windows/example/AutolinkedNativeModules.g.h +++ /dev/null @@ -1,10 +0,0 @@ -// AutolinkedNativeModules.g.h contents generated by "npx @react-native-community/cli autolink-windows" -// clang-format off -#pragma once - -namespace winrt::Microsoft::ReactNative -{ - -void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders); - -} diff --git a/example/windows/example/AutolinkedNativeModules.g.props b/example/windows/example/AutolinkedNativeModules.g.props deleted file mode 100644 index d12701bf..00000000 --- a/example/windows/example/AutolinkedNativeModules.g.props +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/example/windows/example/AutolinkedNativeModules.g.targets b/example/windows/example/AutolinkedNativeModules.g.targets deleted file mode 100644 index ef4e058e..00000000 --- a/example/windows/example/AutolinkedNativeModules.g.targets +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - {685a83ae-36bc-4e9d-bdc6-417ebf168463} - - - diff --git a/example/windows/example/MainPage.cpp b/example/windows/example/MainPage.cpp deleted file mode 100644 index b09666f2..00000000 --- a/example/windows/example/MainPage.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "pch.h" -#include "MainPage.h" -#if __has_include("MainPage.g.cpp") -#include "MainPage.g.cpp" -#endif - -#include "App.h" - -using namespace winrt; -using namespace xaml; - -namespace winrt::example::implementation -{ - MainPage::MainPage() - { - InitializeComponent(); - auto app = Application::Current().as(); - ReactRootView().ReactNativeHost(app->Host()); - } -} diff --git a/example/windows/example/MainPage.h b/example/windows/example/MainPage.h deleted file mode 100644 index 5ed917d5..00000000 --- a/example/windows/example/MainPage.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "MainPage.g.h" -#include - -namespace winrt::example::implementation -{ - struct MainPage : MainPageT - { - MainPage(); - }; -} - -namespace winrt::example::factory_implementation -{ - struct MainPage : MainPageT - { - }; -} - diff --git a/example/windows/example/MainPage.idl b/example/windows/example/MainPage.idl deleted file mode 100644 index ae088fea..00000000 --- a/example/windows/example/MainPage.idl +++ /dev/null @@ -1,10 +0,0 @@ -#include "NamespaceRedirect.h" - -namespace example -{ - [default_interface] - runtimeclass MainPage : XAML_NAMESPACE.Controls.Page - { - MainPage(); - } -} diff --git a/example/windows/example/MainPage.xaml b/example/windows/example/MainPage.xaml deleted file mode 100644 index b9794628..00000000 --- a/example/windows/example/MainPage.xaml +++ /dev/null @@ -1,16 +0,0 @@ - - - diff --git a/example/windows/example/Package.appxmanifest b/example/windows/example/Package.appxmanifest deleted file mode 100644 index 9df757b2..00000000 --- a/example/windows/example/Package.appxmanifest +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - example - Bartosz Klonowski - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/example/windows/example/PropertySheet.props b/example/windows/example/PropertySheet.props deleted file mode 100644 index 85d927cd..00000000 --- a/example/windows/example/PropertySheet.props +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/example/windows/example/ReactPackageProvider.cpp b/example/windows/example/ReactPackageProvider.cpp deleted file mode 100644 index ceb889ff..00000000 --- a/example/windows/example/ReactPackageProvider.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "pch.h" -#include "ReactPackageProvider.h" -#include "NativeModules.h" - -using namespace winrt::Microsoft::ReactNative; - -namespace winrt::example::implementation -{ - -void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept -{ - AddAttributedModules(packageBuilder, true); -} - -} // namespace winrt::example::implementation diff --git a/example/windows/example/ReactPackageProvider.h b/example/windows/example/ReactPackageProvider.h deleted file mode 100644 index 73379511..00000000 --- a/example/windows/example/ReactPackageProvider.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "winrt/Microsoft.ReactNative.h" - -namespace winrt::example::implementation -{ - struct ReactPackageProvider : winrt::implements - { - public: // IReactPackageProvider - void CreatePackage(winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) noexcept; - }; -} // namespace winrt::example::implementation - diff --git a/example/windows/example/example.vcxproj b/example/windows/example/example.vcxproj deleted file mode 100644 index 41f89b63..00000000 --- a/example/windows/example/example.vcxproj +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - true - true - true - {b18dbfa9-1510-4cc9-801d-e3da5168024e} - example - example - en-US - 17.0 - true - Windows Store - 10.0 - - - $([MSBuild]::GetDirectoryNameOfFileAbove($(SolutionDir), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\ - - - - - - Debug - ARM64 - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM64 - - - Release - Win32 - - - Release - x64 - - - - Application - Unicode - - - true - true - - - false - true - false - - - - - - - - - - - - - - - - Use - pch.h - $(IntDir)pch.pch - Level4 - %(AdditionalOptions) /bigobj - 4453;28204 - - - - - _DEBUG;%(PreprocessorDefinitions) - - - - - NDEBUG;%(PreprocessorDefinitions) - - - - - MainPage.xaml - Code - - - - - - App.xaml - - - - - Designer - - - - - Designer - - - - - - - - - - - - - - MainPage.xaml - Code - - - - - Create - - - App.xaml - - - - - - App.xaml - - - MainPage.xaml - Code - - - - - - false - - - - - Designer - - - - - - - - - - - This project references targets in your node_modules\react-native-windows folder that are missing. The missing file is {0}. - - - - - diff --git a/example/windows/example/example.vcxproj.filters b/example/windows/example/example.vcxproj.filters deleted file mode 100644 index ec2808a9..00000000 --- a/example/windows/example/example.vcxproj.filters +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - - - - - - {e48dc53e-40b1-40cb-970a-f89935452892} - - - - - - - - - - - - \ No newline at end of file diff --git a/example/windows/example/packages.lock.json b/example/windows/example/packages.lock.json deleted file mode 100644 index ef739131..00000000 --- a/example/windows/example/packages.lock.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "version": 1, - "dependencies": { - "native,Version=v0.0": { - "Microsoft.JavaScript.Hermes": { - "type": "Direct", - "requested": "[0.1.23, )", - "resolved": "0.1.23", - "contentHash": "cA9t1GjY4Yo0JD1AfA//e1lOwk48hLANfuX6GXrikmEBNZVr2TIX5ONJt5tqCnpZyLz6xGiPDgTfFNKbSfb21g==" - }, - "Microsoft.UI.Xaml": { - "type": "Direct", - "requested": "[2.8.0, )", - "resolved": "2.8.0", - "contentHash": "vxdHxTr63s5KVtNddMFpgvjBjUH50z7seq/5jLWmmSuf8poxg+sXrywkofUdE8ZstbpO9y3FL/IXXUcPYbeesA==", - "dependencies": { - "Microsoft.Web.WebView2": "1.0.1264.42" - } - }, - "Microsoft.Windows.CppWinRT": { - "type": "Direct", - "requested": "[2.0.230706.1, )", - "resolved": "2.0.230706.1", - "contentHash": "l0D7oCw/5X+xIKHqZTi62TtV+1qeSz7KVluNFdrJ9hXsst4ghvqQ/Yhura7JqRdZWBXAuDS0G0KwALptdoxweQ==" - }, - "boost": { - "type": "Transitive", - "resolved": "1.83.0", - "contentHash": "cy53VNMzysEMvhBixDe8ujPk67Fcj3v6FPHQnH91NYJNLHpc6jxa2xq9ruCaaJjE4M3YrGSHDi4uUSTGBWw6EQ==" - }, - "Microsoft.Web.WebView2": { - "type": "Transitive", - "resolved": "1.0.1264.42", - "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" - }, - "common": { - "type": "Project", - "dependencies": { - "boost": "[1.83.0, )" - } - }, - "fmt": { - "type": "Project" - }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.83.0, )", - "fmt": "[1.0.0, )" - } - }, - "microsoft.reactnative": { - "type": "Project", - "dependencies": { - "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "Microsoft.JavaScript.Hermes": "[0.1.23, )", - "Microsoft.UI.Xaml": "[2.8.0, )", - "ReactCommon": "[1.0.0, )", - "boost": "[1.83.0, )" - } - }, - "reactcommon": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )", - "boost": "[1.83.0, )" - } - }, - "sliderwindows": { - "type": "Project", - "dependencies": { - "Microsoft.ReactNative": "[1.0.0, )", - "Microsoft.UI.Xaml": "[2.8.0, )" - } - } - }, - "native,Version=v0.0/win10-arm": { - "Microsoft.Web.WebView2": { - "type": "Transitive", - "resolved": "1.0.1264.42", - "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" - } - }, - "native,Version=v0.0/win10-arm-aot": { - "Microsoft.Web.WebView2": { - "type": "Transitive", - "resolved": "1.0.1264.42", - "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" - } - }, - "native,Version=v0.0/win10-arm64-aot": { - "Microsoft.Web.WebView2": { - "type": "Transitive", - "resolved": "1.0.1264.42", - "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" - } - }, - "native,Version=v0.0/win10-x64": { - "Microsoft.Web.WebView2": { - "type": "Transitive", - "resolved": "1.0.1264.42", - "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" - } - }, - "native,Version=v0.0/win10-x64-aot": { - "Microsoft.Web.WebView2": { - "type": "Transitive", - "resolved": "1.0.1264.42", - "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" - } - }, - "native,Version=v0.0/win10-x86": { - "Microsoft.Web.WebView2": { - "type": "Transitive", - "resolved": "1.0.1264.42", - "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" - } - }, - "native,Version=v0.0/win10-x86-aot": { - "Microsoft.Web.WebView2": { - "type": "Transitive", - "resolved": "1.0.1264.42", - "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" - } - } - } -} \ No newline at end of file diff --git a/example/windows/example/pch.cpp b/example/windows/example/pch.cpp deleted file mode 100644 index e0d2ef1a..00000000 --- a/example/windows/example/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" diff --git a/example/windows/example/pch.h b/example/windows/example/pch.h deleted file mode 100644 index 54f954f4..00000000 --- a/example/windows/example/pch.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#define NOMINMAX - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -using namespace winrt::Windows::Foundation; From 1ef359f375e0a4cc1a8fcd5ffbb8387a59276b02 Mon Sep 17 00:00:00 2001 From: BartoszKlonowski Date: Tue, 19 May 2026 09:28:34 +0200 Subject: [PATCH 4/7] Custom compose with new callstack space - Android + RN This commit actually reimplements the whole Slider package so that: * Kotlin is being used for Android * Jetpack Compose is used to render the Slider * RNCustomRenderComposeView is implemented as AbstractComposeView didn't work with current solution * SliderViewManagerImpl is removed in favor of keeping everything in ViewManager And most of all: * Slider is now out of @react-native-community --- example/App.tsx | 55 +- example/package.json | 9 +- package/__test__/Slider.test.tsx | 80 --- .../__test__/components/StepNumber.test.tsx | 12 - .../components/StepsIndicator.test.tsx | 93 ---- .../__test__/components/TrackMark.test.tsx | 41 -- package/android/build.gradle | 7 +- package/android/gradle.properties | 4 - .../android/gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - package/android/gradlew | 172 ------ package/android/gradlew.bat | 84 --- package/android/src/main/AndroidManifest.xml | 5 +- .../com/callstack/slider/InlineComposeView.kt | 113 ++++ .../callstack/slider/ReactSliderPackage.kt | 15 + .../java/com/callstack/slider/SliderEvents.kt | 20 + .../java/com/callstack/slider/SliderView.kt | 55 ++ .../com/callstack/slider/SliderViewManager.kt | 50 ++ .../slider/ReactSlider.kt | 498 ------------------ .../slider/ReactSliderEvent.kt | 31 -- .../slider/ReactSliderEventListener.kt | 9 - .../slider/ReactSliderManager.kt | 173 ------ .../slider/ReactSliderManagerImpl.kt | 123 ----- .../slider/ReactSliderPackage.kt | 22 - .../slider/ReactSlidingCompleteEvent.kt | 31 -- .../slider/ReactSlidingStartEvent.kt | 31 -- package/android/src/main/jni/CMakeLists.txt | 93 +--- .../src/main/jni/{RNCSlider.h => Slider.h} | 4 +- .../RNCSlider/RNCSliderComponentDescriptor.h | 44 -- .../RNCSliderMeasurementsManager.cpp | 62 --- .../RNCSlider/RNCSliderMeasurementsManager.h | 26 - .../RNCSlider/RNCSliderShadowNode.cpp | 27 - .../RNCSlider/RNCSliderShadowNode.h | 45 -- .../components/RNCSlider/RNCSliderState.h | 28 - package/ios/RNCSlider.h | 8 +- package/ios/RNCSlider.m | 4 +- package/ios/RNCSliderComponentView.h | 10 +- package/ios/RNCSliderComponentView.mm | 68 +-- package/package.json | 11 +- package/react-native.config.js | 4 +- package/src/RNCSliderNativeComponent.ts | 46 -- package/src/RNCSliderNativeComponent.web.tsx | 48 +- package/src/Slider.tsx | 395 ++------------ package/src/SliderNativeComponent.ts | 26 + package/src/components/StepNumber.tsx | 21 - package/src/components/StepsIndicator.tsx | 105 ---- package/src/components/TrackMark.tsx | 55 -- package/src/index.ts | 5 +- package/src/utils/constants.ts | 13 - package/src/utils/styles.ts | 55 -- package/typings/index.d.ts | 214 -------- .../SliderWindows/SliderViewManager.cpp | 6 +- 52 files changed, 468 insertions(+), 2694 deletions(-) delete mode 100644 package/__test__/Slider.test.tsx delete mode 100644 package/__test__/components/StepNumber.test.tsx delete mode 100644 package/__test__/components/StepsIndicator.test.tsx delete mode 100644 package/__test__/components/TrackMark.test.tsx delete mode 100644 package/android/gradle.properties delete mode 100644 package/android/gradle/wrapper/gradle-wrapper.jar delete mode 100644 package/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 package/android/gradlew delete mode 100644 package/android/gradlew.bat create mode 100644 package/android/src/main/java/com/callstack/slider/InlineComposeView.kt create mode 100644 package/android/src/main/java/com/callstack/slider/ReactSliderPackage.kt create mode 100644 package/android/src/main/java/com/callstack/slider/SliderEvents.kt create mode 100644 package/android/src/main/java/com/callstack/slider/SliderView.kt create mode 100644 package/android/src/main/java/com/callstack/slider/SliderViewManager.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEventListener.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.kt delete mode 100644 package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.kt rename package/android/src/main/jni/{RNCSlider.h => Slider.h} (68%) delete mode 100644 package/common/cpp/react/renderer/components/RNCSlider/RNCSliderComponentDescriptor.h delete mode 100644 package/common/cpp/react/renderer/components/RNCSlider/RNCSliderMeasurementsManager.cpp delete mode 100644 package/common/cpp/react/renderer/components/RNCSlider/RNCSliderMeasurementsManager.h delete mode 100644 package/common/cpp/react/renderer/components/RNCSlider/RNCSliderShadowNode.cpp delete mode 100644 package/common/cpp/react/renderer/components/RNCSlider/RNCSliderShadowNode.h delete mode 100644 package/common/cpp/react/renderer/components/RNCSlider/RNCSliderState.h delete mode 100644 package/src/RNCSliderNativeComponent.ts create mode 100644 package/src/SliderNativeComponent.ts delete mode 100644 package/src/components/StepNumber.tsx delete mode 100644 package/src/components/StepsIndicator.tsx delete mode 100644 package/src/components/TrackMark.tsx delete mode 100644 package/src/utils/constants.ts delete mode 100644 package/src/utils/styles.ts delete mode 100644 package/typings/index.d.ts diff --git a/example/App.tsx b/example/App.tsx index a001944c..86ab6300 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -5,44 +5,37 @@ * @format */ -import Slider from '@react-native-community/slider'; -import { NewAppScreen } from '@react-native/new-app-screen'; -import { useState } from 'react'; -import { SafeAreaView, StatusBar, StyleSheet, Text, useColorScheme, View } from 'react-native'; -import { - SafeAreaProvider, - useSafeAreaInsets, -} from 'react-native-safe-area-context'; +import Slider from "@react-native-community/slider"; +import { useState } from "react"; +import { StyleSheet, Text, View } from "react-native"; function App() { - const isDarkMode = useColorScheme() === 'dark'; - return ( - - - ); } function AppContent() { const [sliderValue, setSliderValue] = useState(0); - const safeAreaInsets = useSafeAreaInsets(); - console.log("BLA"); return ( - { - console.log('value', value); - }} - /> - {sliderValue} + {sliderValue.toFixed(2)} + { + setSliderValue(value); + console.log('value', value); + }} + step={5} + minValue={50} + maxValue={100} + style={{ + padding: 20, + width: "80%", + height: 40, + backgroundColor: "transparent", + }} + /> ); } @@ -51,18 +44,18 @@ const styles = StyleSheet.create({ container: { padding: 10, gap: 10, - justifyContent: 'center', - alignItems: 'center', + justifyContent: "center", + alignItems: "center", flex: 1, }, stepMarker: { - backgroundColor: 'red', + backgroundColor: "red", width: 10, height: 10, }, slider: { - color: 'red', - width: '70%', + color: "red", + width: "70%", height: 40, }, }); diff --git a/example/package.json b/example/package.json index 022462b3..52ec8d01 100644 --- a/example/package.json +++ b/example/package.json @@ -15,11 +15,10 @@ "clean-ios": "rm -rf ios/build/generated/ios && rm -rf ios/Pods && rm ios/Podfile.lock" }, "dependencies": { + "@mgcrea/react-native-jetpack-compose": "^0.8.0", "@react-native-community/slider": "file:../package", "react": "19.2.3", - "react-native": "0.85.1", - "@react-native/new-app-screen": "0.85.1", - "react-native-safe-area-context": "^5.5.2" + "react-native": "0.85.1" }, "devDependencies": { "@babel/core": "^7.25.2", @@ -36,13 +35,13 @@ "@types/jest": "^29.5.13", "@types/react": "^19.2.0", "@types/react-test-renderer": "^19.1.0", + "copyfiles": "^2.4.1", "eslint": "^8.19.0", "jest": "^29.6.3", "prettier": "2.8.8", "react-test-renderer": "19.2.3", - "typescript": "^5.8.3", "rimraf": "^5.0.5", - "copyfiles": "^2.4.1" + "typescript": "^5.8.3" }, "engines": { "node": ">= 22.11.0" diff --git a/package/__test__/Slider.test.tsx b/package/__test__/Slider.test.tsx deleted file mode 100644 index f2073126..00000000 --- a/package/__test__/Slider.test.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react'; -import {fireEvent, render} from '@testing-library/react-native'; -import Slider from '../src/Slider'; - -describe('Slider', () => { - it('Calls the given onValueChange when native event is emitted', () => { - const onValueChange = jest.fn(); - const {getByTestId} = render( - , - ); - const slider = getByTestId('slider'); - fireEvent(slider, 'change', {nativeEvent: {value: 2}}); - expect(onValueChange).toHaveBeenCalledWith(2); - }); - - it('Handles provided events when sliding starts is emitted', () => { - const onSlidingStart = jest.fn(); - const {getByTestId} = render( - , - ); - const slider = getByTestId('slider'); - - fireEvent(slider, 'onRNCSliderSlidingStart', {nativeEvent: {value: 2}}); - expect(onSlidingStart).toHaveBeenCalledWith(2); - }); - - it('Handles provided events when sliding end is emitted', () => { - const onSlidingComplete = jest.fn(); - const {getByTestId} = render( - , - ); - const slider = getByTestId('slider'); - - fireEvent(slider, 'onRNCSliderSlidingComplete', {nativeEvent: {value: 2}}); - expect(onSlidingComplete).toHaveBeenCalledWith(2); - }); - - it('Calls the accessibility handler when accessibility action is triggered', () => { - const mockedAccessibilityHandler = jest.fn(); - const {getByTestId} = render( - , - ); - const slider = getByTestId('slider'); - - fireEvent(slider, 'onRNCSliderAccessibilityAction', { - actionName: 'mocked-action', - }); - expect(mockedAccessibilityHandler).toHaveBeenCalledWith({ - actionName: 'mocked-action', - }); - }); - - it('Emitts a warning in the dev console if lower and upper limits are switched', () => { - const mockedWarn = jest.fn(); - console.warn = mockedWarn; - render(); - expect(mockedWarn).toHaveBeenCalled(); - }); - - it('Provides the onLayout with the measured width', () => { - const {getByTestId} = render(); - const slider = getByTestId('slider'); - fireEvent(slider, 'onLayout', {nativeEvent: {layout: {width: 200}}}); - expect(slider).toHaveStyle({width: 200}); - }); - - it('Prevents the gesture control from being released externally', () => { - const mockedRelease = jest.fn(); - jest.mock('../src/index', () => ({ - ...jest.requireActual('../src/index'), - onResponderRelease: mockedRelease, - })); - const {getByTestId} = render(); - fireEvent(getByTestId('slider'), 'onResponderTerminationRequest'); - expect(mockedRelease).not.toHaveBeenCalled(); - }); -}); diff --git a/package/__test__/components/StepNumber.test.tsx b/package/__test__/components/StepNumber.test.tsx deleted file mode 100644 index 92828c72..00000000 --- a/package/__test__/components/StepNumber.test.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import {render} from '@testing-library/react-native'; -import {StepNumber} from '../../src/components/StepNumber'; - -describe('StepNumber', () => { - it('Displays number of step according to given index', () => { - const {getByText} = render( - , - ); - expect(getByText('0')).toBeDefined(); - }); -}); diff --git a/package/__test__/components/StepsIndicator.test.tsx b/package/__test__/components/StepsIndicator.test.tsx deleted file mode 100644 index 5f49a93f..00000000 --- a/package/__test__/components/StepsIndicator.test.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import React from 'react'; -import {render} from '@testing-library/react-native'; -import {StepsIndicator} from '../../src/components/StepsIndicator'; -import {constants} from '../../src/utils/constants'; -import {Platform} from 'react-native'; -import {styles} from '../../src/utils/styles'; - -const defaultOptions = [0, 1, 2, 3, 4, 5]; -const longerOptions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - -describe('StepsIndicator', () => { - it('Renders every step provided in options', () => { - const {getByText} = render( - , - ); - for (const step of defaultOptions) { - expect(getByText(step.toString())).toBeDefined(); - } - }); - - it('Applies the big font size to the lower number of steps', () => { - const {getByTestId} = render( - , - ); - expect(getByTestId('0th-step')).toHaveStyle({ - fontSize: constants.STEP_NUMBER_TEXT_FONT_BIG, - }); - }); - - it('Applies the small font size to the number of steps higher than 9', () => { - const {getByTestId} = render( - , - ); - expect(getByTestId('0th-step')).toHaveStyle({ - fontSize: constants.STEP_NUMBER_TEXT_FONT_SMALL, - }); - }); - - it('Applies platform-dependent styles for web', () => { - Platform.OS = 'web'; - const {getByTestId} = render( - , - ); - expect(getByTestId('StepsIndicator-Container')).toHaveStyle( - styles.stepsIndicator, - ); - }); - - it('Reverts given options when isLTR is set', () => { - const {getByTestId} = render( - , - ); - expect(getByTestId('0th-step')).toHaveTextContent('5'); - expect(getByTestId('2th-step')).toHaveTextContent('3'); - }); - - it('Does not display any step numbers if prop is not set', () => { - const {queryByTestId} = render( - , - ); - expect(queryByTestId('0th-step')).toBeFalsy(); - }); -}); diff --git a/package/__test__/components/TrackMark.test.tsx b/package/__test__/components/TrackMark.test.tsx deleted file mode 100644 index b2356879..00000000 --- a/package/__test__/components/TrackMark.test.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import {render} from '@testing-library/react-native'; -import {MarkerProps, SliderTrackMark} from '../../src/components/TrackMark'; -import {View} from 'react-native'; - -const MockedStepMarker = ({}: MarkerProps) => ( - -); - -const MockedThumbImage = 1; - -describe('TrackMark', () => { - it('Renders the StepMarker if custom component is given', () => { - const {getByTestId} = render( - , - ); - expect(getByTestId('mockedStepMarker')).toBeDefined(); - }); - - it('Renders the StepMarker with thumbImage if provided', () => { - const {getByTestId} = render( - , - ); - expect(getByTestId('sliderTrackMark-thumbImage')).toBeDefined(); - }); -}); diff --git a/package/android/build.gradle b/package/android/build.gradle index c391ca61..53c7de7b 100644 --- a/package/android/build.gradle +++ b/package/android/build.gradle @@ -36,7 +36,7 @@ android { def major = agpVersion[0].toInteger() def minor = agpVersion[1].toInteger() if ((major == 7 && minor >= 3) || major >= 8) { - namespace "com.reactnativecommunity.slider" + namespace "com.callstack.slider" buildFeatures { buildConfig true compose true @@ -77,5 +77,8 @@ dependencies { implementation 'androidx.compose.ui:ui-tooling-preview' debugImplementation 'androidx.compose.ui:ui-tooling' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0' -} + implementation 'com.facebook.react:react-android' + + implementation 'androidx.activity:activity-compose:1.8.2' +} diff --git a/package/android/gradle.properties b/package/android/gradle.properties deleted file mode 100644 index cdf09fb3..00000000 --- a/package/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -ReactNativeSlider_compileSdkVersion=30 -ReactNativeSlider_buildToolsVersion=30.0.0 -ReactNativeSlider_targetSdkVersion=30 -ReactNativeSlider_minSdkVersion=21 diff --git a/package/android/gradle/wrapper/gradle-wrapper.jar b/package/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index f6b961fd5a86aa5fbfe90f707c3138408be7c718..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54329 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

<5G2M1WZP5 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 F{|7XC?P&l2 diff --git a/package/android/gradle/wrapper/gradle-wrapper.properties b/package/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 862a5356..00000000 --- a/package/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Sat Feb 09 14:36:05 CET 2019 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip diff --git a/package/android/gradlew b/package/android/gradlew deleted file mode 100644 index cccdd3d5..00000000 --- a/package/android/gradlew +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env sh - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/package/android/gradlew.bat b/package/android/gradlew.bat deleted file mode 100644 index e95643d6..00000000 --- a/package/android/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/package/android/src/main/AndroidManifest.xml b/package/android/src/main/AndroidManifest.xml index f8c7bb80..a2f47b60 100644 --- a/package/android/src/main/AndroidManifest.xml +++ b/package/android/src/main/AndroidManifest.xml @@ -1,3 +1,2 @@ - - \ No newline at end of file + + diff --git a/package/android/src/main/java/com/callstack/slider/InlineComposeView.kt b/package/android/src/main/java/com/callstack/slider/InlineComposeView.kt new file mode 100644 index 00000000..7991aeff --- /dev/null +++ b/package/android/src/main/java/com/callstack/slider/InlineComposeView.kt @@ -0,0 +1,113 @@ +package com.callstack.slider + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Recomposer +import androidx.compose.ui.platform.AbstractComposeView +import androidx.compose.ui.platform.AndroidUiDispatcher +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.platform.compositionContext +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.setViewTreeLifecycleOwner +import androidx.savedstate.SavedStateRegistry +import androidx.savedstate.SavedStateRegistryController +import androidx.savedstate.SavedStateRegistryOwner +import androidx.savedstate.setViewTreeSavedStateRegistryOwner +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.events.Event +import com.facebook.react.uimanager.events.EventDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch + +abstract class RNCustomRenderComposeView( + protected val reactContext: ThemedReactContext, +) : AbstractComposeView(reactContext), LifecycleOwner, SavedStateRegistryOwner { + + private val lifecycleRegistry = LifecycleRegistry(this) + private val savedStateRegistryController = SavedStateRegistryController.create(this) + + override val lifecycle: Lifecycle get() = lifecycleRegistry + override val savedStateRegistry: SavedStateRegistry + get() = savedStateRegistryController.savedStateRegistry + + private var recomposerScope: CoroutineScope? = null + + var eventDispatcher: EventDispatcher? = null + + @Composable + abstract fun ComposeContent() + + @Composable + override fun Content() { + ComposeContent() + } + + init { + savedStateRegistryController.performRestore(null) + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) + setViewCompositionStrategy( + ViewCompositionStrategy.DisposeOnLifecycleDestroyed(lifecycle), + ) + } + + override fun onAttachedToWindow() { + ensureRecomposer() + resumeLifecycle() + super.onAttachedToWindow() + } + + override fun onDetachedFromWindow() { + pauseLifecycle() + super.onDetachedFromWindow() + } + + open fun onDropInstance() { + eventDispatcher = null + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) + recomposerScope?.cancel() + recomposerScope = null + } + + protected fun dispatchEvent(event: Event<*>) { + val dispatcher = eventDispatcher ?: return + post { + dispatcher.dispatchEvent(event) + } + } + + protected fun getSurfaceId(): Int = UIManagerHelper.getSurfaceId(this) + + private fun ensureRecomposer() { + if (recomposerScope != null) return + + setViewTreeLifecycleOwner(this) + setViewTreeSavedStateRegistryOwner(this) + + val scope = CoroutineScope(AndroidUiDispatcher.CurrentThread) + recomposerScope = scope + val recomposer = Recomposer(scope.coroutineContext) + scope.launch { recomposer.runRecomposeAndApplyChanges() } + compositionContext = recomposer + } + + private fun resumeLifecycle() { + when (lifecycleRegistry.currentState) { + Lifecycle.State.CREATED -> { + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START) + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) + } + Lifecycle.State.STARTED -> + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) + else -> Unit + } + } + + private fun pauseLifecycle() { + if (lifecycleRegistry.currentState == Lifecycle.State.DESTROYED) return + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) + } +} diff --git a/package/android/src/main/java/com/callstack/slider/ReactSliderPackage.kt b/package/android/src/main/java/com/callstack/slider/ReactSliderPackage.kt new file mode 100644 index 00000000..16906aaa --- /dev/null +++ b/package/android/src/main/java/com/callstack/slider/ReactSliderPackage.kt @@ -0,0 +1,15 @@ +package com.callstack.slider + +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.uimanager.ViewManager + +class SliderPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List = + emptyList() + + override fun createViewManagers( + reactContext: ReactApplicationContext, + ): List> = listOf(SliderViewManager()) +} diff --git a/package/android/src/main/java/com/callstack/slider/SliderEvents.kt b/package/android/src/main/java/com/callstack/slider/SliderEvents.kt new file mode 100644 index 00000000..892a339a --- /dev/null +++ b/package/android/src/main/java/com/callstack/slider/SliderEvents.kt @@ -0,0 +1,20 @@ +package com.callstack.slider + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +class ValueChangedEvent(surfaceId: Int, viewId: Int, private val value: Float) : + Event(surfaceId, viewId) { + + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap = + Arguments.createMap().apply { + putDouble("value", value.toDouble()) + } + + companion object { + const val EVENT_NAME = "topValueChange" + } +} diff --git a/package/android/src/main/java/com/callstack/slider/SliderView.kt b/package/android/src/main/java/com/callstack/slider/SliderView.kt new file mode 100644 index 00000000..928c7624 --- /dev/null +++ b/package/android/src/main/java/com/callstack/slider/SliderView.kt @@ -0,0 +1,55 @@ +package com.callstack.slider + +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Slider +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import com.facebook.react.uimanager.ThemedReactContext +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.sizeIn +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.remember + +@OptIn(ExperimentalMaterial3Api::class) +internal class SliderView(reactContext: ThemedReactContext) : + RNCustomRenderComposeView(reactContext) { + + private val minValue = mutableStateOf(0f) + private val maxValue = mutableStateOf(1f) + private val steps = mutableStateOf(0) + + fun setMinValue(value: Float) { + minValue.value = value + } + + fun setMaxValue(value: Float) { + maxValue.value = value + } + + fun setStep(value: Int) { + steps.value = value + } + + @Composable + override fun ComposeContent() { + var sliderPosition by rememberSaveable { mutableStateOf(0f) } + val interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } + + Slider( + value = sliderPosition, + onValueChange = { + sliderPosition = it + dispatchEvent(ValueChangedEvent(getSurfaceId(), id, it)) + }, + steps = steps.value, + valueRange = minValue.value..maxValue.value, + interactionSource = interactionSource, + ) + } +} diff --git a/package/android/src/main/java/com/callstack/slider/SliderViewManager.kt b/package/android/src/main/java/com/callstack/slider/SliderViewManager.kt new file mode 100644 index 00000000..fa6ec22f --- /dev/null +++ b/package/android/src/main/java/com/callstack/slider/SliderViewManager.kt @@ -0,0 +1,50 @@ +package com.callstack.slider + +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.ViewManagerDelegate +import com.facebook.react.viewmanagers.SliderViewManagerDelegate +import com.facebook.react.viewmanagers.SliderViewManagerInterface + +@ReactModule(name = SliderViewManager.NAME) +internal class SliderViewManager : + SimpleViewManager(), + SliderViewManagerInterface { + + private val delegate: ViewManagerDelegate = + SliderViewManagerDelegate(this) + + override fun getName(): String = NAME + + override fun createViewInstance(context: ThemedReactContext): SliderView = SliderView(context) + + override fun getDelegate(): ViewManagerDelegate = delegate + + override fun onDropViewInstance(view: SliderView) { + super.onDropViewInstance(view) + view.onDropInstance() + } + + override fun setStep(view: SliderView, value: Int) { + view.setStep(value) + } + + override fun setMinValue(view: SliderView, value: Float) { + view.setMinValue(value) + } + + override fun setMaxValue(view: SliderView, value: Float) { + view.setMaxValue(value) + } + + override fun addEventEmitters(reactContext: ThemedReactContext, view: SliderView) { + view.eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id) + } + + companion object { + const val NAME = "SliderView" + } +} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt deleted file mode 100644 index 8bf735a1..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.kt +++ /dev/null @@ -1,498 +0,0 @@ -@file:OptIn(androidx.compose.material3.ExperimentalMaterial3Api::class) - -package com.reactnativecommunity.slider - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.os.Build -import android.util.AttributeSet -import android.util.Log -import android.view.accessibility.AccessibilityEvent -import android.view.accessibility.AccessibilityManager -import androidx.compose.foundation.Image -import androidx.compose.foundation.interaction.DragInteraction -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.size -import androidx.compose.material3.Slider -import androidx.compose.material3.SliderDefaults -import androidx.compose.material3.SliderState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.Recomposer -import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.scale -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.AbstractComposeView -import androidx.compose.ui.platform.AndroidUiDispatcher -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.LayoutDirection -import androidx.compose.ui.unit.dp -import com.facebook.react.modules.i18nmanager.I18nUtil -import java.net.URL -import java.util.Timer -import java.util.TimerTask -import kotlin.math.ceil -import kotlin.math.max -import kotlin.math.min -import kotlin.math.round -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext - -/** - * Slider that behaves more like the iOS one, for consistency. - * - * On iOS, the value is 0..1. Android SeekBar only supports integer values. For consistency, we - * pretend in JS that the value is 0..1 but use discrete steps internally. - * - * Note that the slider is _not_ a controlled component (setValue isn't called during dragging). - * - * UI is implemented with Jetpack Compose (Material 3 [Slider]) inside an [AbstractComposeView]. - */ -class ReactSlider @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, -) : AbstractComposeView(context, attrs) { - - private val defaultTotalSteps = 128 - - private var minValue = 0.0 - private var maxValue = 0.0 - private var value = 0.0 - private var step = 0.0 - private var stepCalculated = 0.0 - private var accessibilityUnits: String? = null - private var accessibilityIncrements: List? = null - - private var realLowerLimit = Long.MIN_VALUE.toDouble() - internal var lowerLimit = 0 - private set - private var realUpperLimit = Long.MAX_VALUE.toDouble() - internal var upperLimit = 0 - private set - - private var thumbSizePx = 0 - private var thumbImageUri: String? = null - private var thumbTintColor: Int? = null - private var minimumTrackTintColor: Int? = null - private var maximumTrackTintColor: Int? = null - private var inverted = false - - private val propsVersion = mutableIntStateOf(0) - private val isUserDragging = mutableStateOf(false) - - internal val isSliding: Boolean - get() = isUserDragging.value - - private var eventListener: ReactSliderEventListener? = null - - /** Latest value shown on the slider; used for sliding-start events and accessibility. */ - private var latestDisplayedValue = 0.0 - - /** - * React Native can measure and update this view before it is attached to a window. The default - * Compose path looks up a [androidx.compose.ui.platform.WindowRecomposer] from the view root, which - * throws if the view has no window. A dedicated [Recomposer] avoids that lookup. - * Use [AndroidUiDispatcher.Main] so [Recomposer.runRecomposeAndApplyChanges] has a - * [androidx.compose.runtime.MonotonicFrameClock]. - */ - private val recomposer = Recomposer(AndroidUiDispatcher.Main) - private val recomposerScope = CoroutineScope(SupervisorJob() + AndroidUiDispatcher.Main) - private var recomposerRunJob: Job? = null - - init { - setParentCompositionContext(recomposer) - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow) - startRecomposerIfNeeded() - } - - private fun startRecomposerIfNeeded() { - if (recomposerRunJob?.isActive == true) return - recomposerRunJob = - recomposerScope.launch { - recomposer.runRecomposeAndApplyChanges() - } - } - - override fun onAttachedToWindow() { - super.onAttachedToWindow() - startRecomposerIfNeeded() - } - - override fun onDetachedFromWindow() { - recomposerRunJob?.cancel() - recomposerRunJob = null - super.onDetachedFromWindow() - } - - internal fun setEventListener(listener: ReactSliderEventListener?) { - eventListener = listener - } - - private fun bumpProps() { - propsVersion.intValue++ - } - - internal fun setMaxValue(max: Double) { - maxValue = max - updateAll() - } - - internal fun setMinValue(min: Double) { - minValue = min - updateAll() - } - - internal fun getValidProgressValue(progress: Int): Int { - return when { - progress < lowerLimit -> lowerLimit - progress > upperLimit -> upperLimit - else -> progress - } - } - - internal fun setValue(value: Double) { - this.value = value - if (!isSliding) { - bumpProps() - } - } - - internal fun setStep(step: Double) { - this.step = step - updateAll() - } - - internal fun setLowerLimit(value: Double) { - realLowerLimit = value - updateLowerLimit() - bumpProps() - } - - internal fun setUpperLimit(value: Double) { - realUpperLimit = value - updateUpperLimit() - bumpProps() - } - - internal fun setAccessibilityUnits(accessibilityUnits: String?) { - this.accessibilityUnits = accessibilityUnits - } - - internal fun setAccessibilityIncrements(accessibilityIncrements: List?) { - this.accessibilityIncrements = accessibilityIncrements - } - - internal fun setThumbImageUri(uri: String?) { - thumbImageUri = uri - bumpProps() - } - - internal fun setThumbSize(sizeDp: Float) { - val density = resources.displayMetrics.density - thumbSizePx = if (sizeDp > 0) round(sizeDp * density).toInt() else 0 - bumpProps() - } - - internal fun setThumbTintColor(color: Int?) { - thumbTintColor = color - bumpProps() - } - - internal fun setMinimumTrackTintColor(color: Int?) { - minimumTrackTintColor = color - bumpProps() - } - - internal fun setMaximumTrackTintColor(color: Int?) { - maximumTrackTintColor = color - bumpProps() - } - - internal fun applyDisabledProp(disabled: Boolean) { - isEnabled = !disabled - bumpProps() - } - - internal fun setInverted(inverted: Boolean) { - this.inverted = inverted - bumpProps() - } - - fun toRealProgress(seekBarProgress: Int): Double { - return if (seekBarProgress == totalSteps) { - maxValue - } else { - seekBarProgress * getStepValue() + minValue - } - } - - private fun updateAll() { - if (step == 0.0) { - stepCalculated = (maxValue - minValue) / defaultTotalSteps.toDouble() - } - updateLowerLimit() - updateUpperLimit() - bumpProps() - } - - private fun updateLowerLimit() { - if (maxValue <= minValue) return - val limit = maxOf(realLowerLimit, minValue) - val lower = round((limit - minValue) / (maxValue - minValue) * totalSteps).toInt() - if (lower > upperLimit) { - Log.d("Invalid configuration", "upperLimit < lowerLimit; lowerLimit not set") - } else { - lowerLimit = minOf(lower, upperLimit) - } - } - - private fun updateUpperLimit() { - if (maxValue <= minValue) return - val limit = minOf(realUpperLimit, maxValue) - val upper = round((limit - minValue) / (maxValue - minValue) * totalSteps).toInt() - if (lowerLimit > upper) { - Log.d("Invalid configuration", "upperLimit < lowerLimit; upperLimit not set") - } else { - upperLimit = upper - } - } - - private val totalSteps: Int - get() { - if (maxValue <= minValue) return 0 - return ceil((maxValue - minValue) / getStepValue()).toInt() - } - - private fun getStepValue(): Double = if (step > 0) step else stepCalculated - - private fun progressForReal(real: Double): Int { - if (maxValue <= minValue || totalSteps <= 0) return 0 - return round((real - minValue) / (maxValue - minValue) * totalSteps).toInt() - } - - private fun clampedRealToFloat(real: Double): Float { - val p = getValidProgressValue(progressForReal(real)) - return toRealProgress(p).toFloat() - } - - override fun onPopulateAccessibilityEvent(event: AccessibilityEvent) { - super.onPopulateAccessibilityEvent(event) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (event.eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED || - (event.eventType == AccessibilityEvent.TYPE_VIEW_SELECTED && isAccessibilityFocused) - ) { - setupAccessibility(latestDisplayedValue.toInt()) - } - } - } - - override fun announceForAccessibility(text: CharSequence?) { - val ctx = context - val manager = ctx.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager - if (manager.isEnabled && text != null) { - val e = AccessibilityEvent.obtain() - e.eventType = AccessibilityEvent.TYPE_ANNOUNCEMENT - e.className = javaClass.name - e.packageName = ctx.packageName - e.text.add(text) - val task = - object : TimerTask() { - override fun run() { - manager.sendAccessibilityEvent(e) - } - } - Timer().schedule(task, 1000) - } - } - - fun setupAccessibility(index: Int) { - val units = accessibilityUnits - val increments = accessibilityIncrements - if (units != null && increments != null && increments.size - 1 == maxValue.toInt()) { - val sliderValue = increments[index] - val stringLength = units.length - var spokenUnits = units - if (sliderValue.toInt() == 1) { - spokenUnits = spokenUnits.substring(0, stringLength - 1) - } - announceForAccessibility(String.format("%s %s", sliderValue, spokenUnits)) - } - } - - private fun loadBitmap(uri: String): Bitmap? { - return try { - if (uri.startsWith("http://") || uri.startsWith("https://") || - uri.startsWith("file://") || uri.startsWith("asset://") || uri.startsWith("data:") - ) { - BitmapFactory.decodeStream(URL(uri).openStream()) - } else { - val drawableId = resources.getIdentifier(uri, "drawable", context.packageName) - BitmapFactory.decodeResource(resources, drawableId) - } - } catch (e: Exception) { - e.printStackTrace() - null - } - } - - @Composable - override fun Content() { - val _propsTick = propsVersion.intValue - @Suppress("DEPRECATION") - val isRtl = I18nUtil.getInstance().isRTL(context) - val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr - - val minV = minValue.toFloat() - val maxV = maxValue.toFloat() - val rangeEmptyOrInvalid = maxV <= minV - val valueRange = minV..maxV - val materialSteps = if (rangeEmptyOrInvalid) 0 else maxOf(totalSteps - 1, 0) - - val interactionSource = remember { MutableInteractionSource() } - - var localValue by remember(minV, maxV, _propsTick) { - mutableFloatStateOf(clampedRealToFloat(value)) - } - - val dragging = isUserDragging.value - LaunchedEffect(value, _propsTick, dragging) { - if (!dragging) { - localValue = clampedRealToFloat(value) - } - } - - val valueAtGesture = remember { mutableFloatStateOf(0f) } - - LaunchedEffect(interactionSource) { - interactionSource.interactions.collect { interaction -> - when (interaction) { - is DragInteraction.Start -> { - isUserDragging.value = true - eventListener?.onSlidingStart(valueAtGesture.floatValue.toDouble()) - } - is DragInteraction.Stop, is DragInteraction.Cancel -> { - isUserDragging.value = false - } - } - } - } - - val thumbUri = thumbImageUri - var thumbBitmap by remember(thumbUri, _propsTick) { mutableStateOf(null) } - LaunchedEffect(thumbUri, _propsTick) { - if (thumbUri == null) { - thumbBitmap = null - return@LaunchedEffect - } - val bmp = withContext(Dispatchers.IO) { loadBitmap(thumbUri) } - thumbBitmap = bmp - } - - val density = LocalDensity.current - val thumbDp = - if (thumbSizePx > 0) { - with(density) { thumbSizePx.toDp() } - } else { - 0.dp - } - val thumbSizeDp = if (thumbSizePx > 0) DpSize(thumbDp, thumbDp) else DpSize(20.dp, 20.dp) - - val baseColors = SliderDefaults.colors() - val sliderColors = - SliderDefaults.colors( - thumbColor = thumbTintColor?.let { Color(it) } ?: baseColors.thumbColor, - activeTrackColor = minimumTrackTintColor?.let { Color(it) } ?: baseColors.activeTrackColor, - inactiveTrackColor = maximumTrackTintColor?.let { Color(it) } ?: baseColors.inactiveTrackColor, - ) - - SideEffect { - valueAtGesture.floatValue = localValue - latestDisplayedValue = localValue.toDouble() - } - - androidx.compose.runtime.CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) { - Box( - modifier = - Modifier - .fillMaxWidth() - .height(48.dp) - .then(if (inverted) Modifier.scale(scaleX = -1f, scaleY = 1f) else Modifier), - contentAlignment = Alignment.Center, - ) { - if (!rangeEmptyOrInvalid) { - Slider( - value = localValue, - onValueChange = { newVal -> - val clamped = clampedRealToFloat(newVal.toDouble()) - if (clamped != localValue) { - localValue = clamped - } - eventListener?.onSliderValueChange(clamped.toDouble(), true) - }, - modifier = Modifier.fillMaxWidth(), - enabled = isEnabled, - onValueChangeFinished = { - eventListener?.onSlidingComplete(localValue.toDouble()) - isUserDragging.value = false - }, - colors = sliderColors, - interactionSource = interactionSource, - steps = materialSteps, - thumb = { _: SliderState -> - val bmp = thumbBitmap - if (bmp != null) { - val sizeForImage = - if (thumbSizePx > 0) Modifier.size(thumbDp) else Modifier.size(ThumbImageFallbackDp) - Image( - bitmap = bmp.asImageBitmap(), - contentDescription = null, - modifier = sizeForImage, - contentScale = ContentScale.Fit, - ) - } else if (thumbSizePx > 0) { - SliderDefaults.Thumb( - interactionSource = interactionSource, - colors = sliderColors, - enabled = isEnabled, - thumbSize = thumbSizeDp, - ) - } else { - SliderDefaults.Thumb( - interactionSource = interactionSource, - colors = sliderColors, - enabled = isEnabled, - ) - } - }, - valueRange = valueRange, - ) - } - } - } - } - - companion object { - private val ThumbImageFallbackDp = 24.dp - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.kt deleted file mode 100644 index c25d835b..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEvent.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.reactnativecommunity.slider - -import com.facebook.react.bridge.Arguments -import com.facebook.react.bridge.WritableMap -import com.facebook.react.uimanager.events.Event - -/** Event emitted by a ReactSliderManager when user changes slider position. */ -class ReactSliderEvent( - viewId: Int, - private val value: Double, - private val fromUser: Boolean, -) : Event(viewId) { - - override fun getEventName(): String = EVENT_NAME - - override fun getCoalescingKey(): Short = 0 - - override fun getEventData(): WritableMap? = serializeEventData() - - private fun serializeEventData(): WritableMap { - val eventData = Arguments.createMap() - eventData.putInt("target", viewTag) - eventData.putDouble("value", value) - eventData.putBoolean("fromUser", fromUser) - return eventData - } - - companion object { - const val EVENT_NAME = "topChange" - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEventListener.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEventListener.kt deleted file mode 100644 index a9d49ec9..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderEventListener.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.reactnativecommunity.slider - -internal interface ReactSliderEventListener { - fun onSliderValueChange(value: Double, fromUser: Boolean) - - fun onSlidingStart(value: Double) - - fun onSlidingComplete(value: Double) -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt deleted file mode 100644 index d355a64b..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManager.kt +++ /dev/null @@ -1,173 +0,0 @@ -package com.reactnativecommunity.slider - -import android.content.Context -import android.view.View -import com.facebook.react.bridge.ReadableArray -import com.facebook.react.bridge.ReadableMap -import com.facebook.react.module.annotations.ReactModule -import com.facebook.react.uimanager.PixelUtil -import com.facebook.react.uimanager.SimpleViewManager -import com.facebook.react.uimanager.ThemedReactContext -import com.facebook.react.uimanager.UIManagerHelper -import com.facebook.react.uimanager.ViewManagerDelegate -import com.facebook.react.uimanager.annotations.ReactProp -import com.facebook.react.viewmanagers.RNCSliderManagerDelegate -import com.facebook.react.viewmanagers.RNCSliderManagerInterface -import com.facebook.yoga.YogaMeasureMode -import com.facebook.yoga.YogaMeasureOutput - -/** Manages instances of [ReactSlider]. */ -@ReactModule(name = ReactSliderManagerImpl.REACT_CLASS) -class ReactSliderManager : SimpleViewManager(), RNCSliderManagerInterface { - - private val delegate: ViewManagerDelegate = RNCSliderManagerDelegate(this) - - override fun getDelegate(): ViewManagerDelegate? = delegate - - override fun getName(): String = ReactSliderManagerImpl.REACT_CLASS - - override fun createViewInstance(context: ThemedReactContext): ReactSlider = - ReactSliderManagerImpl.createViewInstance(context) - - @ReactProp(name = "disabled", defaultBoolean = false) - override fun setDisabled(view: ReactSlider, disabled: Boolean) { - ReactSliderManagerImpl.setDisabled(view, disabled) - } - - @ReactProp(name = "value", defaultFloat = 0f) - override fun setValue(view: ReactSlider, value: Float) { - ReactSliderManagerImpl.setValue(view, value.toDouble()) - } - - @ReactProp(name = "minimumValue", defaultFloat = 0f) - override fun setMinimumValue(view: ReactSlider, value: Double) { - ReactSliderManagerImpl.setMinimumValue(view, value) - } - - @ReactProp(name = "maximumValue", defaultFloat = 0f) - override fun setMaximumValue(view: ReactSlider, value: Double) { - ReactSliderManagerImpl.setMaximumValue(view, value) - } - - @ReactProp(name = "step", defaultFloat = 0f) - override fun setStep(view: ReactSlider, value: Double) { - ReactSliderManagerImpl.setStep(view, value) - } - - @ReactProp(name = "thumbTintColor", customType = "Color") - override fun setThumbTintColor(view: ReactSlider, color: Int?) { - ReactSliderManagerImpl.setThumbTintColor(view, color) - } - - @ReactProp(name = "thumbSize", defaultFloat = 0f) - override fun setThumbSize(view: ReactSlider, size: Float) { - ReactSliderManagerImpl.setThumbSize(view, size) - } - - @ReactProp(name = "minimumTrackTintColor", customType = "Color") - override fun setMinimumTrackTintColor(view: ReactSlider, color: Int?) { - ReactSliderManagerImpl.setMinimumTrackTintColor(view, color) - } - - @ReactProp(name = "maximumTrackTintColor", customType = "Color") - override fun setMaximumTrackTintColor(view: ReactSlider, color: Int?) { - ReactSliderManagerImpl.setMaximumTrackTintColor(view, color) - } - - @ReactProp(name = "inverted", defaultBoolean = false) - override fun setInverted(view: ReactSlider, inverted: Boolean) { - ReactSliderManagerImpl.setInverted(view, inverted) - } - - @ReactProp(name = "accessibilityUnits") - override fun setAccessibilityUnits(view: ReactSlider, accessibilityUnits: String?) { - ReactSliderManagerImpl.setAccessibilityUnits(view, accessibilityUnits) - } - - @ReactProp(name = "accessibilityIncrements") - override fun setAccessibilityIncrements(view: ReactSlider, accessibilityIncrements: ReadableArray?) { - ReactSliderManagerImpl.setAccessibilityIncrements(view, accessibilityIncrements) - } - - @ReactProp(name = "lowerLimit") - override fun setLowerLimit(view: ReactSlider, value: Float) { - ReactSliderManagerImpl.setLowerLimit(view, value.toDouble()) - } - - @ReactProp(name = "upperLimit") - override fun setUpperLimit(view: ReactSlider, value: Float) { - ReactSliderManagerImpl.setUpperLimit(view, value.toDouble()) - } - - @ReactProp(name = "thumbImage") - override fun setThumbImage(view: ReactSlider, source: ReadableMap?) { - ReactSliderManagerImpl.setThumbImage(view, source) - } - - override fun setTestID(view: ReactSlider, value: String?) { - super.setTestId(view, value) - } - - override fun addEventEmitters(reactContext: ThemedReactContext, view: ReactSlider) { - view.setEventListener( - object : ReactSliderEventListener { - override fun onSliderValueChange(value: Double, fromUser: Boolean) { - if (!fromUser) return - val reactTag = view.id - UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) - ?.dispatchEvent(ReactSliderEvent(reactTag, value, true)) - } - - override fun onSlidingStart(value: Double) { - val reactTag = view.id - UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) - ?.dispatchEvent(ReactSlidingStartEvent(reactTag, value)) - } - - override fun onSlidingComplete(value: Double) { - val reactTag = view.id - UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag) - ?.dispatchEvent(ReactSlidingCompleteEvent(reactTag, value)) - } - }, - ) - } - - // these props are not available on Android, however we must override their setters - override fun setMinimumTrackImage(view: ReactSlider, readableMap: ReadableMap?) {} - - override fun setMaximumTrackImage(view: ReactSlider, readableMap: ReadableMap?) {} - - override fun setTrackImage(view: ReactSlider, value: ReadableMap?) {} - - override fun setTapToSeek(view: ReactSlider, value: Boolean) {} - - override fun setVertical(view: ReactSlider, value: Boolean) {} - - override fun measure( - context: Context, - localData: ReadableMap?, - props: ReadableMap?, - state: ReadableMap?, - width: Float, - widthMode: YogaMeasureMode, - height: Float, - heightMode: YogaMeasureMode, - attachmentsPositions: FloatArray?, - ): Long { - val view = ReactSlider(context, null) - val measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) - view.measure(measureSpec, measureSpec) - return YogaMeasureOutput.make( - PixelUtil.toDIPFromPixel(view.measuredWidth.toFloat()), - PixelUtil.toDIPFromPixel(view.measuredHeight.toFloat()), - ) - } - - override fun getExportedCustomBubblingEventTypeConstants(): Map? = - ReactSliderManagerImpl.getExportedCustomBubblingEventTypeConstants() - - override fun getExportedCustomDirectEventTypeConstants(): Map? = - ReactSliderManagerImpl.getExportedCustomDirectEventTypeConstants() - -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt deleted file mode 100644 index 9d8aac6f..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderManagerImpl.kt +++ /dev/null @@ -1,123 +0,0 @@ -package com.reactnativecommunity.slider - -import android.os.Build -import com.facebook.react.bridge.ReadableArray -import com.facebook.react.bridge.ReadableMap -import com.facebook.react.common.MapBuilder -import com.facebook.react.uimanager.ThemedReactContext - -object ReactSliderManagerImpl { - const val REACT_CLASS = "RNCSlider" - - @JvmStatic - fun createViewInstance(context: ThemedReactContext): ReactSlider { - return ReactSlider(context, null) - } - - @JvmStatic - fun setValue(view: ReactSlider, value: Double) { - if (!view.isSliding) { - view.setValue(value) - if (view.isAccessibilityFocused && Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) { - view.setupAccessibility(value.toInt()) - } - } - } - - @JvmStatic - fun setMinimumValue(view: ReactSlider, value: Double) { - view.setMinValue(value) - } - - @JvmStatic - fun setMaximumValue(view: ReactSlider, value: Double) { - view.setMaxValue(value) - } - - @JvmStatic - fun setLowerLimit(view: ReactSlider, value: Double) { - view.setLowerLimit(value) - } - - @JvmStatic - fun setUpperLimit(view: ReactSlider, value: Double) { - view.setUpperLimit(value) - } - - @JvmStatic - fun setStep(view: ReactSlider, value: Double) { - view.setStep(value) - } - - @JvmStatic - fun setDisabled(view: ReactSlider, disabled: Boolean) { - view.applyDisabledProp(disabled) - } - - @JvmStatic - fun setThumbTintColor(view: ReactSlider, color: Int?) { - view.setThumbTintColor(color) - } - - @JvmStatic - fun setMinimumTrackTintColor(view: ReactSlider, color: Int?) { - view.setMinimumTrackTintColor(color) - } - - @JvmStatic - fun setThumbImage(view: ReactSlider, source: ReadableMap?) { - val uri = source?.getString("uri") - view.setThumbImageUri(uri) - } - - @JvmStatic - fun setThumbSize(view: ReactSlider, size: Float) { - view.setThumbSize(size) - } - - @JvmStatic - fun setMaximumTrackTintColor(view: ReactSlider, color: Int?) { - view.setMaximumTrackTintColor(color) - } - - @JvmStatic - fun setInverted(view: ReactSlider, inverted: Boolean) { - view.setInverted(inverted) - } - - @JvmStatic - fun setAccessibilityUnits(view: ReactSlider, accessibilityUnits: String?) { - view.setAccessibilityUnits(accessibilityUnits) - } - - @JvmStatic - fun setAccessibilityIncrements(view: ReactSlider, accessibilityIncrements: ReadableArray?) { - if (accessibilityIncrements == null) { - return - } - val objectList = accessibilityIncrements.toArrayList() - val stringList = ArrayList(objectList.size) - for (item in objectList) { - stringList.add(item as String) - } - view.setAccessibilityIncrements(stringList) - } - - @JvmStatic - fun getExportedCustomBubblingEventTypeConstants(): Map { - return MapBuilder.of( - ReactSliderEvent.EVENT_NAME, - MapBuilder.of("registrationName", ReactSliderEvent.EVENT_NAME), - ) - } - - @JvmStatic - fun getExportedCustomDirectEventTypeConstants(): Map { - return MapBuilder.of( - ReactSlidingStartEvent.EVENT_NAME, - MapBuilder.of("registrationName", ReactSlidingStartEvent.EVENT_NAME), - ReactSlidingCompleteEvent.EVENT_NAME, - MapBuilder.of("registrationName", ReactSlidingCompleteEvent.EVENT_NAME), - ) - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.kt deleted file mode 100644 index 60aa6324..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSliderPackage.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.reactnativecommunity.slider - -import com.facebook.react.ReactPackage -import com.facebook.react.bridge.JavaScriptModule -import com.facebook.react.bridge.NativeModule -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.uimanager.ViewManager - -class ReactSliderPackage : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List { - return emptyList() - } - - // Deprecated from RN 0.47 - fun createJSModules(): List> { - return emptyList() - } - - override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return listOf(ReactSliderManager()) - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.kt deleted file mode 100644 index a54441b3..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingCompleteEvent.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.reactnativecommunity.slider - -import com.facebook.react.bridge.Arguments -import com.facebook.react.bridge.WritableMap -import com.facebook.react.uimanager.events.Event - -/** Event emitted when the user finishes dragging the slider. */ -class ReactSlidingCompleteEvent( - viewId: Int, - private val value: Double, -) : Event(viewId) { - - override fun getEventName(): String = EVENT_NAME - - override fun getCoalescingKey(): Short = 0 - - override fun canCoalesce(): Boolean = false - - override fun getEventData(): WritableMap? = serializeEventData() - - private fun serializeEventData(): WritableMap { - val eventData = Arguments.createMap() - eventData.putInt("target", viewTag) - eventData.putDouble("value", value) - return eventData - } - - companion object { - const val EVENT_NAME = "onRNCSliderSlidingComplete" - } -} diff --git a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.kt b/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.kt deleted file mode 100644 index 7cc1fe65..00000000 --- a/package/android/src/main/java/com/reactnativecommunity/slider/ReactSlidingStartEvent.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.reactnativecommunity.slider - -import com.facebook.react.bridge.Arguments -import com.facebook.react.bridge.WritableMap -import com.facebook.react.uimanager.events.Event - -/** Event emitted when the user starts dragging the slider. */ -class ReactSlidingStartEvent( - viewId: Int, - private val value: Double, -) : Event(viewId) { - - override fun getEventName(): String = EVENT_NAME - - override fun getCoalescingKey(): Short = 0 - - override fun canCoalesce(): Boolean = false - - override fun getEventData(): WritableMap? = serializeEventData() - - private fun serializeEventData(): WritableMap { - val eventData = Arguments.createMap() - eventData.putInt("target", viewTag) - eventData.putDouble("value", value) - return eventData - } - - companion object { - const val EVENT_NAME = "onRNCSliderSlidingStart" - } -} diff --git a/package/android/src/main/jni/CMakeLists.txt b/package/android/src/main/jni/CMakeLists.txt index 6fe63910..32493c68 100644 --- a/package/android/src/main/jni/CMakeLists.txt +++ b/package/android/src/main/jni/CMakeLists.txt @@ -1,93 +1,44 @@ cmake_minimum_required(VERSION 3.13) -set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_VERBOSE_MAKEFILE on) -set(LIB_LITERAL RNCSlider) +include(${REACT_ANDROID_DIR}/../ReactCommon/cmake-utils/react-native-flags.cmake) + +set(LIB_LITERAL Slider) set(LIB_TARGET_NAME react_codegen_${LIB_LITERAL}) set(LIB_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) -set(LIB_COMMON_DIR ${LIB_ANDROID_DIR}/../common/cpp) -set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/build/generated/source/codegen/jni) -set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_LITERAL}) +set(LIB_GENERATED_DIR ${LIB_ANDROID_DIR}/build/generated/source/codegen/jni) +set(LIB_COMPONENTS_DIR ${LIB_GENERATED_DIR}/react/renderer/components/${LIB_LITERAL}) -file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS *.cpp ${LIB_COMMON_DIR}/react/renderer/components/${LIB_LITERAL}/*.cpp) -file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_ANDROID_GENERATED_JNI_DIR}/*.cpp ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp) +file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_GENERATED_DIR}/*.cpp ${LIB_COMPONENTS_DIR}/*.cpp) add_library( ${LIB_TARGET_NAME} - SHARED - ${LIB_CUSTOM_SRCS} + OBJECT ${LIB_CODEGEN_SRCS} ) target_include_directories( ${LIB_TARGET_NAME} PUBLIC - . - ${LIB_COMMON_DIR} - ${LIB_ANDROID_GENERATED_JNI_DIR} - ${LIB_ANDROID_GENERATED_COMPONENTS_DIR} -) - -# https://github.com/react-native-community/discussions-and-proposals/discussions/816 -# This if-then-else can be removed once this library does not support version below 0.76 -if (REACTNATIVE_MERGED_SO) - target_link_libraries( - ${LIB_TARGET_NAME} - fbjni - jsi - reactnative - ) -else() - target_link_libraries( - ${LIB_TARGET_NAME} - fbjni - folly_runtime - glog - jsi - react_codegen_rncore - react_debug - react_render_componentregistry - react_render_core - react_render_debug - react_render_graphics - react_render_imagemanager - react_render_mapbuffer - react_utils - react_nativemodule_core - rrc_image - turbomodulejsijni - rrc_view - yoga - ) -endif() - -if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 81) - target_compile_reactnative_options(${LIB_TARGET_NAME} PUBLIC) -else() - target_compile_options( - ${LIB_TARGET_NAME} - PRIVATE - -fexceptions - -frtti - -std=c++20 - -Wall - -Wpedantic - -Wno-gnu-zero-variadic-macro-arguments - ) -endif() - -target_compile_options( - ${LIB_TARGET_NAME} - PRIVATE - -DLOG_TAG=\"ReactNative\" - -fexceptions - -frtti - -std=c++20 - -Wall + ${CMAKE_CURRENT_SOURCE_DIR} + ${LIB_GENERATED_DIR} + ${LIB_COMPONENTS_DIR} ) target_include_directories( ${CMAKE_PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ${LIB_GENERATED_DIR} + ${LIB_COMPONENTS_DIR} ) + +target_link_libraries( + ${LIB_TARGET_NAME} + fbjni + jsi + reactnative +) + +target_compile_reactnative_options(${LIB_TARGET_NAME} PRIVATE) diff --git a/package/android/src/main/jni/RNCSlider.h b/package/android/src/main/jni/Slider.h similarity index 68% rename from package/android/src/main/jni/RNCSlider.h rename to package/android/src/main/jni/Slider.h index f0c0e9f5..25f52bdf 100644 --- a/package/android/src/main/jni/RNCSlider.h +++ b/package/android/src/main/jni/Slider.h @@ -3,16 +3,14 @@ #include #include #include -#include namespace facebook { namespace react { JSI_EXPORT -std::shared_ptr RNCSlider_ModuleProvider( +std::shared_ptr Slider_ModuleProvider( const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); } // namespace react } // namespace facebook - diff --git a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderComponentDescriptor.h b/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderComponentDescriptor.h deleted file mode 100644 index 8bc649ad..00000000 --- a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderComponentDescriptor.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include -#include "RNCSliderMeasurementsManager.h" - -namespace facebook { - namespace react { - - class RNCSliderComponentDescriptor final - : public ConcreteComponentDescriptor { -#ifdef ANDROID - public: - RNCSliderComponentDescriptor(const ComponentDescriptorParameters ¶meters) - : ConcreteComponentDescriptor(parameters), measurementsManager_( - std::make_shared(contextContainer_)) {} - - void adopt(ShadowNode &shadowNode) const override { - ConcreteComponentDescriptor::adopt(shadowNode); - - - auto &rncSliderShadowNode = - static_cast(shadowNode); - - // `RNCSliderShadowNode` uses `RNCSliderMeasurementsManager` to - // provide measurements to Yoga. - rncSliderShadowNode.setSliderMeasurementsManager( - measurementsManager_); - - // All `RNCSliderShadowNode`s must have leaf Yoga nodes with properly - // setup measure function. - rncSliderShadowNode.enableMeasurement(); - } - private: - const std::shared_ptr measurementsManager_; -#else - public: - RNCSliderComponentDescriptor(const ComponentDescriptorParameters ¶meters) - : ConcreteComponentDescriptor(parameters) {} -#endif - }; - - } -} diff --git a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderMeasurementsManager.cpp b/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderMeasurementsManager.cpp deleted file mode 100644 index fada95c9..00000000 --- a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderMeasurementsManager.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifdef ANDROID -#include "RNCSliderMeasurementsManager.h" - -#include -#include -#include - -using namespace facebook::jni; - -namespace facebook::react { - -Size RNCSliderMeasurementsManager::measure( - SurfaceId surfaceId, - LayoutConstraints layoutConstraints) const { - { - std::scoped_lock lock(mutex_); - if (hasBeenMeasured_) { - return cachedMeasurement_; - } - } - - const jni::global_ref& fabricUIManager = - contextContainer_->at>("FabricUIManager"); - - static auto measure = - jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") - ->getMethod("measure"); - - auto minimumSize = layoutConstraints.minimumSize; - auto maximumSize = layoutConstraints.maximumSize; - - local_ref componentName = make_jstring("RNCSlider"); - - auto measurement = yogaMeassureToSize(measure( - fabricUIManager, - surfaceId, - componentName.get(), - nullptr, - nullptr, - nullptr, - minimumSize.width, - maximumSize.width, - minimumSize.height, - maximumSize.height)); - - std::scoped_lock lock(mutex_); - cachedMeasurement_ = measurement; - hasBeenMeasured_ = true; - return measurement; -} - -} -#endif diff --git a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderMeasurementsManager.h b/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderMeasurementsManager.h deleted file mode 100644 index adcb27b5..00000000 --- a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderMeasurementsManager.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifdef ANDROID -#pragma once - -#include -#include -#include - -namespace facebook::react { - - class RNCSliderMeasurementsManager { - public: - RNCSliderMeasurementsManager( - const std::shared_ptr &contextContainer) - : contextContainer_(contextContainer) {} - - Size measure(SurfaceId surfaceId, LayoutConstraints layoutConstraints) const; - - private: - const std::shared_ptr contextContainer_; - mutable std::mutex mutex_; - mutable bool hasBeenMeasured_ = false; - mutable Size cachedMeasurement_{}; - - }; -} -#endif diff --git a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderShadowNode.cpp b/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderShadowNode.cpp deleted file mode 100644 index d10cb078..00000000 --- a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderShadowNode.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "RNCSliderShadowNode.h" -#include "RNCSliderMeasurementsManager.h" - -namespace facebook { - namespace react { - - extern const char RNCSliderComponentName[] = "RNCSlider"; - -#ifdef ANDROID - void RNCSliderShadowNode::setSliderMeasurementsManager( - const std::shared_ptr & - measurementsManager) { - ensureUnsealed(); - measurementsManager_ = measurementsManager; - } - -#pragma mark - LayoutableShadowNode - - Size RNCSliderShadowNode::measureContent( - const LayoutContext & /*layoutContext*/, - const LayoutConstraints &layoutConstraints) const { - return measurementsManager_->measure(getSurfaceId(), layoutConstraints); - } -#endif - - } -} diff --git a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderShadowNode.h b/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderShadowNode.h deleted file mode 100644 index b30099fe..00000000 --- a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderShadowNode.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "RNCSliderMeasurementsManager.h" - -namespace facebook { - namespace react { - - JSI_EXPORT extern const char RNCSliderComponentName[]; - -/* - * `ShadowNode` for component. - */ - class JSI_EXPORT RNCSliderShadowNode final - : public ConcreteViewShadowNode< - RNCSliderComponentName, - RNCSliderProps, - RNCSliderEventEmitter, - RNCSliderState> { - public: - using ConcreteViewShadowNode::ConcreteViewShadowNode; - -#ifdef ANDROID - void setSliderMeasurementsManager( - const std::shared_ptr &measurementsManager); - -#pragma mark - LayoutableShadowNode - - Size measureContent( - const LayoutContext &layoutContext, - const LayoutConstraints &layoutConstraints) const override; - - private: - std::shared_ptr measurementsManager_; -#endif - - }; - - } -} diff --git a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderState.h b/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderState.h deleted file mode 100644 index 13cdf8e5..00000000 --- a/package/common/cpp/react/renderer/components/RNCSlider/RNCSliderState.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#ifdef ANDROID -#include -#include -#include -#endif - -namespace facebook { -namespace react { - -class RNCSliderState { -public: - RNCSliderState() = default; - -#ifdef ANDROID - RNCSliderState(RNCSliderState const &previousState, folly::dynamic data){}; - folly::dynamic getDynamic() const { - return {}; - }; - MapBuffer getMapBuffer() const { - return MapBufferBuilder::EMPTY(); - }; -#endif -}; - -} -} diff --git a/package/ios/RNCSlider.h b/package/ios/RNCSlider.h index aa9d1855..41b3dfbe 100644 --- a/package/ios/RNCSlider.h +++ b/package/ios/RNCSlider.h @@ -2,11 +2,11 @@ #import -@interface RNCSlider : UISlider +@interface Slider : UISlider -@property (nonatomic, copy) RCTBubblingEventBlock onRNCSliderValueChange; -@property (nonatomic, copy) RCTBubblingEventBlock onRNCSliderSlidingStart; -@property (nonatomic, copy) RCTBubblingEventBlock onRNCSliderSlidingComplete; +@property (nonatomic, copy) RCTBubblingEventBlock onSliderValueChange; +@property (nonatomic, copy) RCTBubblingEventBlock onSliderSlidingStart; +@property (nonatomic, copy) RCTBubblingEventBlock onSliderSlidingComplete; @property (nonatomic, assign) float step; @property (nonatomic, assign) float lastValue; diff --git a/package/ios/RNCSlider.m b/package/ios/RNCSlider.m index 8bc1c248..a902db11 100644 --- a/package/ios/RNCSlider.m +++ b/package/ios/RNCSlider.m @@ -1,6 +1,6 @@ -#import "RNCSlider.h" +#import "Slider.h" -@implementation RNCSlider +@implementation Slider { float _unclippedValue; bool _minimumTrackImageSet; diff --git a/package/ios/RNCSliderComponentView.h b/package/ios/RNCSliderComponentView.h index 3bb041d7..7be1caa6 100644 --- a/package/ios/RNCSliderComponentView.h +++ b/package/ios/RNCSliderComponentView.h @@ -1,17 +1,17 @@ #import #import -#import "RNCSlider.h" +#import "Slider.h" NS_ASSUME_NONNULL_BEGIN typedef void (^RNCLoadImageCompletionBlock)(NSError * _Nullable error, UIImage * _Nullable image); typedef void (^RNCLoadImageFailureBlock)(); -@interface RNCSliderComponentView : RCTViewComponentView +@interface SliderComponentView : RCTViewComponentView -@property (nonatomic, copy) RCTBubblingEventBlock onRNCSliderValueChange; -@property (nonatomic, copy) RCTBubblingEventBlock onRNCSliderSlidingStart; -@property (nonatomic, copy) RCTBubblingEventBlock onRNCSliderSlidingComplete; +@property (nonatomic, copy) RCTBubblingEventBlock onSliderValueChange; +@property (nonatomic, copy) RCTBubblingEventBlock onSliderSlidingStart; +@property (nonatomic, copy) RCTBubblingEventBlock onSliderSlidingComplete; @property (nonatomic, assign) float step; @property (nonatomic, assign) float lastValue; diff --git a/package/ios/RNCSliderComponentView.mm b/package/ios/RNCSliderComponentView.mm index 605487a8..7e865b6e 100644 --- a/package/ios/RNCSliderComponentView.mm +++ b/package/ios/RNCSliderComponentView.mm @@ -1,34 +1,34 @@ -#import "RNCSliderComponentView.h" +#import "SliderComponentView.h" #import -#import -#import -#import -#import +#import +#import +#import +#import #import #import "RCTImagePrimitivesConversions.h" #import #import "RCTFabricComponentsPlugins.h" -#import "RNCSlider.h" +#import "Slider.h" using namespace facebook::react; -@interface RNCSliderComponentView () +@interface SliderComponentView () @end -@implementation RNCSliderComponentView +@implementation SliderComponentView { - RNCSlider *slider; + Slider *slider; UIImage *_image; BOOL _isSliding; } + (ComponentDescriptorProvider)componentDescriptorProvider { - return concreteComponentDescriptorProvider(); + return concreteComponentDescriptorProvider(); } + (BOOL)shouldBeRecycled { @@ -38,9 +38,9 @@ + (BOOL)shouldBeRecycled { - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); + static const auto defaultProps = std::make_shared(); _props = defaultProps; - slider = [[RNCSlider alloc] initWithFrame:self.bounds]; + slider = [[Slider alloc] initWithFrame:self.bounds]; [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged]; [slider addTarget:self action:@selector(sliderTouchStart:) @@ -62,10 +62,10 @@ - (instancetype)initWithFrame:(CGRect)frame } - (void)tapHandler:(UITapGestureRecognizer *)gesture { - if ([gesture.view class] != [RNCSlider class]) { + if ([gesture.view class] != [Slider class]) { return; } - RNCSlider *slider = (RNCSlider *)gesture.view; + Slider *slider = (Slider *)gesture.view; slider.isSliding = _isSliding; // Ignore this tap if in the middle of a slide. @@ -98,37 +98,37 @@ - (void)tapHandler:(UITapGestureRecognizer *)gesture { [slider setValue:[slider discreteValue:value] animated: YES]; - std::dynamic_pointer_cast(_eventEmitter) - ->onRNCSliderSlidingStart(RNCSliderEventEmitter::OnRNCSliderSlidingStart{.value = static_cast(slider.lastValue)}); + std::dynamic_pointer_cast(_eventEmitter) + ->onSliderSlidingStart(SliderEventEmitter::OnSliderSlidingStart{.value = static_cast(slider.lastValue)}); // Trigger onValueChange to address https://github.com/react-native-community/react-native-slider/issues/212 - std::dynamic_pointer_cast(_eventEmitter) - ->onRNCSliderValueChange(RNCSliderEventEmitter::OnRNCSliderValueChange{.value = static_cast(slider.value)}); + std::dynamic_pointer_cast(_eventEmitter) + ->onSliderValueChange(SliderEventEmitter::OnSliderValueChange{.value = static_cast(slider.value)}); - std::dynamic_pointer_cast(_eventEmitter) - ->onRNCSliderSlidingComplete(RNCSliderEventEmitter::OnRNCSliderSlidingComplete{.value = static_cast(slider.value)}); + std::dynamic_pointer_cast(_eventEmitter) + ->onSliderSlidingComplete(SliderEventEmitter::OnSliderSlidingComplete{.value = static_cast(slider.value)}); } -- (void)sliderValueChanged:(RNCSlider *)sender +- (void)sliderValueChanged:(Slider *)sender { [self RNCSendSliderEvent:sender withContinuous:YES isSlidingStart:NO]; } -- (void)sliderTouchStart:(RNCSlider *)sender +- (void)sliderTouchStart:(Slider *)sender { [self RNCSendSliderEvent:sender withContinuous:NO isSlidingStart:YES]; _isSliding = YES; sender.isSliding = YES; } -- (void)sliderTouchEnd:(RNCSlider *)sender +- (void)sliderTouchEnd:(Slider *)sender { [self RNCSendSliderEvent:sender withContinuous:NO isSlidingStart:NO]; sender.isSliding = NO; _isSliding = NO; } -- (void)RNCSendSliderEvent:(RNCSlider *)sender withContinuous:(BOOL)continuous isSlidingStart:(BOOL)isSlidingStart +- (void)RNCSendSliderEvent:(Slider *)sender withContinuous:(BOOL)continuous isSlidingStart:(BOOL)isSlidingStart { float value = [sender discreteValue:sender.value]; @@ -146,17 +146,17 @@ - (void)RNCSendSliderEvent:(RNCSlider *)sender withContinuous:(BOOL)continuous i if (continuous) { if (sender.lastValue != value) { - std::dynamic_pointer_cast(_eventEmitter) - ->onRNCSliderValueChange(RNCSliderEventEmitter::OnRNCSliderValueChange{.value = static_cast(value)}); + std::dynamic_pointer_cast(_eventEmitter) + ->onSliderValueChange(SliderEventEmitter::OnSliderValueChange{.value = static_cast(value)}); } } else { if (!isSlidingStart) { - std::dynamic_pointer_cast(_eventEmitter) - ->onRNCSliderSlidingComplete(RNCSliderEventEmitter::OnRNCSliderSlidingComplete{.value = static_cast(value)}); + std::dynamic_pointer_cast(_eventEmitter) + ->onSliderSlidingComplete(SliderEventEmitter::OnSliderSlidingComplete{.value = static_cast(value)}); } if (isSlidingStart) { - std::dynamic_pointer_cast(_eventEmitter) - ->onRNCSliderSlidingStart(RNCSliderEventEmitter::OnRNCSliderSlidingStart{.value = static_cast(value)}); + std::dynamic_pointer_cast(_eventEmitter) + ->onSliderSlidingStart(SliderEventEmitter::OnSliderSlidingStart{.value = static_cast(value)}); } } @@ -165,8 +165,8 @@ - (void)RNCSendSliderEvent:(RNCSlider *)sender withContinuous:(BOOL)continuous i - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps { - const auto &oldScreenProps = *std::static_pointer_cast(_props); - const auto &newScreenProps = *std::static_pointer_cast(props); + const auto &oldScreenProps = *std::static_pointer_cast(_props); + const auto &newScreenProps = *std::static_pointer_cast(props); if (oldScreenProps.value != newScreenProps.value) { if (!slider.isSliding) { @@ -303,7 +303,7 @@ - (void)setInverted:(BOOL)inverted @end -Class RNCSliderCls(void) +Class SliderCls(void) { - return RNCSliderComponentView.class; + return SliderComponentView.class; } diff --git a/package/package.json b/package/package.json index 63179687..6dd961a1 100644 --- a/package/package.json +++ b/package/package.json @@ -9,7 +9,6 @@ "access": "public" }, "main": "dist/Slider.js", - "types": "typings/index.d.ts", "keywords": [ "react-native", "react native", @@ -17,7 +16,7 @@ ], "scripts": { "prepare": "babel --extensions \".ts,.tsx\" --out-dir dist src", - "lint": "npx eslint src __test__", + "lint": "npx eslint src", "test": "jest", "prepack": "npx copyfiles \"./../README.md\" ./README.md" }, @@ -65,21 +64,21 @@ ] }, "prettier": { - "singleQuote": true, + "singleQuote": false, "trailingComma": "all", "bracketSpacing": false, "jsxBracketSameLine": true }, "codegenConfig": { - "name": "RNCSlider", + "name": "Slider", "type": "components", "jsSrcsDir": "src", "android": { - "javaPackageName": "com.reactnativecommunity.slider" + "javaPackageName": "com.callstack.slider" }, "ios": { "componentProvider": { - "RNCSlider": "RNCSliderComponentView" + "Slider": "SliderComponentView" } } } diff --git a/package/react-native.config.js b/package/react-native.config.js index ffcb1e61..97d077e1 100644 --- a/package/react-native.config.js +++ b/package/react-native.config.js @@ -2,8 +2,8 @@ module.exports = { dependency: { platforms: { android: { - libraryName: 'RNCSlider', - componentDescriptors: ['RNCSliderComponentDescriptor'], + libraryName: 'Slider', + componentDescriptors: ['SliderViewComponentDescriptor'], cmakeListsPath: 'src/main/jni/CMakeLists.txt', }, }, diff --git a/package/src/RNCSliderNativeComponent.ts b/package/src/RNCSliderNativeComponent.ts deleted file mode 100644 index 62f97abd..00000000 --- a/package/src/RNCSliderNativeComponent.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type {ColorValue, HostComponent, ViewProps} from 'react-native'; -import {ImageSource, codegenNativeComponent} from 'react-native'; -import type { - Float, - WithDefault, - DirectEventHandler, - BubblingEventHandler, - Double, -} from 'react-native/Libraries/Types/CodegenTypes'; - -type Event = Readonly<{ - value: Float; - fromUser?: boolean; -}>; - -export interface NativeProps extends ViewProps { - accessibilityUnits?: string; - accessibilityIncrements?: ReadonlyArray; - disabled?: WithDefault; - inverted?: WithDefault; - vertical?: WithDefault; - tapToSeek?: WithDefault; - maximumTrackImage?: ImageSource; - maximumTrackTintColor?: ColorValue; - maximumValue?: Double; - minimumTrackImage?: ImageSource; - minimumTrackTintColor?: ColorValue; - minimumValue?: Double; - onChange?: BubblingEventHandler; - onRNCSliderSlidingStart?: DirectEventHandler; - onRNCSliderSlidingComplete?: DirectEventHandler; - onRNCSliderValueChange?: BubblingEventHandler; - step?: Double; - testID?: string; - thumbImage?: ImageSource; - thumbTintColor?: ColorValue; - thumbSize?: Float; - trackImage?: ImageSource; - value?: Float; - lowerLimit?: Float; - upperLimit?: Float; -} - -export default codegenNativeComponent('RNCSlider', { - interfaceOnly: true, -}) as HostComponent; diff --git a/package/src/RNCSliderNativeComponent.web.tsx b/package/src/RNCSliderNativeComponent.web.tsx index e11e1853..3587fdaa 100644 --- a/package/src/RNCSliderNativeComponent.web.tsx +++ b/package/src/RNCSliderNativeComponent.web.tsx @@ -1,4 +1,4 @@ -import React, {RefObject, useCallback} from 'react'; +import React, {RefObject, useCallback} from "react"; import { Animated, View, @@ -8,10 +8,10 @@ import { LayoutChangeEvent, Image, ImageSourcePropType, -} from 'react-native'; +} from "react-native"; //@ts-ignore -import type {ImageSource} from 'react-native/Libraries/Image/ImageSource'; -import {constants} from './utils/constants'; +import type {ImageSource} from "react-native/Libraries/Image/ImageSource"; +import {constants} from "./utils/constants"; type Event = Readonly<{ nativeEvent: { @@ -58,9 +58,9 @@ const RCTSliderWebComponent = React.forwardRef( lowerLimit = 0, upperLimit = 0, step = 1, - minimumTrackTintColor = '#009688', - maximumTrackTintColor = '#939393', - thumbTintColor = '#009688', + minimumTrackTintColor = "#009688", + maximumTrackTintColor = "#939393", + thumbTintColor = "#009688", thumbStyle = {}, style = {}, inverted = false, @@ -189,16 +189,16 @@ const RCTSliderWebComponent = React.forwardRef( } }; //@ts-ignore - window.addEventListener('resize', invalidateContainerPosition); + window.addEventListener("resize", invalidateContainerPosition); //@ts-ignore - document.addEventListener('scroll', onDocumentScroll, {capture: true}); + document.addEventListener("scroll", onDocumentScroll, {capture: true}); return () => { //@ts-ignore - window.removeEventListener('resize', invalidateContainerPosition); + window.removeEventListener("resize", invalidateContainerPosition); //@ts-ignore - document.removeEventListener('scroll', onDocumentScroll, { + document.removeEventListener("scroll", onDocumentScroll, { capture: true, }); }; @@ -208,9 +208,9 @@ const RCTSliderWebComponent = React.forwardRef( { flexGrow: 1, flexShrink: 1, - flexBasis: 'auto', - flexDirection: 'row', - alignItems: 'center', + flexBasis: "auto", + flexDirection: "row", + alignItems: "center", }, style, ] as ViewStyle[]; @@ -218,7 +218,7 @@ const RCTSliderWebComponent = React.forwardRef( const trackStyle = { height: trackHeight, borderRadius: trackHeight / 2, - userSelect: 'none', + userSelect: "none", }; const minimumTrackStyle = { @@ -241,7 +241,7 @@ const RCTSliderWebComponent = React.forwardRef( backgroundColor: thumbTintColor, zIndex: 1, borderRadius: thumbSize / 2, - overflow: 'hidden', + overflow: "hidden", }, thumbStyle, ] as ViewStyle[]; @@ -316,10 +316,10 @@ const RCTSliderWebComponent = React.forwardRef( const accessibilityActions = (event: any) => { const tenth = (maximumValue - minimumValue) / 10; switch (event.nativeEvent.actionName) { - case 'increment': + case "increment": updateValue(value + (step || tenth)); break; - case 'decrement': + case "decrement": updateValue(value - (step || tenth)); break; } @@ -346,12 +346,12 @@ const RCTSliderWebComponent = React.forwardRef( } }} accessibilityActions={[ - {name: 'increment', label: 'increment'}, - {name: 'decrement', label: 'decrement'}, + {name: "increment", label: "increment"}, + {name: "decrement", label: "decrement"}, ]} onAccessibilityAction={accessibilityActions} accessible={true} - accessibilityRole={'adjustable'} + accessibilityRole={"adjustable"} style={containerStyle} {...others} // NOTE: gesture responders should all fall _after_ the {...others} @@ -366,7 +366,7 @@ const RCTSliderWebComponent = React.forwardRef( {thumbImage !== undefined ? ( ) : null} @@ -387,12 +387,12 @@ function calculatePrecision( } else { // Calculate the number of decimals we can encounter in the results const decimals = [minimumValue, maximumValue, step].map( - (value) => ((value + '').split('.').pop() || '').length, + (value) => ((value + "").split(".").pop() || "").length, ); return Math.max(...decimals); } } -RCTSliderWebComponent.displayName = 'RTCSliderWebComponent'; +RCTSliderWebComponent.displayName = "RTCSliderWebComponent"; export default RCTSliderWebComponent; diff --git a/package/src/Slider.tsx b/package/src/Slider.tsx index c452ef9c..9fbf44c7 100644 --- a/package/src/Slider.tsx +++ b/package/src/Slider.tsx @@ -1,356 +1,61 @@ -import React, {useEffect, useState} from 'react'; +import React, {FunctionComponent, useCallback, useMemo} from "react"; import { - Image, Platform, - AccessibilityActionEvent, - ViewProps, - ViewStyle, - ColorValue, - NativeSyntheticEvent, - StyleProp, - View, - ImageSource, - ImageSourcePropType, -} from 'react-native'; -import RCTSliderNativeComponent from './index'; - -import type {FC, Ref} from 'react'; -import {MarkerProps} from './components/TrackMark'; -import {StepsIndicator} from './components/StepsIndicator'; -import {styles} from './utils/styles'; -import {constants} from './utils/constants'; - -type Event = NativeSyntheticEvent< - Readonly<{ - value: number; - /** - * Android Only. - */ - fromUser?: boolean; - }> ->; - -type WindowsProps = Readonly<{ - /** - * If true the slider will be inverted. - * Default value is false. - */ - vertical?: boolean; -}>; - -type IOSProps = Readonly<{ - /** - * Assigns a single image for the track. Only static images are supported. - * The center pixel of the image will be stretched to fill the track. - */ - trackImage?: ImageSource; - - /** - * Assigns a minimum track image. Only static images are supported. The - * rightmost pixel of the image will be stretched to fill the track. - */ - minimumTrackImage?: ImageSource; - - /** - * Assigns a maximum track image. Only static images are supported. The - * leftmost pixel of the image will be stretched to fill the track. - */ - maximumTrackImage?: ImageSource; - - /** - * Permits tapping on the slider track to set the thumb position. - * Defaults to false on iOS. No effect on Android or Windows. - */ - tapToSeek?: boolean; -}>; - -type Props = ViewProps & - IOSProps & - WindowsProps & - Readonly<{ - /** - * Used to style and layout the `Slider`. See `StyleSheet.js` and - * `DeprecatedViewStylePropTypes.js` for more info. - */ - style?: StyleProp; - - /** - * Write-only property representing the value of the slider. - * Can be used to programmatically control the position of the thumb. - * Entered once at the beginning still acts as an initial value. - * The value should be between minimumValue and maximumValue, - * which default to 0 and 1 respectively. - * Default value is 0. - * - * This is not a controlled component, you don't need to update the - * value during dragging. - */ - value?: number; - - /** - * Step value of the slider. The value should be - * between 0 and (maximumValue - minimumValue). - * Default value is 0. - */ - step?: number; - - /** - * Initial minimum value of the slider. Default value is 0. - */ - minimumValue?: number; - - /** - * Initial maximum value of the slider. Default value is 1. - */ - maximumValue?: number; - - /** - * The lower limit value of the slider. The user won't be able to slide below this limit. - */ - lowerLimit?: number; - - /** - * The upper limit value of the slider. The user won't be able to slide above this limit. - */ - upperLimit?: number; - - /** - * The color used for the track to the left of the button. - * Overrides the default blue gradient image on iOS. - */ - minimumTrackTintColor?: ColorValue; - - /** - * The color used for the track to the right of the button. - * Overrides the default blue gradient image on iOS. - */ - maximumTrackTintColor?: ColorValue; - /** - * The color used to tint the default thumb images on iOS, or the - * color of the foreground switch grip on Android. - */ - thumbTintColor?: ColorValue; - - /** - * If true the user won't be able to move the slider. - * Default value is false. - */ - disabled?: boolean; - - /** - * Callback continuously called while the user is dragging the slider. - */ - onValueChange?: (_value: number) => void; - - /** - * Callback that is called when the user touches the slider, - * regardless if the value has changed. The current value is passed - * as an argument to the callback handler. - */ - onSlidingStart?: (_value: number) => void; - - /** - * Callback that is called when the user releases the slider, - * regardless if the value has changed. The current value is passed - * as an argument to the callback handler. - */ - onSlidingComplete?: (_value: number) => void; - - /** - * Used to locate this view in UI automation tests. - */ - testID?: string; - - /** - * Sets an image for the thumb. Only static images are supported. - */ - thumbImage?: ImageSource; - - /** - * Sets the size (width and height) of the thumb. - * If `thumbImage` is provided, it will be scaled to this size. - */ - thumbSize?: number; - - /** - * If true the slider will be inverted. - * Default value is false. - */ - inverted?: boolean; - - /** - * Component to be rendered for each step indicator. - */ - StepMarker?: FC; - - /** - * - */ - renderStepNumber?: boolean; - - /** - * A string of one or more words to be announced by the screen reader. - * Otherwise, it will announce the value as a percentage. - * Requires passing a value to `accessibilityIncrements` to work correctly. - * Should be a plural word, as singular units will be handled. - */ - accessibilityUnits?: string; - - /** - * An array of values that represent the different increments displayed - * by the slider. All the values passed into this prop must be strings. - * Requires passing a value to `accessibilityUnits` to work correctly. - * The number of elements must be the same as `maximumValue`. - */ - accessibilityIncrements?: Array; - }>; - -const SliderComponent = ( - { - onValueChange, - onSlidingStart, - onSlidingComplete, - onAccessibilityAction, - value = constants.SLIDER_DEFAULT_INITIAL_VALUE, - minimumValue = 0, - maximumValue = 1, - step = 0, - inverted = false, - tapToSeek = false, - lowerLimit = Platform.select({ - web: minimumValue, - default: constants.LIMIT_MIN_VALUE, - }), - upperLimit = Platform.select({ - web: maximumValue, - default: constants.LIMIT_MAX_VALUE, - }), - ...props - }: Props, - forwardedRef?: Ref, -) => { - const [currentValue, setCurrentValue] = useState( - value ?? minimumValue ?? constants.SLIDER_DEFAULT_INITIAL_VALUE, - ); - const [width, setWidth] = useState(0); - - const stepResolution = step ? step : constants.DEFAULT_STEP_RESOLUTION; - - const defaultStep = (maximumValue - minimumValue) / stepResolution; - const stepLength = step || defaultStep; + StyleSheet, + type NativeSyntheticEvent, + type StyleProp, + type ViewStyle, +} from "react-native"; + +import SliderNativeComponent, { + type NativeSliderProps, + type SliderChangeEvent, +} from "./SliderNativeComponent"; + +export type SliderProps = { + style?: StyleProp; + onValueChange?: (value: number) => void; +} & NativeSliderProps; + +export const Slider: FunctionComponent = ({ + minValue, + maxValue, + step, + onValueChange, + style, +}) => { + const steps = useMemo(() => { + if (!step) { + return undefined; + } else { + return Platform.OS === "android" + ? Math.round(Math.abs(((maxValue || 1) - (minValue || 0)) / step)) - 1 + : step; + } + }, [minValue, maxValue, step]); - const options = Array.from( - { - length: (step ? defaultStep : stepResolution) + 1, + const handleValueChange = useCallback( + (event: NativeSyntheticEvent) => { + onValueChange?.(event.nativeEvent.value); }, - (_, index) => minimumValue + index * stepLength, + [onValueChange], ); - const defaultStyle = - Platform.OS === 'ios' ? styles.defaultSlideriOS : styles.defaultSlider; - const sliderStyle = {zIndex: 1, width: width}; - const style = [defaultStyle, props.style]; - - const onValueChangeEvent = (event: Event) => { - onValueChange && onValueChange(event.nativeEvent.value); - setCurrentValue(event.nativeEvent.value); - }; - - const _disabled = - typeof props.disabled === 'boolean' - ? props.disabled - : props.accessibilityState?.disabled === true; - - const _accessibilityState = - typeof props.disabled === 'boolean' - ? {...props.accessibilityState, disabled: props.disabled} - : props.accessibilityState; - - const onSlidingStartEvent = onSlidingStart - ? (event: Event) => { - onSlidingStart(event.nativeEvent.value); - } - : null; - const onSlidingCompleteEvent = onSlidingComplete - ? (event: Event) => { - onSlidingComplete(event.nativeEvent.value); - } - : null; - const onAccessibilityActionEvent = onAccessibilityAction - ? (event: AccessibilityActionEvent) => { - onAccessibilityAction(event); - } - : null; - - const passedValue = Number.isNaN(value) || !value ? undefined : value; - - useEffect(() => { - if (lowerLimit >= upperLimit) { - console.warn( - 'Invalid configuration: lower limit is supposed to be smaller than upper limit', - ); - } - }, [lowerLimit, upperLimit]); - return ( - { - setWidth(event.nativeEvent.layout.width); - }} - style={[style, {justifyContent: 'center'}]}> - {props.StepMarker || !!props.renderStepNumber ? ( - - ) : null} - true} - onResponderTerminationRequest={() => false} - onRNCSliderAccessibilityAction={onAccessibilityActionEvent} - thumbTintColor={ - props.thumbImage && !!props.StepMarker - ? 'transparent' - : props.thumbTintColor - } - /> - + ); }; -const SliderWithRef = React.forwardRef(SliderComponent); +export default Slider; -export default SliderWithRef; +const styles = StyleSheet.create({ + base: { + minHeight: 40, + }, +}); diff --git a/package/src/SliderNativeComponent.ts b/package/src/SliderNativeComponent.ts new file mode 100644 index 00000000..aeb274aa --- /dev/null +++ b/package/src/SliderNativeComponent.ts @@ -0,0 +1,26 @@ +import { + codegenNativeComponent, + type HostComponent, + type ViewProps, +} from "react-native"; +import type { + DirectEventHandler, + Double, + Float, + Int32, +} from "react-native/Libraries/Types/CodegenTypes"; + +export type SliderChangeEvent = Readonly<{ + value: Double; +}>; + +export interface NativeSliderProps extends ViewProps { + step?: Int32; + minValue?: Float; + maxValue?: Float; + onValueChange?: DirectEventHandler | null; +} + +export default codegenNativeComponent( + "SliderView", +) as HostComponent; diff --git a/package/src/components/StepNumber.tsx b/package/src/components/StepNumber.tsx deleted file mode 100644 index 09f38c03..00000000 --- a/package/src/components/StepNumber.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import {StyleProp, Text, TextStyle, View} from 'react-native'; -import {styles} from '../utils/styles'; - -export const StepNumber = ({ - i, - index, - style, -}: { - i: number; - index: number; - style: StyleProp; -}) => { - return ( - - - {i} - - - ); -}; diff --git a/package/src/components/StepsIndicator.tsx b/package/src/components/StepsIndicator.tsx deleted file mode 100644 index 0ac98316..00000000 --- a/package/src/components/StepsIndicator.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import React, {FC, Fragment, useCallback, useMemo} from 'react'; -import {Platform, View} from 'react-native'; -import {StepNumber} from './StepNumber'; -import {MarkerProps, SliderTrackMark} from './TrackMark'; -//@ts-ignore -import type {ImageSource} from 'react-native/Libraries/Image/ImageSource'; -import {styles} from '../utils/styles'; -import {constants} from '../utils/constants'; - -export const StepsIndicator = ({ - options, - sliderWidth, - currentValue, - StepMarker, - renderStepNumber, - thumbImage, - isLTR, -}: { - options: number[]; - sliderWidth: number; - currentValue: number; - StepMarker?: FC; - renderStepNumber?: boolean; - thumbImage?: ImageSource; - isLTR?: boolean; -}) => { - const stepNumberFontStyle = useMemo(() => { - return { - fontSize: - options.length > 9 - ? constants.STEP_NUMBER_TEXT_FONT_SMALL - : constants.STEP_NUMBER_TEXT_FONT_BIG, - }; - }, [options.length]); - - const platformDependentStyles = useMemo(() => { - const isWeb = Platform.OS === 'web'; - return { - stepIndicatorContainerStyle: isWeb - ? styles.stepsIndicator - : { - ...styles.stepsIndicator, - marginHorizontal: sliderWidth * constants.MARGIN_HORIZONTAL_PADDING, - }, - stepIndicatorElementStyle: isWeb - ? { - ...styles.stepIndicatorElement, - width: constants.THUMB_SIZE, - justifyContent: 'space-between' as const, - } - : styles.stepIndicatorElement, - }; - }, [sliderWidth]); - - const values = isLTR ? options.reverse() : options; - - const renderStepIndicator = useCallback( - (i: number, index: number) => { - return ( - - - - {renderStepNumber ? ( - - ) : null} - - - ); - }, - [ - currentValue, - StepMarker, - options, - thumbImage, - renderStepNumber, - stepNumberFontStyle, - platformDependentStyles.stepIndicatorElementStyle, - ], - ); - - return ( - - {values.map((i, index) => renderStepIndicator(i, index))} - - ); -}; diff --git a/package/src/components/TrackMark.tsx b/package/src/components/TrackMark.tsx deleted file mode 100644 index 21a096e2..00000000 --- a/package/src/components/TrackMark.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React, {FC} from 'react'; -import {Image, ImageSource, ImageSourcePropType, View} from 'react-native'; -import {styles} from '../utils/styles'; - -export type MarkerProps = { - stepMarked: boolean; - currentValue: number; - index: number; - min: number; - max: number; -}; - -export type TrackMarksProps = { - isTrue: boolean; - index: number; - thumbImage?: ImageSource; - StepMarker?: FC; - currentValue: number; - min: number; - max: number; -}; - -export const SliderTrackMark = ({ - isTrue, - index, - thumbImage, - StepMarker, - currentValue, - min, - max, -}: TrackMarksProps) => { - return ( - - {StepMarker ? ( - - ) : null} - {thumbImage && isTrue ? ( - - - - ) : null} - - ); -}; diff --git a/package/src/index.ts b/package/src/index.ts index ebd6e915..a6b80558 100644 --- a/package/src/index.ts +++ b/package/src/index.ts @@ -1,3 +1,2 @@ -const RNCSlider = require('./RNCSliderNativeComponent').default; - -export default RNCSlider; +import Slider from "./Slider"; +export default Slider; diff --git a/package/src/utils/constants.ts b/package/src/utils/constants.ts deleted file mode 100644 index 72b26fbf..00000000 --- a/package/src/utils/constants.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {Platform} from 'react-native'; - -export const constants = { - SLIDER_DEFAULT_INITIAL_VALUE: 0, - MARGIN_HORIZONTAL_PADDING: 0.05, - // Default thumb size for web platform (used in step indicator positioning) - THUMB_SIZE: 20, - STEP_NUMBER_TEXT_FONT_SMALL: 8, - STEP_NUMBER_TEXT_FONT_BIG: 12, - LIMIT_MIN_VALUE: Number.MIN_SAFE_INTEGER, - LIMIT_MAX_VALUE: Number.MAX_SAFE_INTEGER, - DEFAULT_STEP_RESOLUTION: Platform.OS === 'android' ? 128 : 1000, -}; diff --git a/package/src/utils/styles.ts b/package/src/utils/styles.ts deleted file mode 100644 index 96e1df1d..00000000 --- a/package/src/utils/styles.ts +++ /dev/null @@ -1,55 +0,0 @@ -import {Platform, StyleSheet} from 'react-native'; - -export const styles = StyleSheet.create({ - stepNumber: { - marginTop: 20, - alignItems: 'center', - position: 'absolute', - }, - sliderMainContainer: {zIndex: 1, width: '100%'}, - defaultSlideriOS: { - height: 40, - }, - defaultSlider: {}, - stepsIndicator: { - flex: 1, - flexDirection: 'row', - justifyContent: 'space-between', - top: Platform.OS === 'ios' ? 10 : 0, - zIndex: 2, - }, - trackMarkContainer: { - alignItems: 'center', - alignContent: 'center', - alignSelf: 'center', - justifyContent: 'center', - position: 'absolute', - zIndex: 3, - }, - thumbImageContainer: { - position: 'absolute', - zIndex: 3, - justifyContent: 'center', - alignItems: 'center', - alignContent: 'center', - }, - thumbImage: { - alignContent: 'center', - alignItems: 'center', - position: 'absolute', - }, - stepIndicatorElement: { - alignItems: 'center', - alignContent: 'center', - }, - defaultIndicatorMarked: { - height: 20, - width: 5, - backgroundColor: '#CCCCCC', - }, - defaultIndicatorIdle: { - height: 10, - width: 2, - backgroundColor: '#C0C0C0', - }, -}); diff --git a/package/typings/index.d.ts b/package/typings/index.d.ts deleted file mode 100644 index 6903ca7a..00000000 --- a/package/typings/index.d.ts +++ /dev/null @@ -1,214 +0,0 @@ -import * as React from 'react'; -import { FC } from 'react'; -import * as ReactNative from 'react-native'; -import { ImageURISource } from 'react-native'; - -type Constructor = new (...args: any[]) => T; - -type SliderReferenceType = - | (React.MutableRefObject & React.LegacyRef) - | undefined; - -export interface SliderPropsAndroid extends ReactNative.ViewProps { - /** - * Color of the foreground switch grip. - */ - thumbTintColor?: string; -} - -export interface SliderRef { - updateValue(value: number): void; -} - -export type TrackMarksProps = { - isTrue: boolean; - index: number; - thumbImage?: ImageURISource; - StepMarker?: FC | boolean; - currentValue: number; -}; - -export type MarkerProps = { - stepMarked: boolean; - currentValue: number; - index: number; - min: number; - max: number; -}; - -export interface SliderPropsIOS extends ReactNative.ViewProps { - /** - * Assigns a maximum track image. Only static images are supported. - * The leftmost pixel of the image will be stretched to fill the track. - */ - maximumTrackImage?: ReactNative.ImageURISource; - - /** - * Assigns a minimum track image. Only static images are supported. - * The rightmost pixel of the image will be stretched to fill the track. - */ - minimumTrackImage?: ReactNative.ImageURISource; - - /** - * Permits tapping on the slider track to set the thumb position. - * Defaults to false on iOS. No effect on Android or Windows. - */ - tapToSeek?: boolean; - - /** - * Sets an image for the thumb. Only static images are supported. - */ - thumbImage?: ReactNative.ImageURISource; - - /** - * Assigns a single image for the track. Only static images - * are supported. The center pixel of the image will be stretched - * to fill the track. - */ - trackImage?: ReactNative.ImageURISource; -} - -export interface SliderPropsWindows extends ReactNative.ViewProps { - /** - * Controls the orientation of the slider, default value is 'false' (horizontal). - */ - vertical?: boolean; -} - -export interface SliderProps - extends SliderPropsIOS, - SliderPropsAndroid, - SliderPropsWindows { - /** - * If true the user won't be able to move the slider. - * Default value is false. - */ - disabled?: boolean; - - /** - * The color used for the track to the right of the button. - * Overrides the default blue gradient image. - */ - maximumTrackTintColor?: string; - - /** - * Initial maximum value of the slider. Default value is 1. - */ - maximumValue?: number; - - /** - * The lower limit value of the slider. The user won't be able to slide below this limit. - */ - lowerLimit?: number; - - /** - * The upper limit value of the slider. The user won't be able to slide above this limit. - */ - upperLimit?: number; - - /** - * The color used for the track to the left of the button. - * Overrides the default blue gradient image. - */ - minimumTrackTintColor?: string; - - /** - * Initial minimum value of the slider. Default value is 0. - */ - minimumValue?: number; - - /** - * Callback that is called when the user picks up the slider. - * The initial value is passed as an argument to the callback handler. - */ - onSlidingStart?: (value: number) => void; - - /** - * Callback called when the user finishes changing the value (e.g. when the slider is released). - */ - onSlidingComplete?: (value: number) => void; - - /** - * Callback continuously called while the user is dragging the slider. - */ - onValueChange?: (value: number) => void; - - /** - * Step value of the slider. The value should be between 0 and (maximumValue - minimumValue). Default value is 0. - */ - step?: number; - - /** - * Used to style and layout the Slider. See StyleSheet.js and ViewStylePropTypes.js for more info. - */ - style?: ReactNative.StyleProp; - - /** - * Used to locate this view in UI automation tests. - */ - testID?: string; - - /** - * Write-only property representing the value of the slider. - * Can be used to programmatically control the position of the thumb. - * Entered once at the beginning still acts as an initial value. - * The value should be between minimumValue and maximumValue, - * which default to 0 and 1 respectively. - * Default value is 0. - * - * This is not a controlled component, you don't need to update the - * value during dragging. - */ - value?: number; - - /** - * Reverses the direction of the slider. - */ - inverted?: boolean; - - /** - * Sets the size (width and height) of the thumb. - * If `thumbImage` is provided, it will be scaled to this size. - */ - thumbSize?: number; - - /** - * Component to be rendered for each step indicator. - */ - StepMarker?: FC; - - /** - * - */ - renderStepNumber?: boolean; - - /** - * A string of one or more words to be announced by the screen reader. - * Otherwise, it will announce the value as a percentage. - * Requires passing a value to `accessibilityIncrements` to work correctly. - * Should be a plural word, as singular units will be handled. - */ - accessibilityUnits?: string; - - /** - * An array of values that represent the different increments displayed - * by the slider. All the values passed into this prop must be strings. - * Requires passing a value to `accessibilityUnits` to work correctly. - * The number of elements must be the same as `maximumValue`. - */ - accessibilityIncrements?: Array; - - /** - * Reference object. - */ - ref?: SliderReferenceType; -} - -/** - * A component used to select a single value from a range of values. - */ -declare class SliderComponent extends React.Component {} -declare const SliderBase: Constructor & - typeof SliderComponent; -export default class Slider extends SliderBase {} -export type SliderIOS = Slider; diff --git a/package/windows/SliderWindows/SliderViewManager.cpp b/package/windows/SliderWindows/SliderViewManager.cpp index 16ea5218..8f248de5 100644 --- a/package/windows/SliderWindows/SliderViewManager.cpp +++ b/package/windows/SliderWindows/SliderViewManager.cpp @@ -19,7 +19,7 @@ namespace winrt::SliderWindows::implementation { // IViewManager winrt::hstring SliderViewManager::Name() noexcept { - return L"RNCSlider"; + return L"Slider"; } xaml::FrameworkElement SliderViewManager::CreateView() noexcept { @@ -73,8 +73,8 @@ namespace winrt::SliderWindows::implementation { ConstantProviderDelegate SliderViewManager::ExportedCustomDirectEventTypeConstants() noexcept { return [](winrt::IJSValueWriter const& constantWriter) { WriteCustomDirectEventTypeConstant(constantWriter, "onChange"); - WriteCustomDirectEventTypeConstant(constantWriter, L"topSlidingStart", L"onRNCSliderSlidingStart"); - WriteCustomDirectEventTypeConstant(constantWriter, L"topSlidingComplete", L"onRNCSliderSlidingComplete"); + WriteCustomDirectEventTypeConstant(constantWriter, L"topSlidingStart", L"onSliderSlidingStart"); + WriteCustomDirectEventTypeConstant(constantWriter, L"topSlidingComplete", L"onSliderSlidingComplete"); }; } From 5921dca880dcda812d2f87882b44dc4cf7cb067d Mon Sep 17 00:00:00 2001 From: BartoszKlonowski Date: Fri, 19 Jun 2026 14:15:26 +0200 Subject: [PATCH 5/7] Reimplement iOS platform to be using SwiftUI --- package/ios/RNCSlider.h | 31 -- package/ios/RNCSlider.m | 256 --------------- package/ios/RNCSliderComponentView.h | 36 -- package/ios/RNCSliderComponentView.mm | 309 ------------------ package/ios/Slider-Bridging-Header.h | 1 + .../project.pbxproj | 149 +++++---- package/ios/SliderView.swift | 43 +++ package/ios/SliderViewManager.m | 10 + package/ios/SliderViewManager.swift | 15 + package/package.json | 2 +- package/react-native-slider.podspec | 40 --- package/slider.podspec | 38 +++ package/src/RNCSliderNativeComponent.web.tsx | 26 +- 13 files changed, 198 insertions(+), 758 deletions(-) delete mode 100644 package/ios/RNCSlider.h delete mode 100644 package/ios/RNCSlider.m delete mode 100644 package/ios/RNCSliderComponentView.h delete mode 100644 package/ios/RNCSliderComponentView.mm create mode 100644 package/ios/Slider-Bridging-Header.h rename package/ios/{RNCSlider.xcodeproj => Slider.xcodeproj}/project.pbxproj (56%) create mode 100644 package/ios/SliderView.swift create mode 100644 package/ios/SliderViewManager.m create mode 100644 package/ios/SliderViewManager.swift delete mode 100644 package/react-native-slider.podspec create mode 100644 package/slider.podspec diff --git a/package/ios/RNCSlider.h b/package/ios/RNCSlider.h deleted file mode 100644 index 41b3dfbe..00000000 --- a/package/ios/RNCSlider.h +++ /dev/null @@ -1,31 +0,0 @@ -#import - -#import - -@interface Slider : UISlider - -@property (nonatomic, copy) RCTBubblingEventBlock onSliderValueChange; -@property (nonatomic, copy) RCTBubblingEventBlock onSliderSlidingStart; -@property (nonatomic, copy) RCTBubblingEventBlock onSliderSlidingComplete; - -@property (nonatomic, assign) float step; -@property (nonatomic, assign) float lastValue; -@property (nonatomic, assign) bool isSliding; - -@property (nonatomic, assign) float lowerLimit; -@property (nonatomic, assign) float upperLimit; - -@property (nonatomic, strong) UIImage *trackImage; -@property (nonatomic, strong) UIImage *minimumTrackImage; -@property (nonatomic, strong) UIImage *maximumTrackImage; -@property (nonatomic, strong) UIImage *thumbImage; -@property (nonatomic, assign) CGFloat thumbSize; -@property (nonatomic, assign) bool tapToSeek; -@property (nonatomic, strong) NSString *accessibilityUnits; -@property (nonatomic, strong) NSArray *accessibilityIncrements; - -- (float) discreteValue:(float)value; -- (void) setDisabled:(bool)disabled; -- (void) refreshThumb; - -@end diff --git a/package/ios/RNCSlider.m b/package/ios/RNCSlider.m deleted file mode 100644 index a902db11..00000000 --- a/package/ios/RNCSlider.m +++ /dev/null @@ -1,256 +0,0 @@ -#import "Slider.h" - -@implementation Slider -{ - float _unclippedValue; - bool _minimumTrackImageSet; - bool _maximumTrackImageSet; - UIImage *_thumbImage; - CGFloat _thumbSize; - UIColor *_thumbTintColor; -} - -- (instancetype)init { - if (self = [super init]) { - _upperLimit = FLT_MAX; - _lowerLimit = FLT_MIN; - } - return self; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - return [super initWithFrame:frame]; -} - -- (void)setValue:(float)value -{ - value = [self discreteValue:value]; - _unclippedValue = value; - super.value = value; - [self setupAccessibility:value]; -} - -- (void)setValue:(float)value animated:(BOOL)animated -{ - value = [self discreteValue:value]; - _unclippedValue = value; - [super setValue:value animated:animated]; - [self setupAccessibility:value]; -} - -- (void)setupAccessibility:(float)value -{ - if (self.accessibilityUnits && self.accessibilityIncrements && [self.accessibilityIncrements count] - 1 == (int)self.maximumValue) { - int index = (int)value; - NSString *sliderValue = (NSString *)[self.accessibilityIncrements objectAtIndex:index]; - NSUInteger stringLength = [self.accessibilityUnits length]; - - NSString *spokenUnits = [NSString stringWithString:self.accessibilityUnits]; - if (sliderValue && [sliderValue intValue] == 1) { - spokenUnits = [spokenUnits substringToIndex:stringLength-1]; - } - - self.accessibilityValue = [NSString stringWithFormat:@"%@ %@", sliderValue, spokenUnits]; - } -} - -- (void)setMinimumValue:(float)minimumValue -{ - super.minimumValue = minimumValue; - super.value = _unclippedValue; -} - -- (void)setMaximumValue:(float)maximumValue -{ - super.maximumValue = maximumValue; - super.value = _unclippedValue; -} - -- (void)setTrackImage:(UIImage *)trackImage -{ - if (trackImage != _trackImage) { - _trackImage = trackImage; - CGFloat width = trackImage.size.width / 2; - if (!_minimumTrackImageSet) { - UIImage *minimumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){ - 0, width, 0, width - } resizingMode:UIImageResizingModeStretch]; - [self setMinimumTrackImage:minimumTrackImage forState:UIControlStateNormal]; - } - if (!_maximumTrackImageSet) { - UIImage *maximumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){ - 0, width, 0, width - } resizingMode:UIImageResizingModeStretch]; - [self setMaximumTrackImage:maximumTrackImage forState:UIControlStateNormal]; - } - } -} - -- (void)setMinimumTrackImage:(UIImage *)minimumTrackImage -{ - _trackImage = nil; - _minimumTrackImageSet = true; - minimumTrackImage = [minimumTrackImage resizableImageWithCapInsets:(UIEdgeInsets){ - 0, minimumTrackImage.size.width, 0, 0 - } resizingMode:UIImageResizingModeStretch]; - [self setMinimumTrackImage:minimumTrackImage forState:UIControlStateNormal]; -} - -- (UIImage *)minimumTrackImage -{ - return [self thumbImageForState:UIControlStateNormal]; -} - -- (void)setMaximumTrackImage:(UIImage *)maximumTrackImage -{ - _trackImage = nil; - _maximumTrackImageSet = true; - maximumTrackImage = [maximumTrackImage resizableImageWithCapInsets:(UIEdgeInsets){ - 0, 0, 0, maximumTrackImage.size.width - } resizingMode:UIImageResizingModeStretch]; - [self setMaximumTrackImage:maximumTrackImage forState:UIControlStateNormal]; -} - -- (UIImage *)maximumTrackImage -{ - return [self thumbImageForState:UIControlStateNormal]; -} - -- (void)setThumbImage:(UIImage *)thumbImage -{ - _thumbImage = thumbImage; - [self refreshThumb]; -} - -- (UIImage *)thumbImage -{ - return [self thumbImageForState:UIControlStateNormal]; -} - -- (void)setThumbSize:(CGFloat)thumbSize -{ - _thumbSize = thumbSize; - [self refreshThumb]; -} - -- (void)setThumbTintColor:(UIColor *)thumbTintColor -{ - _thumbTintColor = thumbTintColor; - [super setThumbTintColor:thumbTintColor]; - - [self refreshThumb]; -} - -- (void)refreshThumb -{ - if (![NSThread isMainThread]) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self refreshThumb]; - }); - return; - } - - UIImage *imageToSet = nil; - - if (_thumbSize > 0) { - CGSize newSize = CGSizeMake(_thumbSize, _thumbSize); - UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0); - CGContextRef context = UIGraphicsGetCurrentContext(); - - if (_thumbImage) { - [_thumbImage drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; - } else { - UIColor *fillColor = _thumbTintColor ?: self.thumbTintColor ?: [UIColor whiteColor]; - CGContextSetFillColorWithColor(context, fillColor.CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0, 0, newSize.width, newSize.height)); - - CGContextSetStrokeColorWithColor(context, [[UIColor colorWithWhite:0.0 alpha:0.1] CGColor]); - CGContextSetLineWidth(context, 0.5); - CGContextStrokeEllipseInRect( - context, - CGRectMake(0.25, 0.25, newSize.width - 0.5, newSize.height - 0.5)); - } - - imageToSet = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - } else if (_thumbImage) { - imageToSet = _thumbImage; - } - - if (imageToSet) { - [self setThumbImage:imageToSet forState:UIControlStateNormal]; - [self setThumbImage:imageToSet forState:UIControlStateHighlighted]; - [self setThumbImage:imageToSet forState:UIControlStateSelected]; - } - - [UIView performWithoutAnimation:^{ - float currentValue = super.value; - float minimumValue = super.minimumValue; - float maximumValue = super.maximumValue; - - float eps = (maximumValue - minimumValue) / 1000.0f; - if (eps <= 0) { - eps = 0.0001f; - } - - float nudgedValue = currentValue + eps; - if (nudgedValue > maximumValue) { - nudgedValue = currentValue - eps; - } - if (nudgedValue < minimumValue) { - nudgedValue = minimumValue; - } - - if (nudgedValue != currentValue) { - [super setValue:nudgedValue animated:NO]; - } - [super setValue:currentValue animated:NO]; - - [self setNeedsLayout]; - [self layoutSubviews]; - [self layoutIfNeeded]; - }]; -} - -- (void)setInverted:(BOOL)inverted -{ - if (inverted) { - self.transform = CGAffineTransformMakeScale(-1, 1); - } else { - self.transform = CGAffineTransformMakeScale(1, 1); - } -} - -- (void)setDisabled:(BOOL)disabled -{ - self.enabled = !disabled; - [self layoutSubviews]; -} - -- (float)discreteValue:(float)value -{ - if (self.step > 0 && value >= self.maximumValue) { - return self.maximumValue; - } - - if (self.step > 0 && self.step <= (self.maximumValue - self.minimumValue)) { - double (^_round)(double) = ^(double x) { - if (!UIAccessibilityIsVoiceOverRunning()) { - return round(x); - } else if (self.lastValue > value) { - return floor(x); - } else { - return ceil(x); - } - }; - - return MAX(self.minimumValue, - MIN(self.maximumValue, self.minimumValue + _round((value - self.minimumValue) / self.step) * self.step) - ); - } - - return value; -} - -@end diff --git a/package/ios/RNCSliderComponentView.h b/package/ios/RNCSliderComponentView.h deleted file mode 100644 index 7be1caa6..00000000 --- a/package/ios/RNCSliderComponentView.h +++ /dev/null @@ -1,36 +0,0 @@ -#import -#import -#import "Slider.h" - -NS_ASSUME_NONNULL_BEGIN - -typedef void (^RNCLoadImageCompletionBlock)(NSError * _Nullable error, UIImage * _Nullable image); -typedef void (^RNCLoadImageFailureBlock)(); - -@interface SliderComponentView : RCTViewComponentView - -@property (nonatomic, copy) RCTBubblingEventBlock onSliderValueChange; -@property (nonatomic, copy) RCTBubblingEventBlock onSliderSlidingStart; -@property (nonatomic, copy) RCTBubblingEventBlock onSliderSlidingComplete; - -@property (nonatomic, assign) float step; -@property (nonatomic, assign) float lastValue; -@property (nonatomic, assign) bool isSliding; - -@property (nonatomic, assign) float lowerLimit; -@property (nonatomic, assign) float upperLimit; - -@property (nonatomic, strong) UIImage *trackImage; -@property (nonatomic, strong) UIImage *minimumTrackImage; -@property (nonatomic, strong) UIImage *maximumTrackImage; -@property (nonatomic, strong) UIImage *thumbImage; -@property (nonatomic, assign) CGFloat thumbSize; -@property (nonatomic, assign) bool tapToSeek; -@property (nonatomic, strong) NSString *accessibilityUnits; -@property (nonatomic, strong) NSArray *accessibilityIncrements; - -- (float) discreteValue:(float)value; - -@end - -NS_ASSUME_NONNULL_END diff --git a/package/ios/RNCSliderComponentView.mm b/package/ios/RNCSliderComponentView.mm deleted file mode 100644 index 7e865b6e..00000000 --- a/package/ios/RNCSliderComponentView.mm +++ /dev/null @@ -1,309 +0,0 @@ -#import "SliderComponentView.h" - -#import - -#import -#import -#import -#import -#import -#import "RCTImagePrimitivesConversions.h" -#import -#import "RCTFabricComponentsPlugins.h" -#import "Slider.h" - -using namespace facebook::react; - -@interface SliderComponentView () - -@end - - -@implementation SliderComponentView -{ - Slider *slider; - UIImage *_image; - BOOL _isSliding; -} - -+ (ComponentDescriptorProvider)componentDescriptorProvider -{ - return concreteComponentDescriptorProvider(); -} - -+ (BOOL)shouldBeRecycled { - return NO; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) { - static const auto defaultProps = std::make_shared(); - _props = defaultProps; - slider = [[Slider alloc] initWithFrame:self.bounds]; - [slider addTarget:self action:@selector(sliderValueChanged:) - forControlEvents:UIControlEventValueChanged]; - [slider addTarget:self action:@selector(sliderTouchStart:) - forControlEvents:UIControlEventTouchDown]; - [slider addTarget:self action:@selector(sliderTouchEnd:) - forControlEvents:(UIControlEventTouchUpInside | - UIControlEventTouchUpOutside | - UIControlEventTouchCancel)]; - - UITapGestureRecognizer *tapGesturer; - tapGesturer = [[UITapGestureRecognizer alloc] initWithTarget: self action:@selector(tapHandler:)]; - [tapGesturer setNumberOfTapsRequired: 1]; - [slider addGestureRecognizer:tapGesturer]; - - slider.value = (float)defaultProps->value; - self.contentView = slider; - } - return self; -} - -- (void)tapHandler:(UITapGestureRecognizer *)gesture { - if ([gesture.view class] != [Slider class]) { - return; - } - Slider *slider = (Slider *)gesture.view; - slider.isSliding = _isSliding; - - // Ignore this tap if in the middle of a slide. - if (_isSliding) { - return; - } - - if (!slider.tapToSeek) { - return; - } - - CGPoint touchPoint = [gesture locationInView:slider]; - float rangeWidth = slider.maximumValue - slider.minimumValue; - - float sliderPercent; - if ([UIView userInterfaceLayoutDirectionForSemanticContentAttribute:slider.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft) { - sliderPercent = 1.0 - (touchPoint.x / slider.bounds.size.width); - } else { - sliderPercent = touchPoint.x / slider.bounds.size.width; - } - - slider.lastValue = slider.value; - float value = slider.minimumValue + (rangeWidth * sliderPercent); - - if (value < slider.lowerLimit) { - value = slider.lowerLimit; - } else if (value > slider.upperLimit) { - value = slider.upperLimit; - } - - [slider setValue:[slider discreteValue:value] animated: YES]; - - std::dynamic_pointer_cast(_eventEmitter) - ->onSliderSlidingStart(SliderEventEmitter::OnSliderSlidingStart{.value = static_cast(slider.lastValue)}); - - // Trigger onValueChange to address https://github.com/react-native-community/react-native-slider/issues/212 - std::dynamic_pointer_cast(_eventEmitter) - ->onSliderValueChange(SliderEventEmitter::OnSliderValueChange{.value = static_cast(slider.value)}); - - std::dynamic_pointer_cast(_eventEmitter) - ->onSliderSlidingComplete(SliderEventEmitter::OnSliderSlidingComplete{.value = static_cast(slider.value)}); -} - -- (void)sliderValueChanged:(Slider *)sender -{ - [self RNCSendSliderEvent:sender withContinuous:YES isSlidingStart:NO]; -} - -- (void)sliderTouchStart:(Slider *)sender -{ - [self RNCSendSliderEvent:sender withContinuous:NO isSlidingStart:YES]; - _isSliding = YES; - sender.isSliding = YES; -} - -- (void)sliderTouchEnd:(Slider *)sender -{ - [self RNCSendSliderEvent:sender withContinuous:NO isSlidingStart:NO]; - sender.isSliding = NO; - _isSliding = NO; -} - -- (void)RNCSendSliderEvent:(Slider *)sender withContinuous:(BOOL)continuous isSlidingStart:(BOOL)isSlidingStart -{ - float value = [sender discreteValue:sender.value]; - - if (value < sender.lowerLimit) { - value = sender.lowerLimit; - [sender setValue:value animated:NO]; - } else if (value > sender.upperLimit) { - value = sender.upperLimit; - [sender setValue:value animated:NO]; - } - - if(!sender.isSliding) { - [sender setValue:value animated:NO]; - } - - if (continuous) { - if (sender.lastValue != value) { - std::dynamic_pointer_cast(_eventEmitter) - ->onSliderValueChange(SliderEventEmitter::OnSliderValueChange{.value = static_cast(value)}); - } - } else { - if (!isSlidingStart) { - std::dynamic_pointer_cast(_eventEmitter) - ->onSliderSlidingComplete(SliderEventEmitter::OnSliderSlidingComplete{.value = static_cast(value)}); - } - if (isSlidingStart) { - std::dynamic_pointer_cast(_eventEmitter) - ->onSliderSlidingStart(SliderEventEmitter::OnSliderSlidingStart{.value = static_cast(value)}); - } - } - - sender.lastValue = value; -} - -- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps -{ - const auto &oldScreenProps = *std::static_pointer_cast(_props); - const auto &newScreenProps = *std::static_pointer_cast(props); - - if (oldScreenProps.value != newScreenProps.value) { - if (!slider.isSliding) { - slider.value = newScreenProps.value; - } - } - if (oldScreenProps.disabled != newScreenProps.disabled) { - [slider setDisabled: newScreenProps.disabled]; - } - if (oldScreenProps.step != newScreenProps.step) { - slider.step = newScreenProps.step; - } - if (oldScreenProps.inverted != newScreenProps.inverted) { - [self setInverted:newScreenProps.inverted]; - } - if (oldScreenProps.maximumValue != newScreenProps.maximumValue) { - [slider setMaximumValue:newScreenProps.maximumValue]; - } - if (slider.lowerLimit != newScreenProps.lowerLimit) { - if(newScreenProps.lowerLimit > slider.upperLimit){ - NSLog(@"Invalid configuration: upperLimit < lowerLimit; lowerLimit not set"); - } else { - slider.lowerLimit = newScreenProps.lowerLimit; - } - } - if (slider.upperLimit != newScreenProps.upperLimit) { - if(newScreenProps.upperLimit < slider.lowerLimit){ - NSLog(@"Invalid configuration: upperLimit < lowerLimit; upperLimit not set"); - } else { - slider.upperLimit = newScreenProps.upperLimit; - } - } - if (oldScreenProps.tapToSeek != newScreenProps.tapToSeek) { - slider.tapToSeek = newScreenProps.tapToSeek; - } - if (oldScreenProps.minimumValue != newScreenProps.minimumValue) { - [slider setMinimumValue:newScreenProps.minimumValue]; - } - if (oldScreenProps.thumbTintColor != newScreenProps.thumbTintColor) { - slider.thumbTintColor = RCTUIColorFromSharedColor(newScreenProps.thumbTintColor); - } - if (oldScreenProps.thumbSize != newScreenProps.thumbSize) { - slider.thumbSize = newScreenProps.thumbSize; - } - if (oldScreenProps.minimumTrackTintColor != newScreenProps.minimumTrackTintColor) { - slider.minimumTrackTintColor = RCTUIColorFromSharedColor(newScreenProps.minimumTrackTintColor); - } - if (oldScreenProps.maximumTrackTintColor != newScreenProps.maximumTrackTintColor) { - slider.maximumTrackTintColor = RCTUIColorFromSharedColor(newScreenProps.maximumTrackTintColor); - } - if (oldScreenProps.accessibilityUnits != newScreenProps.accessibilityUnits) { - NSString *convertedAccessibilityUnits = [NSString stringWithCString:newScreenProps.accessibilityUnits.c_str() - encoding:[NSString defaultCStringEncoding]]; - slider.accessibilityUnits = convertedAccessibilityUnits; - } - if (oldScreenProps.accessibilityIncrements != newScreenProps.accessibilityIncrements) { - id accessibilityIncrements = [NSMutableArray new]; - for (auto str : newScreenProps.accessibilityIncrements) { - [accessibilityIncrements addObject:[NSString stringWithUTF8String:str.c_str()]]; - } - [slider setAccessibilityIncrements:accessibilityIncrements]; - } - if (oldScreenProps.thumbImage != newScreenProps.thumbImage) { - [self loadImageFromImageSource:newScreenProps.thumbImage completionBlock:^(NSError *error, UIImage *image) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self->slider setThumbImage:image]; - }); - } - failureBlock:^{ - [self->slider setThumbImage:nil]; - }]; - } - if (oldScreenProps.trackImage != newScreenProps.trackImage) { - [self loadImageFromImageSource:newScreenProps.trackImage completionBlock:^(NSError *error, UIImage *image) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self->slider setTrackImage:image]; - }); - } - failureBlock:^{ - [self->slider setTrackImage:nil]; - }]; - } - if (oldScreenProps.minimumTrackImage != newScreenProps.minimumTrackImage) { - [self loadImageFromImageSource:newScreenProps.minimumTrackImage completionBlock:^(NSError *error, UIImage *image) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self->slider setMinimumTrackImage:image]; - }); - } - failureBlock:^{ - [self->slider setMinimumTrackImage:nil]; - }]; - } - if (oldScreenProps.maximumTrackImage != newScreenProps.maximumTrackImage) { - [self loadImageFromImageSource:newScreenProps.maximumTrackImage completionBlock:^(NSError *error, UIImage *image) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self->slider setMaximumTrackImage:image]; - }); - } - failureBlock:^{ - [self->slider setMaximumTrackImage:nil]; - }]; - } - [super updateProps:props oldProps:oldProps]; -} - - -// TODO temporarily using bridge, workaround for https://github.com/reactwg/react-native-new-architecture/discussions/31#discussioncomment-2717047, rewrite when Meta comes with a solution. -- (void)loadImageFromImageSource:(ImageSource)source completionBlock:(RNCLoadImageCompletionBlock)completionBlock failureBlock:(RNCLoadImageFailureBlock)failureBlock -{ - NSString *uri = [[NSString alloc] initWithUTF8String:source.uri.c_str()]; - if ((BOOL)uri.length) { - [[[RCTBridge currentBridge] moduleForName:@"ImageLoader"] - loadImageWithURLRequest:NSURLRequestFromImageSource(source) - size:CGSizeMake(source.size.width, source.size.height) - scale:source.scale - clipped:NO - resizeMode:RCTResizeModeCover - progressBlock:nil - partialLoadBlock:nil - completionBlock:completionBlock]; - } else { - failureBlock(); - } -} - -- (void)setInverted:(BOOL)inverted -{ - if (inverted) { - self.transform = CGAffineTransformMakeScale(-1, 1); - } else { - self.transform = CGAffineTransformMakeScale(1, 1); - } -} - -@end - -Class SliderCls(void) -{ - return SliderComponentView.class; -} diff --git a/package/ios/Slider-Bridging-Header.h b/package/ios/Slider-Bridging-Header.h new file mode 100644 index 00000000..16eb5eb1 --- /dev/null +++ b/package/ios/Slider-Bridging-Header.h @@ -0,0 +1 @@ +#import diff --git a/package/ios/RNCSlider.xcodeproj/project.pbxproj b/package/ios/Slider.xcodeproj/project.pbxproj similarity index 56% rename from package/ios/RNCSlider.xcodeproj/project.pbxproj rename to package/ios/Slider.xcodeproj/project.pbxproj index 057244e9..ecdc3473 100644 --- a/package/ios/RNCSlider.xcodeproj/project.pbxproj +++ b/package/ios/Slider.xcodeproj/project.pbxproj @@ -3,16 +3,16 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 46; objects = { /* Begin PBXBuildFile section */ - 28C79A23220DC7760061DE82 /* RNCSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 28C79A21220DC7760061DE82 /* RNCSlider.m */; }; - 7682E5172887E3AB00642F2D /* RNCSliderComponentView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7682E5162887E3AB00642F2D /* RNCSliderComponentView.mm */; }; + 5E555C0D2413F4C50049A1A2 /* Slider.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* Slider.m */; }; + F4FF95D7245B92E800C19C63 /* Slider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* Slider.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ - 28C79A07220DC4CC0061DE82 /* CopyFiles */ = { + 58B511D91A9E6C8500147676 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "include/$(PRODUCT_NAME)"; @@ -24,15 +24,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 28C79A09220DC4CC0061DE82 /* libRNCSlider.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNCSlider.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 28C79A1E220DC7760061DE82 /* RNCSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNCSlider.h; sourceTree = ""; }; - 28C79A21220DC7760061DE82 /* RNCSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNCSlider.m; sourceTree = ""; }; - 7682E5152887E39900642F2D /* RNCSliderComponentView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNCSliderComponentView.h; sourceTree = ""; }; - 7682E5162887E3AB00642F2D /* RNCSliderComponentView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = RNCSliderComponentView.mm; sourceTree = ""; }; + 134814201AA4EA6300B7C361 /* libSlider.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSlider.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B3E7B5891CC2AC0600A0062D /* Slider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Slider.m; sourceTree = ""; }; + F4FF95D5245B92E700C19C63 /* Slider-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Slider-Bridging-Header.h"; sourceTree = ""; }; + F4FF95D6245B92E800C19C63 /* Slider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Slider.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 28C79A06220DC4CC0061DE82 /* Frameworks */ = { + 58B511D81A9E6C8500147676 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( @@ -42,124 +41,118 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 28C79A00220DC4CC0061DE82 = { + 134814211AA4EA7D00B7C361 /* Products */ = { isa = PBXGroup; children = ( - 7682E5162887E3AB00642F2D /* RNCSliderComponentView.mm */, - 7682E5152887E39900642F2D /* RNCSliderComponentView.h */, - 28C79A1E220DC7760061DE82 /* RNCSlider.h */, - 28C79A21220DC7760061DE82 /* RNCSlider.m */, - 28C79A0A220DC4CC0061DE82 /* Products */, + 134814201AA4EA6300B7C361 /* libSlider.a */, ); + name = Products; sourceTree = ""; }; - 28C79A0A220DC4CC0061DE82 /* Products */ = { + 58B511D21A9E6C8500147676 = { isa = PBXGroup; children = ( - 28C79A09220DC4CC0061DE82 /* libRNCSlider.a */, + F4FF95D6245B92E800C19C63 /* Slider.swift */, + B3E7B5891CC2AC0600A0062D /* Slider.m */, + F4FF95D5245B92E700C19C63 /* Slider-Bridging-Header.h */, + 134814211AA4EA7D00B7C361 /* Products */, ); - name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 28C79A08220DC4CC0061DE82 /* RNCSlider */ = { + 58B511DA1A9E6C8500147676 /* Slider */ = { isa = PBXNativeTarget; - buildConfigurationList = 28C79A12220DC4CC0061DE82 /* Build configuration list for PBXNativeTarget "RNCSlider" */; + buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "Slider" */; buildPhases = ( - 28C79A05220DC4CC0061DE82 /* Sources */, - 28C79A06220DC4CC0061DE82 /* Frameworks */, - 28C79A07220DC4CC0061DE82 /* CopyFiles */, + 58B511D71A9E6C8500147676 /* Sources */, + 58B511D81A9E6C8500147676 /* Frameworks */, + 58B511D91A9E6C8500147676 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); - name = RNCSlider; - productName = RNCSlider; - productReference = 28C79A09220DC4CC0061DE82 /* libRNCSlider.a */; + name = Slider; + productName = RCTDataManager; + productReference = 134814201AA4EA6300B7C361 /* libSlider.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - 28C79A01220DC4CC0061DE82 /* Project object */ = { + 58B511D31A9E6C8500147676 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1010; - ORGANIZATIONNAME = "React Native Community"; + LastUpgradeCheck = 0920; + ORGANIZATIONNAME = Facebook; TargetAttributes = { - 28C79A08220DC4CC0061DE82 = { - CreatedOnToolsVersion = 10.1; + 58B511DA1A9E6C8500147676 = { + CreatedOnToolsVersion = 6.1.1; }; }; }; - buildConfigurationList = 28C79A04220DC4CC0061DE82 /* Build configuration list for PBXProject "RNCSlider" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; + buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "Slider" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); - mainGroup = 28C79A00220DC4CC0061DE82; - productRefGroup = 28C79A0A220DC4CC0061DE82 /* Products */; + mainGroup = 58B511D21A9E6C8500147676; + productRefGroup = 58B511D21A9E6C8500147676; projectDirPath = ""; projectRoot = ""; targets = ( - 28C79A08220DC4CC0061DE82 /* RNCSlider */, + 58B511DA1A9E6C8500147676 /* Slider */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 28C79A05220DC4CC0061DE82 /* Sources */ = { + 58B511D71A9E6C8500147676 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7682E5172887E3AB00642F2D /* RNCSliderComponentView.mm in Sources */, - 28C79A23220DC7760061DE82 /* RNCSlider.m in Sources */, + F4FF95D7245B92E800C19C63 /* Slider.swift in Sources */, + B3E7B58A1CC2AC0600A0062D /* Slider.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 28C79A10220DC4CC0061DE82 /* Debug */ = { + 58B511ED1A9E6C8500147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=*]" = arm64; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -168,55 +161,49 @@ "DEBUG=1", "$(inherited)", ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MTL_ENABLE_DEBUG_INFO = YES; - MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; - 28C79A11220DC4CC0061DE82 /* Release */ = { + 58B511EE1A9E6C8500147676 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=*]" = arm64; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -225,54 +212,72 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; - 28C79A13220DC4CC0061DE82 /* Debug */ = { + 58B511F01A9E6C8500147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../../React/**", + "$(SRCROOT)/../../react-native/React/**", + ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = Slider; SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "Slider-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; - 28C79A14220DC4CC0061DE82 /* Release */ = { + 58B511F11A9E6C8500147676 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../../React/**", + "$(SRCROOT)/../../react-native/React/**", + ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = Slider; SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "Slider-Bridging-Header.h"; + SWIFT_VERSION = 5.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 28C79A04220DC4CC0061DE82 /* Build configuration list for PBXProject "RNCSlider" */ = { + 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "Slider" */ = { isa = XCConfigurationList; buildConfigurations = ( - 28C79A10220DC4CC0061DE82 /* Debug */, - 28C79A11220DC4CC0061DE82 /* Release */, + 58B511ED1A9E6C8500147676 /* Debug */, + 58B511EE1A9E6C8500147676 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 28C79A12220DC4CC0061DE82 /* Build configuration list for PBXNativeTarget "RNCSlider" */ = { + 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "Slider" */ = { isa = XCConfigurationList; buildConfigurations = ( - 28C79A13220DC4CC0061DE82 /* Debug */, - 28C79A14220DC4CC0061DE82 /* Release */, + 58B511F01A9E6C8500147676 /* Debug */, + 58B511F11A9E6C8500147676 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; - rootObject = 28C79A01220DC4CC0061DE82 /* Project object */; + rootObject = 58B511D31A9E6C8500147676 /* Project object */; } diff --git a/package/ios/SliderView.swift b/package/ios/SliderView.swift new file mode 100644 index 00000000..4baf462d --- /dev/null +++ b/package/ios/SliderView.swift @@ -0,0 +1,43 @@ +import SwiftUI + +struct SliderComponent: View { + @EnvironmentObject var state: SliderState + + @State private var value: Double = 0 + + var body: some View { + VStack { + Slider( + value: $value, + in: state.minValue...state.maxValue, + step: state.step + ) + } + } +} + +class SliderState: ObservableObject { + @Published var minValue: Double = 0 + @Published var maxValue: Double = 1 + @Published var step: Double = 1 + @Published var color: Color = .accentColor + @Published var onValueChange: (Double) -> Void = { _ in } +} + +class SliderView: UIView { + private var state: SliderState = SliderState() + + override init(frame: CGRect) { + super.init(frame: frame) + let hostingController = UIHostingController(rootView: SliderComponent().environmentObject(state)) + addSubview(hostingController.view) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + subviews.first?.frame = self.frame + } +} diff --git a/package/ios/SliderViewManager.m b/package/ios/SliderViewManager.m new file mode 100644 index 00000000..76976d71 --- /dev/null +++ b/package/ios/SliderViewManager.m @@ -0,0 +1,10 @@ +#import + +@interface RCT_EXTERN_MODULE(SliderViewManager, RCTViewManager) + +RCT_EXPORT_VIEW_PROPERTY(minValue, double) +RCT_EXPORT_VIEW_PROPERTY(maxValue, double) +RCT_EXPORT_VIEW_PROPERTY(step, double) +RCT_EXPORT_VIEW_PROPERTY(onValueChange, RCTDirectEventBlock) + +@end diff --git a/package/ios/SliderViewManager.swift b/package/ios/SliderViewManager.swift new file mode 100644 index 00000000..b01f9d01 --- /dev/null +++ b/package/ios/SliderViewManager.swift @@ -0,0 +1,15 @@ + + +@objc(SliderViewManager) +class SliderViewManager: RCTViewManager { + + override func view() -> (SliderView) { + return SliderView() + } + + @objc override static func requiresMainQueueSetup() -> Bool { + return false + } +} + + diff --git a/package/package.json b/package/package.json index 6dd961a1..e4975ae9 100644 --- a/package/package.json +++ b/package/package.json @@ -78,7 +78,7 @@ }, "ios": { "componentProvider": { - "Slider": "SliderComponentView" + "SliderView": "SliderView" } } } diff --git a/package/react-native-slider.podspec b/package/react-native-slider.podspec deleted file mode 100644 index b795d531..00000000 --- a/package/react-native-slider.podspec +++ /dev/null @@ -1,40 +0,0 @@ -require 'json' - -package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) - -Pod::Spec.new do |s| - s.name = "react-native-slider" - s.version = package['version'] - s.summary = package['description'] - s.license = package['license'] - - s.authors = package['author'] - s.homepage = package['homepage'] - s.platforms = { :ios => "9.0", :visionos => "1.0" } - - s.source = { :git => "https://github.com/callstack/react-native-slider.git", :tag => "v#{s.version}" } - s.source_files = "ios/**/*.{h,m,mm}" - - s.subspec "common" do |ss| - ss.source_files = "common/cpp/**/*.{cpp,h}" - ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/common/cpp\"" } - end - - if defined?(install_modules_dependencies) - install_modules_dependencies(s) - else - s.dependency 'React-Core' - s.compiler_flags = "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32 -DRCT_NEW_ARCH_ENABLED=1" - s.pod_target_xcconfig = { - "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", - "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", - "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" - } - s.dependency "React-RCTFabric" - s.dependency "React-Codegen" - s.dependency "RCT-Folly" - s.dependency "RCTRequired" - s.dependency "RCTTypeSafety" - s.dependency "ReactCommon/turbomodule/core" - end -end diff --git a/package/slider.podspec b/package/slider.podspec new file mode 100644 index 00000000..745f6b39 --- /dev/null +++ b/package/slider.podspec @@ -0,0 +1,38 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) +folly_compiler_flags = "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32" + +Pod::Spec.new do |s| + s.name = "slider" + s.version = package["version"] + s.summary = package["description"] + s.license = package["license"] + + s.authors = package["author"] + s.homepage = package["homepage"] + + s.platforms = { :ios => "16.0" } + s.source = { :git => "https://github.com/callstack/react-native-slider.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift}" + + s.dependency "React-Core" + + if defined?(install_modules_dependencies) + install_modules_dependencies(s) + else + s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", + "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + s.dependency "React-RCTFabric" + s.dependency "React-Codegen" + s.dependency "RCT-Folly" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon/turbomodule/core" + end +end diff --git a/package/src/RNCSliderNativeComponent.web.tsx b/package/src/RNCSliderNativeComponent.web.tsx index 3587fdaa..1c29678b 100644 --- a/package/src/RNCSliderNativeComponent.web.tsx +++ b/package/src/RNCSliderNativeComponent.web.tsx @@ -42,9 +42,9 @@ export interface Props { disabled: boolean; trackHeight: number; thumbImage?: ImageSource; - onRNCSliderSlidingStart: (event: Event) => void; - onRNCSliderSlidingComplete: (event: Event) => void; - onRNCSliderValueChange: (event: Event) => void; + onSliderSlidingStart: (event: Event) => void; + onSliderSlidingComplete: (event: Event) => void; + onSliderValueChange: (event: Event) => void; } const valueToEvent = (value: number): Event => ({nativeEvent: {value}}); @@ -67,9 +67,9 @@ const RCTSliderWebComponent = React.forwardRef( disabled = false, trackHeight = 4, thumbImage, - onRNCSliderSlidingStart = (_: Event) => {}, - onRNCSliderSlidingComplete = (_: Event) => {}, - onRNCSliderValueChange = (_: Event) => {}, + onSliderSlidingStart = (_: Event) => {}, + onSliderSlidingComplete = (_: Event) => {}, + onSliderValueChange = (_: Event) => {}, ...others }: Props, forwardedRef: any, @@ -112,26 +112,26 @@ const RCTSliderWebComponent = React.forwardRef( const onValueChange = useCallback( (value: number) => { - onRNCSliderValueChange && onRNCSliderValueChange(valueToEvent(value)); + onSliderValueChange && onSliderValueChange(valueToEvent(value)); }, - [onRNCSliderValueChange], + [onSliderValueChange], ); const onSlidingStart = useCallback( (value: number) => { isUserInteracting.current = true; - onRNCSliderSlidingStart && onRNCSliderSlidingStart(valueToEvent(value)); + onSliderSlidingStart && onSliderSlidingStart(valueToEvent(value)); }, - [onRNCSliderSlidingStart], + [onSliderSlidingStart], ); const onSlidingComplete = useCallback( (value: number) => { isUserInteracting.current = false; - onRNCSliderSlidingComplete && - onRNCSliderSlidingComplete(valueToEvent(value)); + onSliderSlidingComplete && + onSliderSlidingComplete(valueToEvent(value)); }, - [onRNCSliderSlidingComplete], + [onSliderSlidingComplete], ); // Add a ref to track user interaction const isUserInteracting = React.useRef(false); From 6138893800cd8c77d9cd3b4e4dc21ed5340eda79 Mon Sep 17 00:00:00 2001 From: Maciej Lodygowski Date: Wed, 24 Jun 2026 18:02:55 +0200 Subject: [PATCH 6/7] Modernize slider native implementations and examples --- .nvmrc | 1 + README.md | 18 +- example-web/assets/slider-example-icon.png | Bin 0 -> 54258 bytes example-web/craco.config.js | 15 +- example-web/src/App.tsx | 240 +- example-web/src/Examples.tsx | 674 +++++- example-web/src/Props.tsx | 92 +- example-web/src/index.css | 10 + example-web/src/react-native-shim.d.ts | 82 + example-web/src/resources/ck-icon.png | Bin 0 -> 2809 bytes example-web/src/resources/empty.png | Bin 0 -> 1723 bytes example-web/src/resources/twitter-small.png | Bin 0 -> 4052 bytes example/App.tsx | 64 +- example/Gemfile.lock | 114 + example/__tests__/App.test.tsx | 5 + .../src/main/java/com/example/MainActivity.kt | 2 +- .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3056 -> 3214 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 3214 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 5024 -> 4318 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2096 -> 2274 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 2274 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 2858 -> 2931 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4569 -> 4295 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 4295 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 7098 -> 5836 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 6464 -> 6468 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 6468 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 10676 -> 8889 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9250 -> 8641 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 8641 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 15523 -> 11951 bytes .../app/src/main/res/values/colors.xml | 3 + .../app/src/main/res/values/strings.xml | 2 +- example/app.json | 4 +- example/assets/slider-example-icon.png | Bin 0 -> 54258 bytes example/ios/Podfile | 2 +- example/ios/Podfile.lock | 2106 +++++++++++++++++ example/ios/example.xcodeproj/project.pbxproj | 27 +- .../contents.xcworkspacedata | 10 + example/ios/example/AppDelegate.swift | 2 +- .../AppIcon.appiconset/AppIcon-1024.png | Bin 0 -> 54258 bytes .../AppIcon.appiconset/AppIcon-20@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/AppIcon-20@3x.png | Bin 0 -> 2687 bytes .../AppIcon.appiconset/AppIcon-29@2x.png | Bin 0 -> 2677 bytes .../AppIcon.appiconset/AppIcon-29@3x.png | Bin 0 -> 3899 bytes .../AppIcon.appiconset/AppIcon-40@2x.png | Bin 0 -> 3607 bytes .../AppIcon.appiconset/AppIcon-40@3x.png | Bin 0 -> 5277 bytes .../AppIcon.appiconset/AppIcon-60@2x.png | Bin 0 -> 5277 bytes .../AppIcon.appiconset/AppIcon-60@3x.png | Bin 0 -> 7853 bytes .../AppIcon.appiconset/Contents.json | 9 + example/ios/example/Info.plist | 5 +- example/ios/example/LaunchScreen.storyboard | 4 +- example/metro.config.js | 23 +- example/package.json | 9 +- example/src/App.tsx | 249 ++ example/src/Examples.tsx | 763 ++++++ example/src/Props.tsx | 210 ++ example/src/resources/ck-icon.png | Bin 0 -> 2809 bytes example/src/resources/empty.png | Bin 0 -> 1723 bytes example/src/resources/slider-left.png | Bin 0 -> 1395 bytes example/src/resources/slider-right.png | Bin 0 -> 1398 bytes example/src/resources/slider.png | Bin 0 -> 1562 bytes example/src/resources/twitter-small.png | Bin 0 -> 4052 bytes example/src/resources/twitter.png | Bin 0 -> 21556 bytes example/src/resources/uie_thumb_big.png | Bin 0 -> 6752 bytes package/android/build.gradle | 12 +- package/android/gradle.properties | 4 + .../com/callstack/slider/InlineComposeView.kt | 1 + .../java/com/callstack/slider/SliderEvents.kt | 30 + .../java/com/callstack/slider/SliderView.kt | 157 +- .../com/callstack/slider/SliderViewManager.kt | 63 +- package/ios/Slider-Bridging-Header.h | 3 +- package/ios/Slider.xcodeproj/project.pbxproj | 52 +- package/ios/SliderComponentView.mm | 291 +++ package/ios/SliderView.swift | 600 ++++- package/ios/SliderViewManager.m | 18 +- package/ios/SliderViewManager.swift | 18 +- package/ios/slider.h | 2 + package/package.json | 9 +- ...er.podspec => react-native-slider.podspec} | 4 +- package/src/RNCSliderNativeComponent.web.tsx | 398 ---- package/src/Slider.tsx | 335 ++- package/src/SliderNativeComponent.ts | 36 +- package/src/SliderNativeComponent.web.tsx | 273 +++ package/src/components/StepNumber.tsx | 22 + package/src/components/StepsIndicator.tsx | 124 + package/src/components/TrackMark.tsx | 57 + package/src/index.ts | 4 +- package/src/utils/constants.ts | 13 + package/src/utils/styles.ts | 55 + package/typings/index.d.ts | 90 + 93 files changed, 6614 insertions(+), 812 deletions(-) create mode 100644 .nvmrc create mode 100644 example-web/assets/slider-example-icon.png create mode 100644 example-web/src/react-native-shim.d.ts create mode 100644 example-web/src/resources/ck-icon.png create mode 100644 example-web/src/resources/empty.png create mode 100644 example-web/src/resources/twitter-small.png create mode 100644 example/Gemfile.lock create mode 100644 example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 example/android/app/src/main/res/values/colors.xml create mode 100644 example/assets/slider-example-icon.png create mode 100644 example/ios/Podfile.lock create mode 100644 example/ios/example.xcworkspace/contents.xcworkspacedata create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-1024.png create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-20@2x.png create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-20@3x.png create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-29@2x.png create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-29@3x.png create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-40@2x.png create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-40@3x.png create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-60@2x.png create mode 100644 example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-60@3x.png create mode 100644 example/src/App.tsx create mode 100644 example/src/Examples.tsx create mode 100644 example/src/Props.tsx create mode 100644 example/src/resources/ck-icon.png create mode 100644 example/src/resources/empty.png create mode 100644 example/src/resources/slider-left.png create mode 100644 example/src/resources/slider-right.png create mode 100644 example/src/resources/slider.png create mode 100644 example/src/resources/twitter-small.png create mode 100644 example/src/resources/twitter.png create mode 100644 example/src/resources/uie_thumb_big.png create mode 100644 package/android/gradle.properties create mode 100644 package/ios/SliderComponentView.mm create mode 100644 package/ios/slider.h rename package/{slider.podspec => react-native-slider.podspec} (93%) delete mode 100644 package/src/RNCSliderNativeComponent.web.tsx create mode 100644 package/src/SliderNativeComponent.web.tsx create mode 100644 package/src/components/StepNumber.tsx create mode 100644 package/src/components/StepsIndicator.tsx create mode 100644 package/src/components/TrackMark.tsx create mode 100644 package/src/utils/constants.ts create mode 100644 package/src/utils/styles.ts create mode 100644 package/typings/index.d.ts diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..6fa8dec4 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22.13.0 diff --git a/README.md b/README.md index 4d42aa5d..3b84c67a 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ To use this library you need to ensure you are using the correct version of Reac | `4.x.x` | `>=0.60`; `>=0.62` (on Windows); | | `3.1.x` | `>=0.60` | | `2.x.x` | `>= 0.60` | -| [`1.x.x`](https://github.com/react-native-community/react-native-slider/tree/937f0942f1fffc6ed88b5cf7c88d73b7878f00f0) | `<= 0.59` | +| [`1.x.x`](https://github.com/callstack/react-native-slider/tree/937f0942f1fffc6ed88b5cf7c88d73b7878f00f0) | `<= 0.59` | ## Properties @@ -93,14 +93,14 @@ To use this library you need to ensure you are using the correct version of Reac | `tapToSeek` | Permits tapping on the slider track to set the thumb position.
Defaults to false on iOS. No effect on Android or Windows. | bool | iOS | | `inverted` | Reverses the direction of the slider.
Default value is false. | bool | | | `vertical` | Changes the orientation of the slider to vertical, if set to `true`.
Default value is false. | bool | Windows | -| `thumbTintColor` | Color of the foreground switch grip.
**NOTE:** This prop will override the `thumbImage` prop set, meaning that if both `thumbImage` and `thumbTintColor` will be set, image used for the thumb may not be displayed correctly! | [color](https://reactnative.dev/docs/colors) | Android | +| `thumbTintColor` | Color of the foreground switch grip.
**NOTE:** This prop will override the `thumbImage` prop set, meaning that if both `thumbImage` and `thumbTintColor` will be set, image used for the thumb may not be displayed correctly! | [color](https://reactnative.dev/docs/colors) | Android, iOS, Web | | `thumbSize` | Sets the size (width and height) of the thumb.
If `thumbImage` is provided, it will be scaled to this size.
Units: points on iOS, dp on Android. | number | Android, iOS, Web | -| `maximumTrackImage` | Assigns a maximum track image. Only static images are supported. The leftmost pixel of the image will be stretched to fill the track. | Image
.propTypes
.source | iOS | -| `minimumTrackImage` | Assigns a minimum track image. Only static images are supported. The rightmost pixel of the image will be stretched to fill the track. | Image
.propTypes
.source | iOS | -| `thumbImage` | Sets an image for the thumb. Only static images are supported. Needs to be a URI of a local or network image; base64-encoded SVG is not supported. | Image
.propTypes
.source | | -| `trackImage` | Assigns a single image for the track. Only static images are supported. The center pixel of the image will be stretched to fill the track. | Image
.propTypes
.source | iOS | -| [`StepMarker`](#stepmarker) | Component to be rendered for each step on the track,
with the possibility to change the styling, when thumb is at that given step | `FC` | iOS, Android, Windows | -| [`renderStepNumber`](#renderstepnumber) | Turns on the displaying of numbers of steps.
Numbers of steps are displayed under the track | bool | iOS, Android, Windows | +| `maximumTrackImage` | Assigns a maximum track image. Only static images are supported. The leftmost pixel of the image will be stretched to fill the track. | Image
.propTypes
.source | iOS, Web | +| `minimumTrackImage` | Assigns a minimum track image. Only static images are supported. The rightmost pixel of the image will be stretched to fill the track. | Image
.propTypes
.source | iOS, Web | +| `thumbImage` | Sets an image for the thumb. Only static images are supported. Needs to be a URI of a local or network image; base64-encoded SVG is not supported. | Image
.propTypes
.source | iOS, Web | +| `trackImage` | Assigns a single image for the track. Only static images are supported. The center pixel of the image will be stretched to fill the track. | Image
.propTypes
.source | iOS, Web | +| [`StepMarker`](#stepmarker) | Component to be rendered for each step on the track,
with the possibility to change the styling, when thumb is at that given step | `FC` | Android, iOS, Web | +| [`renderStepNumber`](#renderstepnumber) | Turns on the displaying of numbers of steps.
Numbers of steps are displayed under the track | bool | Android, iOS, Web | | `ref` | Reference object. | MutableRefObject | web | | `View` | [Inherited `View` props...](https://github.com/facebook/react-native-website/blob/master/docs/view.md#props) | | | @@ -236,7 +236,7 @@ You can also do this manually by: ## Contributors -This module was extracted from `react-native` core. Please, refer to [contributors graph](https://github.com/react-native-community/react-native-slider/graphs/contributors) for the complete list of contributors. +This module was extracted from `react-native` core. Please, refer to [contributors graph](https://github.com/callstack/react-native-slider/graphs/contributors) for the complete list of contributors. --- diff --git a/example-web/assets/slider-example-icon.png b/example-web/assets/slider-example-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ddbed368790f02d6767ae9de46619d3e508064d7 GIT binary patch literal 54258 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 JevQ>+|36`%6>k6l literal 0 HcmV?d00001 diff --git a/example-web/craco.config.js b/example-web/craco.config.js index 90051fbb..529b6c89 100644 --- a/example-web/craco.config.js +++ b/example-web/craco.config.js @@ -2,7 +2,7 @@ const path = require('path'); const babelInclude = require('@dealmore/craco-plugin-babel-include'); const webpack = require('webpack'); -const LIB_PATH = `../package/dist/Slider.js`; +const LIB_PATH = `../package/src`; module.exports = { webpack: { @@ -12,6 +12,19 @@ module.exports = { // make sure we don't include multiple versions of react 'react': path.resolve(__dirname, './node_modules/react'), }, + configure: webpackConfig => { + webpackConfig.resolve.extensions = [ + '.web.tsx', + '.web.ts', + '.web.js', + ...webpackConfig.resolve.extensions.filter( + extension => + !['.web.tsx', '.web.ts', '.web.js'].includes(extension), + ), + ]; + + return webpackConfig; + }, babel: { presets: [ '@babel/preset-react', diff --git a/example-web/src/App.tsx b/example-web/src/App.tsx index a096bec4..ae57897c 100644 --- a/example-web/src/App.tsx +++ b/example-web/src/App.tsx @@ -1,34 +1,40 @@ -import React from 'react'; +import React, {useState} from "react"; import { - Text, - View, - ScrollView, + Image, Platform, + Pressable, + ScrollView, StyleSheet, -// @ts-ignore -} from 'react-native'; + Text, + View, +} from "react-native"; +import Slider from "@react-native-community/slider"; -import {examples, Props as ExamplesTabProperties} from './Examples'; -import {propsExamples, Props as PropsTabProperties} from './Props'; +import {examples, type Props as ExamplesTabProperties} from "./Examples"; +import {propsExamples, type Props as PropsTabProperties} from "./Props"; + +const App = () => { + const [currentPage, setCurrentPage] = useState(0); + const titles = ["Examples", "Props"]; -function App() { const renderExampleTab = ( sliders: PropsTabProperties[] | ExamplesTabProperties[], filtered?: boolean, ) => { + const tabSliders = filtered + ? (sliders as ExamplesTabProperties[]).filter( + e => !e.platform || e.platform === Platform.OS, + ) + : sliders; + return ( - + - {(filtered - ? (sliders as ExamplesTabProperties[]).filter( - e => !e.platform || e.platform === Platform.OS, - ) - : sliders - ).map((e, i) => ( - - {e.title} + {tabSliders.map((e, i) => ( + + {e.title} {e.render()} ))} @@ -38,56 +44,182 @@ function App() { }; return ( -

+ + {titles.map((title, index) => { + const isActive = index === currentPage; + return ( + setCurrentPage(index)} + role="button" + style={[styles.tab, isActive && styles.activeTab]}> + + {title} + + + ); + })} + + + + {titles[currentPage]} + + + {currentPage === 0 + ? renderExampleTab(examples, true) + : renderExampleTab(propsExamples, true)} + ); -} +}; export default App; -const pageViewPositionSlider = { - trackColor: '#ABABAB', - thumbColor: '#1411AB', - style: { - width: '100%', - }, +const colors = { + accent: "#7C5CFF", + border: "#D9DEEA", + card: "#FFFFFF", + ink: "#201A3D", + page: "#F3F5FA", + track: "#51486F", }; const styles = StyleSheet.create({ - pagerViewContainer: { + homeScreenContainer: { flex: 1, + minHeight: "100vh" as never, + backgroundColor: colors.ink, }, - homeScreenContainer: { + header: { + backgroundColor: colors.ink, + paddingHorizontal: 20, + paddingTop: 18, + paddingBottom: 18, + }, + brandRow: { + alignItems: "center", + flexDirection: "row", + gap: 14, + marginBottom: 22, + }, + brandMark: { + width: 52, + height: 52, + borderRadius: 16, + }, + brandCopy: { + flex: 1, + }, + eyebrow: { + color: "#B9B2DF", + fontSize: 12, + fontWeight: "700", + letterSpacing: 0, + marginBottom: 2, + textTransform: "uppercase", + }, + appTitle: { + color: colors.card, + fontSize: 28, + fontWeight: "800", + letterSpacing: 0, + }, + tabBar: { + flexDirection: "row", + backgroundColor: "#332A61", + borderRadius: 8, + padding: 4, + }, + tab: { + alignItems: "center", + borderRadius: 6, flex: 1, + minHeight: 40, + justifyContent: "center", + }, + activeTab: { + backgroundColor: colors.card, + }, + tabText: { + color: "#D9D4F4", + fontSize: 14, + fontWeight: "700", + }, + activeTabText: { + color: colors.ink, + }, + pageIndicator: { + height: 32, + marginHorizontal: -4, + marginTop: 12, + }, + sectionTitle: { + color: colors.card, + fontSize: 18, + fontWeight: "700", + marginTop: 2, + }, + page: { + flex: 1, + backgroundColor: colors.page, }, scrollView: { - backgroundColor: '#F5FCFF', + backgroundColor: colors.page, }, container: { - justifyContent: 'center', - alignItems: 'center', - paddingVertical: 20, - }, - title: { - fontSize: 30, - color: pageViewPositionSlider.thumbColor, - textAlign: 'center', - width: '100%', - marginVertical: 20, - }, - instructions: { - textAlign: 'center', - color: '#333333', - marginBottom: 5, - fontSize: 20, - }, - sliderWidget: { - marginVertical: 30, + alignItems: "center", + paddingHorizontal: 20, + paddingTop: 18, + paddingBottom: 28, + }, + sliderCard: { + alignSelf: "center", + backgroundColor: colors.card, + borderColor: colors.border, + borderRadius: 8, + borderWidth: StyleSheet.hairlineWidth, + marginBottom: 14, + maxWidth: 460, + paddingHorizontal: 18, + paddingVertical: 18, + width: "100%", + boxShadow: "0 8px 18px rgba(16, 24, 40, 0.08)" as never, + }, + cardTitle: { + alignSelf: "stretch", + color: colors.ink, + flexShrink: 1, + flexWrap: "wrap", + fontSize: 16, + fontWeight: "700", + lineHeight: 22, + marginBottom: 12, + maxWidth: "100%", + textAlign: "center", + whiteSpace: "normal" as never, }, }); diff --git a/example-web/src/Examples.tsx b/example-web/src/Examples.tsx index b91f4307..3b186354 100644 --- a/example-web/src/Examples.tsx +++ b/example-web/src/Examples.tsx @@ -1,24 +1,30 @@ -import React, {useState} from 'react'; -// @ts-ignore -import {Text, View, StyleSheet, ScrollView} from 'react-native'; -// @ts-ignore -import Slider, {SliderProps} from '@react-native-community/slider'; +import React, {type FC, type JSX, useCallback, useState} from "react"; +import {Image, StyleSheet, Text, View} from "react-native"; +import Slider, {type MarkerProps, type SliderProps} from "@react-native-community/slider"; export interface Props { title: string; - render(): React.ReactElement; + render(): JSX.Element; platform?: string; } +const CONSTANTS = { + MAX_VALUE: 100, + MIN_VALUE: 10, + STEP: 10, +} as const; + const SliderExample = (props: SliderProps) => { - const [value, setValue] = useState(0); + const [value, setValue] = useState(props.value ?? 0); return ( - + {value && +value.toFixed(3)} @@ -32,7 +38,7 @@ const SlidingStartExample = (props: SliderProps) => { { + onSlidingStart={value => { setSlideStartingValue(value); setSlideStartingCount(prev => prev + 1); }} @@ -51,7 +57,7 @@ const SlidingCompleteExample = (props: SliderProps) => { { + onSlidingComplete={value => { setSlideCompletionValue(value); setSlideCompletionCount(prev => prev + 1); }} @@ -63,186 +69,682 @@ const SlidingCompleteExample = (props: SliderProps) => { ); }; +const SlidingStepsExample = (props: SliderProps) => { + const renderStepMarker = useCallback(({stepMarked}: MarkerProps) => { + return stepMarked ? ( + + + + ) : ( + + + + ); + }, []); + + return ( + + ); +}; + +const SlidingStepsNumbersExample = (props: SliderProps) => { + const renderStepMarker = useCallback(({stepMarked}: MarkerProps) => { + return stepMarked ? ( + + + + ) : ( + + + + ); + }, []); + + return ( + + ); +}; + +const SlidingStepsSmallNumbersExample = (props: SliderProps) => { + const renderStepMarker = useCallback(({stepMarked}: MarkerProps) => { + return stepMarked ? ( + + + + ) : ( + + + + ); + }, []); + + return ( + + ); +}; + +const SlidingCustomStepsThumbImageNumbersExample = (props: SliderProps) => { + const renderStepMarker = useCallback(({stepMarked}: MarkerProps) => { + return stepMarked ? ( + + + + ) : ( + + + + ); + }, []); + + return ( + + ); +}; + +const SlidingCustomStepsAnotherThumbImageNumbersExample = ( + props: SliderProps, +) => { + const renderStepMarker = useCallback(({stepMarked}: MarkerProps) => { + return stepMarked ? ( + + + + ) : ( + + + + ); + }, []); + + return ( + + ); +}; + +const InvertedSliderWithStepMarker = (props: SliderProps) => { + const renderStepMarker = useCallback(({stepMarked}: MarkerProps) => { + return stepMarked ? ( + + + + ) : ( + + + + ); + }, []); + + return ( + + ); +}; + +const SlidingCustomStepsThumbImageWithNumbersAndDifferentWidth = ( + props: SliderProps, +) => { + const renderStepMarker = useCallback(({stepMarked}: MarkerProps) => { + return stepMarked ? ( + + ) : ( + + ); + }, []); + + return ( + + ); +}; + +const MyStepMarker: FC = ({stepMarked, currentValue}) => { + return stepMarked ? ( + + + + {currentValue !== undefined ? ( + + {currentValue % 1 === 0 ? currentValue : currentValue.toFixed(2)} + + ) : ( + - + )} + + + + ) : ( + + ); +}; + +const CustomComponent: FC = ({ + stepMarked, + currentValue, + index, + max, +}) => { + if (stepMarked) { + return ( + + + {index} + + + {max} + + / + + ); + } + + return currentValue > index ? ( + + ) : ( + + ); +}; + +const SliderExampleWithCustomMarker = (props: SliderProps) => { + const [value, setValue] = useState(props.value ?? CONSTANTS.MIN_VALUE); + + return ( + + {value && +value.toFixed(3)} + + + ); +}; + +const SliderExampleWithCustomComponentAndFilledSteps = (props: SliderProps) => { + const [value, setValue] = useState(props.value || 50); + + return ( + + {value && +value.toFixed(3)} + + + ); +}; + export default SliderExample; const styles = StyleSheet.create({ + text: { + fontSize: 14, + textAlign: "center", + fontWeight: "500", + margin: 0, + }, + exampleContainer: { + alignItems: "center", + alignSelf: "stretch", + }, + trackText: { + color: "#FFFFFF", + fontSize: 10, + justifyContent: "center", + alignSelf: "center", + top: 12, + }, + trackDividerText: { + left: 18, + position: "absolute", + }, + trackDot: { + width: 10, + height: 10, + borderRadius: 10, + top: 4, + }, + empty: { + backgroundColor: "#B3BFC9", + }, + filled: { + backgroundColor: "#00629A", + }, + customComponentFrame: { + flex: 1, + flexDirection: "row", + top: -10, + opacity: 0.95, + }, + customComponentLeftFrame: { + height: 40, + width: 20, + borderTopLeftRadius: 40, + borderBottomLeftRadius: 40, + }, + customComponentRightFrame: { + height: 40, + width: 20, + borderTopRightRadius: 40, + borderBottomRightRadius: 40, + }, + divider: { + width: 2, + height: 20, + backgroundColor: "#ffffff", + justifyContent: "center", + alignItems: "center", + }, + separator: { + width: 2, + height: 20, + backgroundColor: "#00629A", + justifyContent: "center", + alignItems: "center", + }, + label: { + marginTop: 10, + width: 55, + paddingVertical: 5, + paddingHorizontal: 10, + backgroundColor: "#ffffff", + boxShadow: "0 1px 4px rgba(0, 0, 0, 0.4)" as never, + justifyContent: "center", + alignItems: "center", + }, + background: { + justifyContent: "center", + alignItems: "center", + }, + tinyLogo: { + marginVertical: 2, + aspectRatio: 1, + flex: 1, + height: "100%", + width: "100%", + }, slider: { - width: 300, + alignSelf: "stretch", opacity: 1, - height: 50, marginTop: 10, + height: 44, }, - text: { - fontSize: 14, - textAlign: 'center', - fontWeight: '500', - margin: 0, + narrowSlider: { + width: 200, + }, + outer: { + width: 20, + height: 20, + borderRadius: 10, + backgroundColor: "#11FF11", + justifyContent: "center", + alignItems: "center", + }, + outerTrue: { + width: 20, + height: 20, + borderRadius: 10, + backgroundColor: "#0F0FFF", + justifyContent: "center", + alignItems: "center", + }, + inner: { + width: 10, + height: 10, + borderRadius: 5, + backgroundColor: "#111111", + }, + innerTrue: { + width: 10, + height: 10, + borderRadius: 5, + backgroundColor: "#0F0FFF", + }, + offsetStepMarker: { + top: 3, + }, + container: { + alignItems: "center", + }, + customMarkerContainer: { + alignItems: "center", + paddingBottom: 80, + }, + outerSmall: { + width: 4, + height: 4, + top: 6, + borderRadius: 2, + backgroundColor: "#003366", + justifyContent: "center", + alignItems: "center", + }, + outerTrueSmall: { + width: 8, + height: 8, + borderRadius: 2, + backgroundColor: "#ABCDEF", + justifyContent: "center", + alignItems: "center", + }, + innerSmall: { + width: 7, + height: 7, + borderRadius: 1, + backgroundColor: "#223366", + }, + innerTrueSmall: { + width: 7, + height: 7, + borderRadius: 1, + backgroundColor: "#334488", }, }); export const examples: Props[] = [ { - title: 'Default settings', + title: "Default settings", render() { return ; }, }, { - title: 'Initial value: 0.5', + title: "Initial value: 0.5", render() { return ; }, }, { - title: 'minimumValue: -1, maximumValue: 2', - render(): React.ReactElement { + title: "minimumValue: -1, maximumValue: 2", + render() { return ; }, }, { - title: 'lowerLimit: 2, upperLimit: 7', - render(): React.ReactElement { - return ; + title: "step: 0.25, tap to seek on iOS", + render() { + return ; + }, + }, + { + title: "Limit on positive values [30, 80]", + render() { + return ( + + ); }, }, { - title: 'step: 0.25, tap to seek on iOS', - render(): React.ReactElement { - return ; + title: "Limit on negative values [-70, -20]", + render() { + return ( + + ); }, }, { - title: 'onSlidingStart', - render(): React.ReactElement { + title: "onSlidingStart", + render() { return ; }, }, { - title: 'onSlidingComplete', + title: "onSlidingComplete", render() { return ; }, }, { - title: 'Custom min/max track tint color', + title: "Custom min/max track tint color", render() { return ( ); }, }, { - title: 'Custom thumb tint color', + title: "Custom thumb tint color", render() { - return ; + return ; }, }, { - title: 'Custom thumb image', + title: "Custom thumb image", render() { - return ( - - ); + return ; }, }, { - title: 'Custom thumb (network image)', - platform: 'windows', + title: "Custom thumb (network image)", + platform: "windows", render() { return ( ); }, }, { - title: 'Custom track image', - platform: 'ios', + title: "Custom track image", render() { - return ; + return ; }, }, { - title: 'Custom min/max track image', - platform: 'ios', + title: "Custom min/max track image", render() { return ( ); }, }, { - title: 'Inverted slider direction', + title: "Slider with customized indicator and no numbers", + render() { + return ; + }, + }, + { + title: "Slider with customized indicator and default numbers", + render() { + return ; + }, + }, + { + title: "Slider with smaller customized indicator and default numbers", + render() { + return ; + }, + }, + { + title: "Slider with custom steps, thumbImage and steps numbers", + render() { + return ; + }, + }, + { + title: "Slider with custom steps, different thumbImage and steps numbers", + render() { + return ; + }, + }, + { + title: "Slider with custom steps, different width and thumbImage", + render() { + return ; + }, + }, + { + title: "Inverted slider direction with steps number and thumbImage", + render() { + return ; + }, + }, + { + title: "Custom step marker settings", + render() { + return ; + }, + }, + { + title: "Custom component with steps filled when passed", + render() { + return ; + }, + }, + { + title: "Inverted slider direction", render() { return ; }, }, { - title: 'Vertical slider', - platform: 'windows', + title: "Vertical slider", + platform: "windows", render() { return ; }, }, { - title: 'Disabled slider', + title: "Disabled slider", render() { return ; }, }, { - title: 'Slider with accessibilityState disabled', - platform: 'android', + title: "Slider with accessibilityState disabled", + platform: "android", render() { return ; }, }, { - title: 'Slider in horizontal scroll view', + title: "Custom thumb size (no image)", render() { - return ( - - - - - Scroll right, then slide âž” - - - - ); + return ; }, }, - // Check the fix for the issue #743 { - title: 'With step numbers', + title: "Custom thumb size (scaled image)", render() { return ( ); }, diff --git a/example-web/src/Props.tsx b/example-web/src/Props.tsx index 715e8e40..bff0bdb5 100644 --- a/example-web/src/Props.tsx +++ b/example-web/src/Props.tsx @@ -1,20 +1,24 @@ -import React, {useState} from 'react'; -// @ts-ignore -import {Text, View, StyleSheet} from 'react-native'; -// @ts-ignore -import Slider, {SliderProps} from '@react-native-community/slider'; +import React, {type JSX, useState} from "react"; +import {StyleSheet, Text, View} from "react-native"; +import Slider, {type SliderProps} from "@react-native-community/slider"; export interface Props { title: string; - render(): React.ReactElement; + render(): JSX.Element; + platform?: string; } const SliderExample = (props: SliderProps) => { const [value, setValue] = useState(0); return ( - + {value && +value.toFixed(3)} - + ); }; @@ -26,7 +30,7 @@ const SlidingStartExample = (props: SliderProps) => { { + onSlidingStart={value => { setSlideStartingValue(value); setSlideStartingCount(prev => prev + 1); }} @@ -44,7 +48,7 @@ const SlidingCompleteExample = () => { return ( { + onSlidingComplete={value => { setSlideCompletionValue(value); setSlideCompletionCount(prev => prev + 1); }} @@ -59,143 +63,143 @@ const SlidingCompleteExample = () => { export default SliderExample; const styles = StyleSheet.create({ + exampleContainer: { + alignSelf: "stretch", + }, slider: { - width: 300, + alignSelf: "stretch", opacity: 1, height: 50, marginTop: 10, }, text: { fontSize: 14, - textAlign: 'center', - fontWeight: '500', + textAlign: "center", + fontWeight: "500", margin: 0, }, }); export const propsExamples: Props[] = [ { - title: 'Default settings', + title: "Default settings", render() { return ; }, }, { - title: 'disabled', + title: "disabled", render() { return ; }, }, { - title: 'maximumValue', + title: "maximumValue", render() { return ; }, }, { - title: 'minimumTrackTintColor', + title: "minimumTrackTintColor", render() { return ; }, }, { - title: 'minimumValue', + title: "minimumValue", render() { - return ; + return ; }, }, { - title: 'onSlidingStart', + title: "onSlidingStart", render() { return ; }, }, { - title: 'onSlidingComplete', + title: "onSlidingComplete", render() { return ; }, }, { - title: 'onValueChange', + title: "onValueChange", render() { return ; }, }, { - title: 'step', + title: "step", render() { return ; }, }, { - title: 'maximumTrackTintColor', + title: "maximumTrackTintColor", render() { return ; }, }, { - title: 'value', + title: "value", render() { return ; }, }, { - title: 'tapToSeek', - render(): React.ReactElement { - return ; + title: "tapToSeek", + render() { + return ; }, }, { - title: 'inverted', + title: "inverted", render() { return ; }, }, { - title: 'vertical', + title: "vertical", + platform: "windows", render() { return ; }, }, { - title: 'thumbTintColor', + title: "thumbTintColor", render() { - return ; + return ; }, }, { - title: 'maximumTrackImage', + title: "maximumTrackImage", render() { return ( ); }, }, { - title: 'minimumTrackImage', + title: "minimumTrackImage", render() { return ( - + ); }, }, { - title: 'thumbImage', + title: "thumbImage", render() { - return ( - - ); + return ; }, }, { - title: 'trackImage', + title: "trackImage", render() { - return ; + return ; }, }, ]; diff --git a/example-web/src/index.css b/example-web/src/index.css index ec2585e8..f32236ad 100644 --- a/example-web/src/index.css +++ b/example-web/src/index.css @@ -1,5 +1,6 @@ body { margin: 0; + min-height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; @@ -7,6 +8,15 @@ body { -moz-osx-font-smoothing: grayscale; } +html, +#root { + min-height: 100%; +} + +body { + background: #f3f5fa; +} + code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; diff --git a/example-web/src/react-native-shim.d.ts b/example-web/src/react-native-shim.d.ts new file mode 100644 index 00000000..0bd6e49a --- /dev/null +++ b/example-web/src/react-native-shim.d.ts @@ -0,0 +1,82 @@ +declare module "react-native" { + import type * as React from "react"; + + export type AccessibilityActionEvent = any; + export type ColorValue = string; + export type GestureResponderEvent = any; + export type HostComponent

= React.ComponentType

; + export type ImageSource = any; + export type ImageSourcePropType = any; + export type ImageStyle = Record; + export type LayoutChangeEvent = { + nativeEvent: { + layout: { + width: number; + height: number; + x: number; + y: number; + }; + }; + }; + export type NativeSyntheticEvent = {nativeEvent: T}; + export type StyleProp = T | T[] | null | undefined; + export type TextStyle = Record; + export type ViewProps = Record; + export type ViewStyle = Record; + + export const Image: any; + export const Platform: { + OS: string; + select(options: Record): T; + }; + export const Pressable: any; + export const ScrollView: any; + export const StyleSheet: any; + export const Text: any; + export const View: any; +} + +declare module "react-native/Libraries/Image/ImageSource" { + export type ImageSource = any; +} + +declare module "react-native/Libraries/Types/CodegenTypes" { + export type DirectEventHandler = (event: {nativeEvent: T}) => void; + export type Double = number; + export type Float = number; + export type WithDefault = T; +} + +declare module "react-native/Libraries/Utilities/codegenNativeComponent" { + import type {HostComponent} from "react-native"; + + export default function codegenNativeComponent

( + componentName: string, + ): HostComponent

; +} + +declare module "@react-native-community/slider" { + import type * as React from "react"; + import type {ViewProps} from "react-native"; + + export type MarkerProps = { + stepMarked: boolean; + currentValue: number; + index: number; + min: number; + max: number; + }; + + export type SliderProps = ViewProps & + Readonly<{ + [key: string]: any; + onSlidingComplete?: (value: number) => void; + onSlidingStart?: (value: number) => void; + onValueChange?: (value: number) => void; + StepMarker?: React.FC; + renderStepNumber?: boolean; + }>; + + const Slider: React.ForwardRefExoticComponent; + export default Slider; +} diff --git a/example-web/src/resources/ck-icon.png b/example-web/src/resources/ck-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9e527f58a1a5af67ea98c56ba82c48f56cf104 GIT binary patch literal 2809 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 A761SM literal 0 HcmV?d00001 diff --git a/example-web/src/resources/empty.png b/example-web/src/resources/empty.png new file mode 100644 index 0000000000000000000000000000000000000000..503d58bb6e05388ca8e11591fe008445042fa068 GIT binary patch literal 1723 zcmeAS@N?(olHy`uVBq!ia0vp^Oh7Ei!3HG1f2kE@U|`|RbaoE#baqwWn zu;}d#jm?k=6|vi0oUW{LE;z@ewPb}ouPX24Fq4H_cGcg#YnC_7)9jYgi22_w?^N0K2#ll^XlDy^Ve>7lND7cluz3HYz22mKjVkxp{L6jtA0(Cw|^BS_butg zc0-3F`c*p~CSN~XY**Ktnf65I(d7=-(BQ0&=>q*{j{b1t`E9u2TKodvtk8#V$l`emN?Wy$mR$DaR^6kr-7oS_E z>9YS>I(sGry+QY;|M(KHklotQs>6+V^t# zMlcJeXgILl7rT+MvYC&~NMx;uWLNycG;!(Y2W&oBZJBxY;J!ms{+&1x-~4mOxh+~L z?RHIKo235qtr5GN`f+t@OtP?josKz^y_%$g(9P!aaYmlsCKehoDphvb_6yZ;W}V zV;;Eek>uQ6;pcwF|9t(&=$rPRtR)ZXpM-zhUUWR_%u@yEVpeU^&4UoBQCu|56ewCpuripn{na$-e? z%pL|N8hujd;YfB0ywNyq?d#uS^Y!Q1%JL=4KU@AgW}jXdW9RRUOkaHeg@%T_ESRDx z8ot4Y1a4mzVv^Y zZM2(TI9ktr&TpOr`|Lly`K|Y;ZwtdTnTE#W%6Ss!PqE))wfNj}Yt!w6vJ*XOxF1~k z{^r~MUq%&mf3Li}bEJ69bKQom=GJrf-+y0n&CcQfYKHXQdd3CwYeEAO{^bM92ba_c z&op0O1}z|)gMo=rh=Cc%Vgy2l_DlvAFq?rv4M+n^l?6<25vB#qa5k`j0RoL9VL&B} znIRD+5xzcF$@#f@i7EL>sd^Q;1z-g>6;?oIZfZ%QLPc&)Ua?h$trA#;6_5=Q)>l#h zD=EpgRf_NpP;kyKN>wn^Gte_ovg1-vP_QXVNwW%aaf50H@@$ndN=gc>^!3Zj%k|2Q z_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUl_7?}%yCIAPAXNgv1=R{lkqslX5dg@c`;jXs7L zRK1NpD3Fi>4H6?@QDBtVaoOm@qt}kBShdp(80S2mE{-7_vdIY&OMtwY42;+0JRgA4 Nf~TvW%Q~loCIBSf$L|0D literal 0 HcmV?d00001 diff --git a/example-web/src/resources/twitter-small.png b/example-web/src/resources/twitter-small.png new file mode 100644 index 0000000000000000000000000000000000000000..fb1f11f39f65e8150815f6a23ceb3eab0d206435 GIT binary patch literal 4052 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 literal 0 HcmV?d00001 diff --git a/example/App.tsx b/example/App.tsx index 86ab6300..ece512e1 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -1,63 +1 @@ -/** - * Sample React Native App - * https://github.com/facebook/react-native - * - * @format - */ - -import Slider from "@react-native-community/slider"; -import { useState } from "react"; -import { StyleSheet, Text, View } from "react-native"; - -function App() { - return ( - - ); -} - -function AppContent() { - const [sliderValue, setSliderValue] = useState(0); - - return ( - - {sliderValue.toFixed(2)} - { - setSliderValue(value); - console.log('value', value); - }} - step={5} - minValue={50} - maxValue={100} - style={{ - padding: 20, - width: "80%", - height: 40, - backgroundColor: "transparent", - }} - /> - - ); -} - -const styles = StyleSheet.create({ - container: { - padding: 10, - gap: 10, - justifyContent: "center", - alignItems: "center", - flex: 1, - }, - stepMarker: { - backgroundColor: "red", - width: 10, - height: 10, - }, - slider: { - color: "red", - width: "70%", - height: 40, - }, -}); - -export default App; +export {default} from "./src/App"; diff --git a/example/Gemfile.lock b/example/Gemfile.lock new file mode 100644 index 00000000..14e521c4 --- /dev/null +++ b/example/Gemfile.lock @@ -0,0 +1,114 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.9) + activesupport (6.1.7.10) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) + algoliasearch (1.27.5) + httpclient (~> 2.8, >= 2.8.3) + json (>= 1.5.1) + atomos (0.1.3) + benchmark (0.5.0) + bigdecimal (4.1.2) + claide (1.1.0) + cocoapods (1.15.2) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.15.2) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.15.2) + activesupport (>= 5.0, < 8) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (2.1) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.2.0) + colored2 (3.1.2) + concurrent-ruby (1.3.3) + escape (0.0.4) + ethon (0.18.0) + ffi (>= 1.15.0) + logger + ffi (1.17.4) + fourflusher (2.3.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + httpclient (2.9.0) + mutex_m + i18n (1.14.8) + concurrent-ruby (~> 1.0) + json (2.7.6) + logger (1.7.0) + minitest (5.25.4) + molinillo (0.8.0) + mutex_m (0.3.0) + nanaimo (0.3.0) + nap (1.1.0) + netrc (0.11.0) + nkf (0.3.0) + public_suffix (4.0.7) + rexml (3.4.4) + ruby-macho (2.5.1) + typhoeus (1.6.0) + ethon (>= 0.18.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + xcodeproj (1.25.1) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (>= 3.3.6, < 4.0) + zeitwerk (2.6.18) + +PLATFORMS + ruby + +DEPENDENCIES + activesupport (>= 6.1.7.5, != 7.1.0) + benchmark + bigdecimal + cocoapods (>= 1.13, != 1.15.1, != 1.15.0) + concurrent-ruby (< 1.3.4) + logger + mutex_m + nkf + xcodeproj (< 1.26.0) + +RUBY VERSION + ruby 2.6.10p210 + +BUNDLED WITH + 1.17.2 diff --git a/example/__tests__/App.test.tsx b/example/__tests__/App.test.tsx index e532f701..b0446b41 100644 --- a/example/__tests__/App.test.tsx +++ b/example/__tests__/App.test.tsx @@ -6,6 +6,11 @@ import React from 'react'; import ReactTestRenderer from 'react-test-renderer'; import App from '../App'; +jest.mock('react-native-pager-view', () => { + const {View} = require('react-native'); + return ({children}: {children: React.ReactNode}) => {children}; +}); + test('renders correctly', async () => { await ReactTestRenderer.act(() => { ReactTestRenderer.create(); diff --git a/example/android/app/src/main/java/com/example/MainActivity.kt b/example/android/app/src/main/java/com/example/MainActivity.kt index 35dff7f9..b9ef55b2 100644 --- a/example/android/app/src/main/java/com/example/MainActivity.kt +++ b/example/android/app/src/main/java/com/example/MainActivity.kt @@ -11,7 +11,7 @@ class MainActivity : ReactActivity() { * Returns the name of the main component registered from JavaScript. This is used to schedule * rendering of the component. */ - override fun getMainComponentName(): String = "example" + override fun getMainComponentName(): String = "SliderExample" /** * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] diff --git a/example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..38ed19d2 --- /dev/null +++ b/example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..38ed19d2 --- /dev/null +++ b/example/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a2f5908281d070150700378b64a84c7db1f97aa1..554a17c362ba6d0c35f0e141a47abd5386eaf52a 100644 GIT binary patch delta 3211 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 A{{R30 literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index 1b523998081149a985cef0cdf89045b9ed29964a..c5c36174eea6ece4e0809ff1358756206dccc3a8 100644 GIT binary patch literal 4318 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 M07*qoM6N<$f_X1NXaE2J literal 5024 zcmV;R6JP9!P)T-ViIFIPY+_yk1-RB&z5bHD$YnPieqLK5EI`ThRCq%$YyeCI#k z>wI&j0Rb2DV5|p6T3Syaq)GU^8BR8(!9qaEe6w+TJxLZtBeQf z`>{w%?oW}WhJSMi-;YIE3P2FtzE8p;}`HCT>Lt1o3h65;M`4J@U(hJSYlTt_?Ucf5~AOFjBT-*WTiV_&id z?xIZPQ`>7M-B?*vptTsj)0XBk37V2zTSQ5&6`0#pVU4dg+Hj7pb;*Hq8nfP(P;0i% zZ7k>Q#cTGyguV?0<0^_L$;~g|Qqw58DUr~LB=oigZFOvHc|MCM(KB_4-l{U|t!kPu z{+2Mishq{vnwb2YD{vj{q`%Pz?~D4B&S9Jdt##WlwvtR2)d5RdqcIvrs!MY#BgDI# z+FHxTmgQp-UG66D4?!;I0$Csk<6&IL09jn+yWmHxUf)alPUi3jBIdLtG|Yhn?vga< zJQBnaQ=Z?I+FZj;ke@5f{TVVT$$CMK74HfIhE?eMQ#fvN2%FQ1PrC+PAcEu?B*`Ek zcMD{^pd?8HMV94_qC0g+B1Z0CE-pcWpK=hDdq`{6kCxxq^X`oAYOb3VU6%K=Tx;aG z*aW$1G~wsy!mL})tMisLXN<*g$Kv)zHl{2OA=?^BLb)Q^Vqgm?irrLM$ds;2n7gHt zCDfI8Y=i4)=cx_G!FU+g^_nE(Xu7tj&a&{ln46@U3)^aEf}FHHud~H%_0~Jv>X{Pm z+E&ljy!{$my1j|HYXdy;#&&l9YpovJ;5yoQYJ+hw9>!H{(^6+$(%!(HeR~&MP-UER zPR&hH$w*_)D3}#A2joDlamSP}n%Y3H@pNb1wE=G1TFH_~Lp-&?b+q%;2IF8njO(rq zQVx(bn#@hTaqZZ1V{T#&p)zL%!r8%|p|TJLgSztxmyQo|0P;eUU~a0y&4)u?eEeGZ z9M6iN2(zw9a(WoxvL%S*jx5!2$E`ACG}F|2_)UTkqb*jyXm{3{73tLMlU%IiPK(UR4}Uv87uZIacp(XTRUs?6D25qn)QV%Xe&LZ-4bUJM!ZXtnKhY#Ws)^axZkui_Z=7 zOlc@%Gj$nLul=cEH-leGY`0T)`IQzNUSo}amQtL)O>v* zNJH1}B2znb;t8tf4-S6iL2_WuMVr~! zwa+Are(1_>{zqfTcoYN)&#lg$AVibhUwnFA33`np7$V)-5~MQcS~aE|Ha>IxGu+iU z`5{4rdTNR`nUc;CL5tfPI63~BlehRcnJ!4ecxOkD-b&G%-JG+r+}RH~wwPQoxuR(I z-89hLhH@)Hs}fNDM1>DUEO%{C;roF6#Q7w~76179D?Y9}nIJFZhWtv`=QNbzNiUmk zDSV5#xXQtcn9 zM{aI;AO6EH6GJ4^Qk!^F?$-lTQe+9ENYIeS9}cAj>Ir`dLe`4~Dulck2#9{o}JJ8v+QRsAAp*}|A^ z1PxxbEKFxar-$a&mz95(E1mAEVp{l!eF9?^K43Ol`+3Xh5z`aC(r}oEBpJK~e>zRtQ4J3K*r1f79xFs>v z5yhl1PoYg~%s#*ga&W@K>*NW($n~au>D~{Rrf@Tg z^DN4&Bf0C`6J*kHg5nCZIsyU%2RaiZkklvEqTMo0tFeq7{pp8`8oAs7 z6~-A=MiytuV+rI2R*|N=%Y));j8>F)XBFn`Aua-)_GpV`#%pda&MxsalV15+%Oy#U zg!?Gu&m@yfCi8xHM>9*N8|p5TPNucv?3|1$aN$&X6&Ge#g}?H`)4ncN@1whNDHF7u z2vU*@9OcC-MZK}lJ-H5CC@og69P#Ielf`le^Om4BZ|}OK33~dC z9o-007j1SXiTo3P#6`YJ^T4tN;KHfgA=+Bc0h1?>NT@P?=}W;Z=U;!nqzTHQbbu37 zOawJK2$GYeHtTr7EIjL_BS8~lBKT^)+ba(OWBsQT=QR3Ka((u#*VvW=A35XWkJ#?R zpRksL`?_C~VJ9Vz?VlXr?cJgMlaJZX!yWW}pMZni(bBP>?f&c#+p2KwnKwy;D3V1{ zdcX-Pb`YfI=B5+oN?J5>?Ne>U!2oCNarQ&KW7D61$fu$`2FQEWo&*AF%68{fn%L<4 zOsDg%m|-bklj!%zjsYZr0y6BFY|dpfDvJ0R9Qkr&a*QG0F`u&Rh{8=gq(fuuAaWc8 zRmup;5F zR3altfgBJbCrF7LP7t+8-2#HL9pn&HMVoEnPLE@KqNA~~s+Ze0ilWm}ucD8EVHs;p z@@l_VDhtt@6q zmV7pb1RO&XaRT)NOe-&7x7C>07@CZLYyn0GZl-MhPBNddM0N}0jayB22swGh3C!m6~r;0uCdOJ6>+nYo*R9J7Pzo%#X_imc=P;u^O*#06g*l)^?9O^cwu z>?m{qW(CawISAnzIf^A@vr*J$(bj4fMWG!DVMK9umxeS;rF)rOmvZY8%sF7i3NLrQ zCMI5u5>e<&Y4tpb@?!%PGzlgm_c^Z7Y6cO6C?)qfuF)!vOkifE(aGmXko*nI3Yr5_ zB%dP>Y)esVRQrVbP5?CtAV%1ftbeAX zSO5O8m|H+>?Ag7NFznXY-Y8iI#>Xdz<)ojC6nCuqwTY9Hlxg=lc7i-4fdWA$x8y)$ z1cEAfv{E7mnX=ZTvo30>Vc{EJ_@UqAo91Co;@r;u7&viaAa=(LUNnDMq#?t$WP2mu zy5`rr8b||Z0+BS)Iiwj0lqg10xE8QkK#>Cp6zNdxLb-wi+CW5b7zH2+M4p3Cj%WpQ zvV+J2IY@kOFU_|NN}2O}n#&F1oX*)lDd-WJICcPhckHVB{_D}UMo!YA)`reITkCv& z+h-AyO1k3@ZEIrpHB)j~Z(*sF@TFpx2IVtytZ1!gf7rg2x94b*P|1@%EFX{|BMC&F zgHR4<48Z5Wte`o!m*m@iyK=>9%pqjT=xfgQua>)1| zzH!~jLG!rggat+qAIR%H=jrI#Ppid$J{TDkck^wb>Cbnli}}Mj8!tNfx{tXtDDVA6#7kU4k)m;JoI1>JM_ zq-flQ5dpn>kG~=9u{Kp+hETG^OCq!Y^l7JkwUJNUU7izHmd|F@nB0=X2`Ui?!twzb zGEx%cIl)h?ZV$NTnhB6KFgkkRg&@c7ldg>o!`sBcgi%9RE?paz`QmZ@sF(jo1bt^} zOO5xhg(FXLQ|z)6CE=`kWOCVJNJCs#Lx)8bDSWkN@122J_Z`gpPK4kwk4&%uxnuQ z^m`!#WD#Y$Wd7NSpiP4Y;lHtj;pJ#m@{GmdPp+;QnX&E&oUq!YlgQ%hIuM43b=cWO zKEo!Er{mwD8T1>Qs$i2XjF2i zo0yfpKQUwdThrD(TOIY_s`L@_<}B|w^!j*FThM0+#t0G?oR`l(S(2v&bXR}F6HLMU zhVvD4K!6s}uUD^L;|Sxgrb+kFs%8d8Ma>5A9p~uUO=yF*;%~xvAJiA`lls1pq5J%k z6&-yQ$_vP5`-Tr56ws&75Y&Q2;zD?CB_KpRHxzC9hKCR0889>jef)|@@$A?!QIu3r qa)363hF;Bq?>HxvTY6qhhx>m(`%O(!)s{N|00002F-s8OHCw(gF=hjF)&koA zmIMgIi5+7HZ%Mq5mzl&)YzQh6s8T6Gq=Zy0Ab}w431JZg1f=k_{nAPx(tdiYv%lxu zbMH7RVx&jOT;DnO_q^vh?>+ZA+kUYdw*PVu)ZFrGsJ-S?Uo(?09IC(tcZekSbi;&s28^ zB6WwUqV)q1tsjI~!x1Wnz~3R^e~aMng~qM-LtxuJ1b#rmhUo>+MO->4)x1e*zo*b{ za0NdE@g0wX<9`poUsjxg*FHiA7XwG>z)1XJOoucPAaApW5U_%dP-r_iQDVn1IPTam z_$CQ|KvtX#&R_>1)}W?QX%J%dOi_990s5Or-R2avLJROA37%*ifkfj`aB3~^0T+Bf z9Xv+CkI;bvZO0UxFCgA|N_ zCiwuV02$;c8;lM-%&H?VIAk$YO+#9>^@=O-6j9SCIQ3ihLWAfwV!`svtIBiu#$gIf zew=O^g>=&x{WldDWdr(}ahuX)oX39a0Zy(*uRRV1C*8^LCjv{+y@8qikoF-Vi^1}DJrjZXbxn&CK) z4H<;OhbAG{d>nG2WAy(SZp1w!k7*H8hU`ij&`AM}!JEeU^(N`H9Wy%a>JPcAuNknJ zuo>ZIq#>k$0@kZ-1D}9QXp&#|I5FU}aB1~f_J32GDPaP`H0MDP2<$iOIvnxK)< zz<)IplL*9ZNXd2%E{qn*Hv$E=i7=bTQ zIe77E@!<=Y8VJ}8oLxT;2lkbuu6_P3J$|Nq5gtGFauvOz=?S7$qF1Tb%P&`fUw?#R zd=VVI`bK>C0#*jbGz06a=b+}+JyiMBLHO*`>+n;3KK}4J>}flxW@^V&1(8tsei@kXJKLLPc%Yi<}rL*Vg(%4d5r2C@eu|(kO8mH z+VV?~CXu7FW{TZ~GeWi-8*j1I;M&3UFu6%Hf9>4tFSFkI; z0)?18_eBc74DG1;)PT5Y>1|U*rzFLq~(hC zOIopRz>JP}^*d9iz=@mDF>>FNpM$HHzy8VkyRU&lS;1@7*A0m3cYmgd0bA}xy9x+w#$?CbF%)$dHNg5w8I7i(|=IAb!1Ka$Z)rM@^yK>A==s$Q zbZ7?Fz`?KS1bo&CkE?FEYZ}0+n=rM8ryvs?^ALN}q2hBB2HbDE^w$^GXVHiWZbFy- zKgG>8up}3;W*|ch1jj8ejnsP=&!-~uj;R4GYAPDvnMz7l1Ak~1kO8#@R+$0+$mnkX z@?PKw6i>Zdi!ON@iMv~=YNN=2XP2?O0kDBvVH4`sPsF}+SI&BgE8$B19K}N8NwuHGJN}kp4%{>l| zcU(+x1dU+3sm>^6k>qi9o-~wR+k}y2xrGo9@ttXv{odRL>}oj+juqV4b1QHIn1Zg; zYE)A)lTdypL+ZPo^Jl6x2J#wi=CBryLW=zSa^zF$_ zW=sL^28T@CrX_#PX8Wb4PQOJTavU{;9fJz0623uo8>onR28$wE8QT9~`Q*Nt#%Ge1 zM%{xY5vQnwgMU8av{W#sKUN}j)0FVqmiI-es>83rs&_l5$nM$_r`oQdMs{0wJFVCp z&uM%n*&Y1u`kt^xRvEN9ncDf;6-Wh(!T#n|hLHUj1{vDzqxyEcqz~Ezmi2_wbp>^u zL8&I5?WDjiX7Qu}=I4t9`G435HO)Jpt^;4tottB%?uUE#zt^RaO&$**I5GbJM-Nj& zZ#XT#=iLsG7*JO@)I~kH1#tl@P}J@i#`XX!EPt%401s8_l?fjW{Bn{`kB?Jy|7T?4 z8B^bD?2XW^ok249gs7%7z;d@{{8E^W zw4}3P%eP+%f6uD|N(^9{v8zNzQGgXz-8Los!Y$wmXQIF;&%(BY2lzQY&2tg7h#%Ay z4kZE0AH~2#7AoT`g#A3W#7Kt4$uXNRX_<>h#Q`kvWAs3Y+9)i~V zyAb3%4t+;Ej~o)%J#d6}9XXtC1AiZLdpB<#)Uur{`;-H9r|3HYA>+;5F2+ZPzh?zp zR27yL(EHj*@3-VXi1of!Dzv{XP!qJ%64%Cb8z^>dqNOY^bZj7<6L?3UKI$bM_tm+9 zO#%&ZACucedQXcCj)AJkgaSHmtAv@z`&L3xBBKKC7NLNeJctVgROCUtA%E`IkjHbY zIL(%aoNRqr0c0kfyCwgJ`o@kRJcfXTKE)yJ>mMNB46|t!KFa69@jiIYIR? zuJe6Z9^@b1+DQ$G05t*~GVbGDz&(92YUCBTiC5w#E*o+^56pBkSIdObGr%qb7}=UN z?T)nN6}JI##qx^VfV^UP8Gmh574=YgI5h*lHhBhI8%GM)&eD<67_g?v!)?+EsK|r3 zP(VcWQ*3Y59boFa2Yjup+HQnfJF{s#K78F zKGcgTXVQH9lNHDzU}Xg+$b72haw2?svnhFLW`t zOLF-~Ht(_`U2)0l&Ao-Tw}v>ABz4Y>BPbi9-lS-&P#bb5i@hxxS+TD*Src-l+q^y` z3$1S@%|VAK1%GUB3)J&?+}8oFcLYoUYqHGOCf-?S+c31~rRVwST-ab`D=sd+ zh-(WNm!D-U5M0ja$2$j0h5hjhCt$x&+s-DNN#AVaWgTP>*mKw1xPAxe%7rDusX+w* O00002F-s8OHCw(gF=hjF)&koAmIMgIi5+7HZ%Mq5mzl&)YzQh6s8T6G zq=Zy0Ab}w431JZg1f=k_{nAPx(tdiYv%lxubMH7RVx&jOT;DnO_q^vh?>+ZA+kUYd zw*PVu)ZFrGsJ-JdZicxaQ-ep`ExDqP#oRCfp>b%&{<^#c&CAB0%L5h{nk-yz|Di{S5t z#;x~5VB0^b5TskP#yh&-lr_gS21wRDw9gl+J55HeloPyUrLI)QEN9n*w z{9;UpG!YdGP`I zn@HW}6tzMN@F5AFXdHn=<56&GE${&sd_NsLM!}EJff95eU9>XfLJdPMQ&Fh_iv~66 zMNt)xOYjj$HXem!;4yIOHUS@{@PibLfF}6>sQ?+|C>x9pJj|*iFF0f|R82!#we^ZC z@Dx$gC^+?7_CkZ`He$i@%&W?C_{L!hOn#hh8ijPz82vXD7-a+cnsJ-bWSqx->j6%# zN3T5&PQ#XaV8`vGRg&D3Zu1arYbx^t5N|j_2P5zVI1?O)Y;b~#{69kn8>1C*8^LCj zv{+y@8qikoF-Vi^1}DJrjZXbxn&CK)4H<;OhbAG{d>nG2WAy(SZp1w!k7*H8hU`ij z&`AM}!JEeU^(N`H9Wy%a>JPcAuNknJuo>ZIq#>k$0@kZ-1D}9QXp&#|I5FU}aB1~f z_EXfrm@*JLCPltygV==4h%)0AI>&$(QBhTA;Ix3vC&2NmK5LmOKG=XTA!dM?n2;vi zM$kIZG-jML?gM^Ig6Ep2pd~y-4A^_VTD%qmWC06kY(O(%8nGD~*MLoE6%|qS6I2Ae zB|HtS;Tdpn^~HWf@B72Zz$k~BppntQH4~Ev#BE5)b`CC#9+wtgbqXJuf!4?@IQH$r zfXcsNKrAMG7W|BOnc-FD(q~i$H>*zI^O0G|N9Vwy)vtNj6(5m*dh=@3Z(a}X-GJeP zPc!vnJww%zo~>@q1a()yg&2V^Q8{?=YVqLLM!4V+y+4+r*@q^^DbEj@mwd=VZ$ z^>P)xqUi~uRiam^*2^zffnS7Td=VVI`bK>C0#*jbGz06a=b+}+JyiMBLHO*`>+n;3 zKK}4J>}flxW@^V&1(8tsm1AMVPWb|G(u+P zF??HM1sv6RjOrWl5e7Pt0k6;6@=K5=k)yL_irs}XLbe+lZ?VB3EPvi7!;yCUI;QJmK4u6=LA9>xtj1 z`l3>I_0GfoyUSD$?5!9&3EAc`y%mP1VWj^L@Z!14@Z$4!J+<*V>hU`KP7Ys8a05wZ zpd(cQNA!IR?^S(u`=8MF=fO$7H)6fsRqgN$oGJgsH+EOv{~G!V6$!68j(7DtQYVQ4 z9Gypv=T8RTm79a!`~vjmOR%dzvUXAz0bA}xy9x+w#$?CbF%)$dHNg5w8I7i(|= zIk{>ef%hzH?d3 z_{~I-n_w}r7^qftoN@DsNT?0LDy?wY{)WvU6A~UZ05JhqqDays;i z6q{nvuZ7q#vIRCx*-bF;g2jYspqm&_Rrh{%;ReUR7`Eae-4HW_W`mp14a`fC@1}t+ zVZas_^C_qpUpByXV6nOK7C%QbgJ%QHLafBs8ey5^H#gltCozy&gYN7ZaIA5$R2)N# zUaWMA?M;NzTI&BgE8$B19K}N8N zwuHGJN}kp4%{>l|cU(+x1dU+3sm>^6k>qi9o-~wR+k}y2xrGo9@ttXv{odRL>}oj+ zjuqV4b1QHIn1Zg;YE)AcdPx#07*qoM6N<$f>762p#T5? literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index 115a4c768a20c9e13185c17043f4c4d12dd4632a..8d1c343dc939c54c2d7a84beaf9f1589fbf1e9ff 100644 GIT binary patch delta 2925 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 delta 2852 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�^;{2hysuW z7^$B%O$Vs}x4Ll!Z}cQP3Jmhy}3QP`v-+>0e6(xYUg` zcxl=(=s3jo@Wl$NOh+-xP>B#KiCY)U67c%L_W$zquWfo5yrgww3tk6Z3A>OWf)t$$ zeJzRW0>3+A>xhfR;@cri|Jvq7hdti zE1v#G;D+Wy;JMWezPQHV71J(2*TQa07=;*>j6@>p)mK~jmmdlIDK-3H`fqG`6g-!@ zk#{vRczN1I=qlJVe%2%m{dr7^PKK)p`5IGv2Q=UL7<{&RZfH5g2uNBtOx5t<#d;B; z>tG*rj82M91}~!Ba-C3TDwuk{^HKQC6#h-Ehrx53dJTAK+HIgSAe-c@jq)&)_}{Ug zQHfE>Xt$O@g{P p=#LD1Tgz^xG4N*iH!ph}{s(3ZbpU4BNTUD%002ovPDHLkV1oR`E4=^! literal 4569 zcmV;~5hm`5P)gh-ObE_muwxq>sEpX)ywtgCHKIATY}p&%F4bRV>R9rYpeWbT(xnE7}?(HDXFgNDdC^@gUdK& zk=MolYT3>rpR*$Ell2!`c zjrIZftl&PUxlH2EgV+3VfQy&FjhL&5*Zg&R8xrSx?WgB?YuLO-JDaP3jr*I~qiywy z`-52AwB_6L#X ztms{{yRkRfQLbsb#Ov%`)acN(OCewI3Ex__xed17hg#g4c1blx?sK}UQg%PM@N;5d zsg{y6(|`H1Xfbz@5x{1688tu7TGkzFEBhOPDdFK(H_NQIFf|(>)ltFd!WdnkrY&mp z0y@5yU2;u1_enx%+U9tyY-LNWrd4^Wi?x<^r`QbaLBngWL`HzX@G550 zrdyNjhPTknrrJn#jT0WD0Z)WJRi&3FKJ#Sa&|883%QxM-?S%4niK{~k81<(c11sLk|!_7%s zH>c$`*nP-wA8Dx-K(HE~JG_@Yxxa;J+2yr+*iVlh;2Eiw?e`D1vu6*qY1+XTe8RVu z?RV%L|Mk!wO}j^S)p4H%?G37StD0Rx{_Y00%3a+V^SyOkfV@ZuFlEc;vR9r-D>cYU&plUkXL|M%1AYBQ3DI;;hF%_X@m*cTQAMZ4+FO74@AQB{A*_HtoXT@}l=8awaa7{RHC>07s?E%G{iSeRbh z?h#NM)bP`z`zdp5lij!N*df;4+sgz&U_JEr?N9#1{+UG3^11oQUOvU4W%tD1Cie3; z4zcz0SIrK-PG0(mp9gTYr(4ngx;ieH{NLq{* z;Pd=vS6KZYPV?DLbo^)~2dTpiKVBOh?|v2XNA)li)4V6B6PA!iq#XV5eO{{vL%OmU z0z3ZE2kcEkZ`kK(g^#s)#&#Zn5zw!R93cW^4+g0D=ydf&j4o_ti<@2WbzC>{(QhCL z(=%Zb;Ax8U=sdec9pkk|cW)1Ko;gK{-575HsDZ!w@WOQ^Up)GGorc38cGxe<$8O!6 zmQ`=@;TG{FjWq(s0eBn5I~vVgoE}un8+#YuR$Asq?lobvVAO-`SBs3!&;QEKT>gZ0T)jG^Foo~J2YkV&mi-axlvC}-(J4S2 z;opuO)+FIV#}&4;wwisb>{XU+FJ~tyK7UaG@ZD^C1^brazu7Xkh5Od}&P)GufW=u# zMxOwfWJ3a^MZha>9OmQ)@!Y;v*4@+dg~s~NQ;q@hV~l>lw`P)d`4XF9rE?aEFe(JV zI>11}Ny%^CkO=VN>wCV?P!-?VdT3vWe4zBLV*?6XPqsC%n93bQXvydh0Mo+tXHO4^ zxQ{x0?CG{fmToCyYny7>*-tNh;Sh9=THLzkS~lBiV9)IKa^C~_p8MVZWAUb)Btjt< zVZ;l7?_KnLHelj>)M1|Q_%pk5b?Bod_&86o-#36xIEag%b+8JqlDy@B^*YS*1; zGYT`@5nPgt)S^6Ap@b160C4d9do0iE;wYdn_Tr(vY{MS!ja!t*Z7G=Vz-=j5Z⁣ zwiG+x#%j}{0gU~J8;<|!B1@-XaB@{KORFwrYg_8rOv({b0EO#DbeQRm;B6_9=mXGf z-x|VL{zd`)#@yN}HkCSJbjbNlE|zL3Wm9Q8HY`sV)}3%pgN>cL^67{Z;PPL(*wT8N zUjXU{@|*hvm}({wsAC=x0^ok0%UAz0;sogW{B!nDqk|JJ5x~4NfTDgP49^zeu`csl?5mY@JdQdISc zFs!E{^grmkLnUk9 zny~m)1vws@5BFI<-0Tuo2JWX(0v`W|t(wg;s--L47WTvTMz-8l#TL^=OJNRS2?_Qj z3AKT+gvbyBi#H*-tJ%tWD|>EV3wy|8qxfzS!5RW;Jpl5*zo&^UBU=fG#2}UvRyNkK zA06Dy9;K1ca@r2T>yThYgI!ont$(G{6q#2QT+00r_x0(b)gsE`lBB?2gr55gq^D3Fi&p%E(p9>U%bv zkg1Jco(RbyTX7FDHOnl7-O@ zI$AaIl?9NJKPm(WiBP`1-#CB1QzU>&hKm)fpa5DKE{2$X0hGz-0uZ?cyTk(YC!Y&| zL=1VrNERSA5NA2jq7FACfX4JfPyj5XXl1yv0>~s;eF7L2$>&oMqeTFT2m$y7FlkON z_yurD1yIOvA;5C6016pyxBznGUt0kJ&k5r#;&>Jow`r)sp9R~PmK~lz$3xH%LT*1U zJdOyABZ3!FvNoR*vN$5ykHS8f`jA4zV+|L}i1C4`B2c{R0;UdYxaU|H)2avz@ z=mEYc|2S<+(B2Tj+FkX+2D+yFI!k9lWMA61DJ{)e;lum$(;O87?vGJJe!KtK04+N_ zI*P~t@dUb>9Xh{dbyl{-ZQ(UMgz7$|QfL5XSPkskt^NgctYC#;4WcZB1@%@wy@2t3 z2z0DI7&%b$*Aw~abe?GxE`ez@+6hOh-6*8fHRV{1os$EL@}uUZeG4h1&Be`98q*7j z=3-v+lhIjfWVo12!<>%V^a6lTgW3+_#W6n|p*~==zOH7z$0{LSZk(Tpd7EaD04hnA zL;#fxS0aD{`5^&D`}>0Uq?byDD-l2=!wm_bLcUl4gc(% za1p|itVANvFF>hghAS07Im1;IK;|b*W)}VDyI;BIp2=K*yu2a)j?B|f<44NI$NbmJ z#dE0>jI$fMr&@>4kN8MLFb4&2O9fEKaQg%(QO$4_1rVQywG^CmBLh#}_7gKW3vd?| z2?1^&KWq8}8I^_S0|)MowU_pw$q@nl@Nkn$z>BQq_KA^9yaR`(R3u{{Ig;cwt z@AJ^{ODQCm^neroM9nKNUAXi9RCK`OsP_LuR0PUR(YZCCX5dNF6VzcoK&=b^r`W?ltt|*F zpkoae%ZT{C1h~EcFui~b7fF`vb<<~j_VquuUA$}QqIKYELPp#;{u?q8Dz}WAG-(3; zjrm$i%7UbyZMM(Y{>!uJ#vNB?R~B{6Htp=>e*<{fQQ5W7V(1coCWlOON!MzZxhum| ztZBQpGR z;~#ur^&PockKdV{Q6R>o`Pl{0x!DEbpZ7y9Y;*ZvE!*gU`V1W3znva{f=?WO5I&>B z&hw6}tjECtaghm5z|C#%M;Yf_*pI^};h}Vl=^r9EN=tVDj86D;C$jIJ?K7VP+00000NkvXXu0mjf D5i!M* diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4765dc0cbf1708ed4c31242b5f4443b0c4a2fa3f GIT binary patch literal 4295 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�^;{2hysuW z7^$B%O$Vs}x4Ll!Z}cQP3Jmhy}3QP`v-+>0e6(xYUg` zcxl=(=s3jo@Wl$NOh+-xP>B#KiCY)U67c%L_W$zquWfo5yrgww3tk6Z3A>OWf)t$$ zeJzRW0>3+A>xhfR;@cri|Jvq7hdti zE1v#G;D+Wy;JMWezPQHV71J(2*TQa07=;*>j6@>p)mK~jmmdlIDK-3H`fqG`6g-!@ zk#{vRczN1I=qlJVe%2%m{dr7^PKK)p`5IGv2Q=UL7<{&RZfH5g2uNBtOx5t<#d;B; z>tG*rj82M91}~!Ba-C3TDwuk{^HKQC6#h-Ehrx53dJTAK+HIgSAe-c@jq)&)_}{Ug zQHfE>Xt$O@g{P p=#LD1Tgz^xG4N*iH!ph}{s(3ZbpU4BNTUD%002ovPDHLkV1oR`E4=^! literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index 459ca609d3ae0d3943ab44cdc27feef9256dc6d7..557bde87f721b1db40a5ca129067dd68d7bb49a6 100644 GIT binary patch literal 5836 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 diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 8ca12fe024be86e868d14e91120a6902f8e88ac6..b7a136b8ab1ba2a98375d3039476600bb9a1bd69 100644 GIT binary patch literal 6468 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 B0*L?s diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..b7a136b8ab1ba2a98375d3039476600bb9a1bd69 GIT binary patch literal 6468 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 F{{a;PY`_2j literal 10676 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 diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..80099b8de69b733480760ff2883c43ecef214a90 GIT binary patch literal 8641 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 Yp2fxTo%8H3&;h{C%Gt8sA|USn062P6LI3~& literal 15523 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 BIP(Ai diff --git a/example/android/app/src/main/res/values/colors.xml b/example/android/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..4f7ef9f1 --- /dev/null +++ b/example/android/app/src/main/res/values/colors.xml @@ -0,0 +1,3 @@ + + #201A3D + diff --git a/example/android/app/src/main/res/values/strings.xml b/example/android/app/src/main/res/values/strings.xml index d75426c8..2649eda6 100644 --- a/example/android/app/src/main/res/values/strings.xml +++ b/example/android/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - example + Slider Example diff --git a/example/app.json b/example/app.json index 3fed6761..c2f0a2db 100644 --- a/example/app.json +++ b/example/app.json @@ -1,4 +1,4 @@ { - "name": "example", - "displayName": "example" + "name": "SliderExample", + "displayName": "Slider Example" } diff --git a/example/assets/slider-example-icon.png b/example/assets/slider-example-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ddbed368790f02d6767ae9de46619d3e508064d7 GIT binary patch literal 54258 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 JevQ>+|36`%6>k6l literal 0 HcmV?d00001 diff --git a/example/ios/Podfile b/example/ios/Podfile index 8963f93d..92ae58af 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -5,7 +5,7 @@ require Pod::Executable.execute_command('node', ['-p', {paths: [process.argv[1]]}, )', __dir__]).strip -platform :ios, min_ios_version_supported +platform :ios, '16.0' prepare_react_native_project! linkage = ENV['USE_FRAMEWORKS'] diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 00000000..eb33b5df --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,2106 @@ +PODS: + - FBLazyVector (0.85.1) + - hermes-engine (250829098.0.10): + - hermes-engine/Pre-built (= 250829098.0.10) + - hermes-engine/Pre-built (250829098.0.10) + - RCTDeprecation (0.85.1) + - RCTRequired (0.85.1) + - RCTSwiftUI (0.85.1) + - RCTSwiftUIWrapper (0.85.1): + - RCTSwiftUI + - RCTTypeSafety (0.85.1): + - FBLazyVector (= 0.85.1) + - RCTRequired (= 0.85.1) + - React-Core (= 0.85.1) + - React (0.85.1): + - React-Core (= 0.85.1) + - React-Core/DevSupport (= 0.85.1) + - React-Core/RCTWebSocket (= 0.85.1) + - React-RCTActionSheet (= 0.85.1) + - React-RCTAnimation (= 0.85.1) + - React-RCTBlob (= 0.85.1) + - React-RCTImage (= 0.85.1) + - React-RCTLinking (= 0.85.1) + - React-RCTNetwork (= 0.85.1) + - React-RCTSettings (= 0.85.1) + - React-RCTText (= 0.85.1) + - React-RCTVibration (= 0.85.1) + - React-callinvoker (0.85.1) + - React-Core (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default (= 0.85.1) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core-prebuilt (0.85.1): + - ReactNativeDependencies + - React-Core/CoreModulesHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/Default (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/DevSupport (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default (= 0.85.1) + - React-Core/RCTWebSocket (= 0.85.1) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTActionSheetHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTAnimationHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTBlobHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTImageHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTLinkingHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTNetworkHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTSettingsHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTTextHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTVibrationHeaders (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTWebSocket (0.85.1): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default (= 0.85.1) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-CoreModules (0.85.1): + - RCTTypeSafety (= 0.85.1) + - React-Core-prebuilt + - React-Core/CoreModulesHeaders (= 0.85.1) + - React-debug + - React-jsi (= 0.85.1) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-NativeModulesApple + - React-RCTBlob + - React-RCTFBReactNativeSpec + - React-RCTImage (= 0.85.1) + - React-runtimeexecutor + - React-utils + - ReactCommon + - ReactNativeDependencies + - React-cxxreact (0.85.1): + - hermes-engine + - React-callinvoker (= 0.85.1) + - React-Core-prebuilt + - React-debug (= 0.85.1) + - React-jsi (= 0.85.1) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-logger (= 0.85.1) + - React-perflogger (= 0.85.1) + - React-runtimeexecutor + - React-timing (= 0.85.1) + - React-utils + - ReactNativeDependencies + - React-debug (0.85.1) + - React-defaultsnativemodule (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-domnativemodule + - React-Fabric/animated + - React-featureflags + - React-featureflagsnativemodule + - React-idlecallbacksnativemodule + - React-intersectionobservernativemodule + - React-jsi + - React-jsiexecutor + - React-microtasksnativemodule + - React-RCTFBReactNativeSpec + - React-webperformancenativemodule + - ReactNativeDependencies + - Yoga + - React-domnativemodule (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-Fabric + - React-Fabric/bridging + - React-FabricComponents + - React-graphics + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-Fabric (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/animated (= 0.85.1) + - React-Fabric/animationbackend (= 0.85.1) + - React-Fabric/animations (= 0.85.1) + - React-Fabric/attributedstring (= 0.85.1) + - React-Fabric/bridging (= 0.85.1) + - React-Fabric/componentregistry (= 0.85.1) + - React-Fabric/componentregistrynative (= 0.85.1) + - React-Fabric/components (= 0.85.1) + - React-Fabric/consistency (= 0.85.1) + - React-Fabric/core (= 0.85.1) + - React-Fabric/dom (= 0.85.1) + - React-Fabric/imagemanager (= 0.85.1) + - React-Fabric/leakchecker (= 0.85.1) + - React-Fabric/mounting (= 0.85.1) + - React-Fabric/observers (= 0.85.1) + - React-Fabric/scheduler (= 0.85.1) + - React-Fabric/telemetry (= 0.85.1) + - React-Fabric/uimanager (= 0.85.1) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/animated (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/animationbackend + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/animationbackend (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/animations (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/attributedstring (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/bridging (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/componentregistry (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/componentregistrynative (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/components/legacyviewmanagerinterop (= 0.85.1) + - React-Fabric/components/root (= 0.85.1) + - React-Fabric/components/scrollview (= 0.85.1) + - React-Fabric/components/view (= 0.85.1) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components/legacyviewmanagerinterop (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components/root (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components/scrollview (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components/view (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-renderercss + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-Fabric/consistency (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/core (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/dom (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/imagemanager (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/leakchecker (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/mounting (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/observers (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/observers/events (= 0.85.1) + - React-Fabric/observers/intersection (= 0.85.1) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/observers/events (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/observers/intersection (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/scheduler (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/animationbackend + - React-Fabric/observers/events + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-performancecdpmetrics + - React-performancetimeline + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/telemetry (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/uimanager (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/uimanager/consistency (= 0.85.1) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/uimanager/consistency (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-FabricComponents (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-FabricComponents/components (= 0.85.1) + - React-FabricComponents/textlayoutmanager (= 0.85.1) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-FabricComponents/components/inputaccessory (= 0.85.1) + - React-FabricComponents/components/iostextinput (= 0.85.1) + - React-FabricComponents/components/modal (= 0.85.1) + - React-FabricComponents/components/rncore (= 0.85.1) + - React-FabricComponents/components/safeareaview (= 0.85.1) + - React-FabricComponents/components/scrollview (= 0.85.1) + - React-FabricComponents/components/switch (= 0.85.1) + - React-FabricComponents/components/text (= 0.85.1) + - React-FabricComponents/components/textinput (= 0.85.1) + - React-FabricComponents/components/unimplementedview (= 0.85.1) + - React-FabricComponents/components/virtualview (= 0.85.1) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/inputaccessory (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/iostextinput (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/modal (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/rncore (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/safeareaview (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/scrollview (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/switch (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/text (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/textinput (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/unimplementedview (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/virtualview (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/textlayoutmanager (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricImage (0.85.1): + - hermes-engine + - RCTRequired (= 0.85.1) + - RCTTypeSafety (= 0.85.1) + - React-Core-prebuilt + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsiexecutor (= 0.85.1) + - React-logger + - React-rendererdebug + - React-utils + - ReactCommon + - ReactNativeDependencies + - Yoga + - React-featureflags (0.85.1): + - React-Core-prebuilt + - ReactNativeDependencies + - React-featureflagsnativemodule (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-featureflags + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-graphics (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-featureflags + - React-jsi + - React-jsiexecutor + - React-utils + - ReactNativeDependencies + - React-hermes (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact (= 0.85.1) + - React-jsi + - React-jsiexecutor (= 0.85.1) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-oscompat + - React-perflogger (= 0.85.1) + - React-runtimeexecutor + - ReactNativeDependencies + - React-idlecallbacksnativemodule (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - React-runtimescheduler + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-ImageManager (0.85.1): + - React-Core-prebuilt + - React-Core/Default + - React-debug + - React-Fabric + - React-graphics + - React-rendererdebug + - React-utils + - ReactNativeDependencies + - React-intersectionobservernativemodule (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-Fabric + - React-Fabric/bridging + - React-graphics + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - React-runtimescheduler + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-jserrorhandler (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - ReactCommon/turbomodule/bridging + - ReactNativeDependencies + - React-jsi (0.85.1): + - hermes-engine + - React-Core-prebuilt + - ReactNativeDependencies + - React-jsiexecutor (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-jserrorhandler + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-utils + - ReactNativeDependencies + - React-jsinspector (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-featureflags + - React-jsi + - React-jsinspectorcdp + - React-jsinspectornetwork + - React-jsinspectortracing + - React-oscompat + - React-perflogger (= 0.85.1) + - React-runtimeexecutor + - React-utils + - ReactNativeDependencies + - React-jsinspectorcdp (0.85.1): + - React-Core-prebuilt + - ReactNativeDependencies + - React-jsinspectornetwork (0.85.1): + - React-Core-prebuilt + - React-jsinspectorcdp + - ReactNativeDependencies + - React-jsinspectortracing (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-jsi + - React-jsinspectornetwork + - React-oscompat + - React-timing + - ReactNativeDependencies + - React-jsitooling (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact (= 0.85.1) + - React-debug + - React-jsi (= 0.85.1) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-runtimeexecutor + - React-utils + - ReactNativeDependencies + - React-jsitracing (0.85.1): + - React-jsi + - React-logger (0.85.1): + - React-Core-prebuilt + - ReactNativeDependencies + - React-Mapbuffer (0.85.1): + - React-Core-prebuilt + - React-debug + - ReactNativeDependencies + - React-microtasksnativemodule (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - react-native-pager-view (6.9.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - react-native-slider (5.2.0): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-NativeModulesApple (0.85.1): + - hermes-engine + - React-callinvoker + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-runtimeexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-networking (0.85.1): + - React-Core-prebuilt + - React-jsinspectornetwork + - React-jsinspectortracing + - React-performancetimeline + - React-timing + - ReactNativeDependencies + - React-oscompat (0.85.1) + - React-perflogger (0.85.1): + - React-Core-prebuilt + - ReactNativeDependencies + - React-performancecdpmetrics (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-jsi + - React-performancetimeline + - React-runtimeexecutor + - React-timing + - ReactNativeDependencies + - React-performancetimeline (0.85.1): + - React-Core-prebuilt + - React-featureflags + - React-jsinspector + - React-jsinspectortracing + - React-perflogger + - React-timing + - ReactNativeDependencies + - React-RCTActionSheet (0.85.1): + - React-Core/RCTActionSheetHeaders (= 0.85.1) + - React-RCTAnimation (0.85.1): + - RCTTypeSafety + - React-Core-prebuilt + - React-Core/RCTAnimationHeaders + - React-debug + - React-featureflags + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactNativeDependencies + - React-RCTAppDelegate (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-CoreModules + - React-debug + - React-defaultsnativemodule + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-jsitooling + - React-NativeModulesApple + - React-RCTFabric + - React-RCTFBReactNativeSpec + - React-RCTImage + - React-RCTNetwork + - React-RCTRuntime + - React-rendererdebug + - React-RuntimeApple + - React-RuntimeCore + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon + - ReactNativeDependencies + - React-RCTBlob (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-Core/RCTBlobHeaders + - React-Core/RCTWebSocket + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - React-RCTNetwork + - ReactCommon + - ReactNativeDependencies + - React-RCTFabric (0.85.1): + - hermes-engine + - RCTSwiftUIWrapper + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-FabricComponents + - React-FabricImage + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-networking + - React-performancecdpmetrics + - React-performancetimeline + - React-RCTAnimation + - React-RCTFBReactNativeSpec + - React-RCTImage + - React-RCTText + - React-rendererconsistency + - React-renderercss + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-RCTFBReactNativeSpec (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec/components (= 0.85.1) + - ReactCommon + - ReactNativeDependencies + - React-RCTFBReactNativeSpec/components (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-NativeModulesApple + - React-rendererdebug + - React-utils + - ReactCommon + - ReactNativeDependencies + - Yoga + - React-RCTImage (0.85.1): + - RCTTypeSafety + - React-Core-prebuilt + - React-Core/RCTImageHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - React-RCTNetwork + - ReactCommon + - ReactNativeDependencies + - React-RCTLinking (0.85.1): + - React-Core/RCTLinkingHeaders (= 0.85.1) + - React-jsi (= 0.85.1) + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactCommon/turbomodule/core (= 0.85.1) + - React-RCTNetwork (0.85.1): + - RCTTypeSafety + - React-Core-prebuilt + - React-Core/RCTNetworkHeaders + - React-debug + - React-featureflags + - React-jsi + - React-jsinspectorcdp + - React-jsinspectornetwork + - React-NativeModulesApple + - React-networking + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactNativeDependencies + - React-RCTRuntime (0.85.1): + - hermes-engine + - React-Core + - React-Core-prebuilt + - React-debug + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-RuntimeApple + - React-RuntimeCore + - React-runtimeexecutor + - React-RuntimeHermes + - React-utils + - ReactNativeDependencies + - React-RCTSettings (0.85.1): + - RCTTypeSafety + - React-Core-prebuilt + - React-Core/RCTSettingsHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactNativeDependencies + - React-RCTText (0.85.1): + - React-Core/RCTTextHeaders (= 0.85.1) + - Yoga + - React-RCTVibration (0.85.1): + - React-Core-prebuilt + - React-Core/RCTVibrationHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactNativeDependencies + - React-rendererconsistency (0.85.1) + - React-renderercss (0.85.1): + - React-debug + - React-utils + - React-rendererdebug (0.85.1): + - React-Core-prebuilt + - React-debug + - ReactNativeDependencies + - React-RuntimeApple (0.85.1): + - hermes-engine + - React-callinvoker + - React-Core-prebuilt + - React-Core/Default + - React-CoreModules + - React-cxxreact + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsitooling + - React-Mapbuffer + - React-NativeModulesApple + - React-RCTFabric + - React-RCTFBReactNativeSpec + - React-RuntimeCore + - React-runtimeexecutor + - React-RuntimeHermes + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - React-RuntimeCore (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-Fabric + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsitooling + - React-performancetimeline + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - React-runtimeexecutor (0.85.1): + - React-Core-prebuilt + - React-debug + - React-featureflags + - React-jsi (= 0.85.1) + - React-utils + - ReactNativeDependencies + - React-RuntimeHermes (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-featureflags + - React-hermes + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-jsitracing + - React-RuntimeCore + - React-runtimeexecutor + - React-utils + - ReactNativeDependencies + - React-runtimescheduler (0.85.1): + - hermes-engine + - React-callinvoker + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - React-jsinspectortracing + - React-performancetimeline + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-timing + - React-utils + - ReactNativeDependencies + - React-timing (0.85.1): + - React-debug + - React-utils (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-debug + - React-jsi (= 0.85.1) + - ReactNativeDependencies + - React-webperformancenativemodule (0.85.1): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-jsi + - React-jsiexecutor + - React-performancetimeline + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - ReactAppDependencyProvider (0.85.1): + - ReactCodegen + - ReactCodegen (0.85.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-FabricImage + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - React-RCTAppDelegate + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - ReactCommon (0.85.1): + - React-Core-prebuilt + - ReactCommon/turbomodule (= 0.85.1) + - ReactNativeDependencies + - ReactCommon/turbomodule (0.85.1): + - hermes-engine + - React-callinvoker (= 0.85.1) + - React-Core-prebuilt + - React-cxxreact (= 0.85.1) + - React-jsi (= 0.85.1) + - React-logger (= 0.85.1) + - React-perflogger (= 0.85.1) + - ReactCommon/turbomodule/bridging (= 0.85.1) + - ReactCommon/turbomodule/core (= 0.85.1) + - ReactNativeDependencies + - ReactCommon/turbomodule/bridging (0.85.1): + - hermes-engine + - React-callinvoker (= 0.85.1) + - React-Core-prebuilt + - React-cxxreact (= 0.85.1) + - React-jsi (= 0.85.1) + - React-logger (= 0.85.1) + - React-perflogger (= 0.85.1) + - ReactNativeDependencies + - ReactCommon/turbomodule/core (0.85.1): + - hermes-engine + - React-callinvoker (= 0.85.1) + - React-Core-prebuilt + - React-cxxreact (= 0.85.1) + - React-debug (= 0.85.1) + - React-featureflags (= 0.85.1) + - React-jsi (= 0.85.1) + - React-logger (= 0.85.1) + - React-perflogger (= 0.85.1) + - React-utils (= 0.85.1) + - ReactNativeDependencies + - ReactNativeDependencies (0.85.1) + - Yoga (0.0.0) + +DEPENDENCIES: + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) + - RCTRequired (from `../node_modules/react-native/Libraries/Required`) + - RCTSwiftUI (from `../node_modules/react-native/ReactApple/RCTSwiftUI`) + - RCTSwiftUIWrapper (from `../node_modules/react-native/ReactApple/RCTSwiftUIWrapper`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Core (from `../node_modules/react-native/`) + - React-Core-prebuilt (from `../node_modules/react-native/React-Core-prebuilt.podspec`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) + - React-defaultsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/defaults`) + - React-domnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/dom`) + - React-Fabric (from `../node_modules/react-native/ReactCommon`) + - React-FabricComponents (from `../node_modules/react-native/ReactCommon`) + - React-FabricImage (from `../node_modules/react-native/ReactCommon`) + - React-featureflags (from `../node_modules/react-native/ReactCommon/react/featureflags`) + - React-featureflagsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/featureflags`) + - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`) + - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-idlecallbacksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks`) + - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) + - React-intersectionobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver`) + - React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`) + - React-jsinspectorcdp (from `../node_modules/react-native/ReactCommon/jsinspector-modern/cdp`) + - React-jsinspectornetwork (from `../node_modules/react-native/ReactCommon/jsinspector-modern/network`) + - React-jsinspectortracing (from `../node_modules/react-native/ReactCommon/jsinspector-modern/tracing`) + - React-jsitooling (from `../node_modules/react-native/ReactCommon/jsitooling`) + - React-jsitracing (from `../node_modules/react-native/ReactCommon/hermes/executor/`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) + - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) + - react-native-pager-view (from `../node_modules/react-native-pager-view`) + - "react-native-slider (from `../node_modules/@react-native-community/slider`)" + - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) + - React-networking (from `../node_modules/react-native/ReactCommon/react/networking`) + - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-performancecdpmetrics (from `../node_modules/react-native/ReactCommon/react/performance/cdpmetrics`) + - React-performancetimeline (from `../node_modules/react-native/ReactCommon/react/performance/timeline`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTFabric (from `../node_modules/react-native/React`) + - React-RCTFBReactNativeSpec (from `../node_modules/react-native/React`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTRuntime (from `../node_modules/react-native/React/Runtime`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-rendererconsistency (from `../node_modules/react-native/ReactCommon/react/renderer/consistency`) + - React-renderercss (from `../node_modules/react-native/ReactCommon/react/renderer/css`) + - React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`) + - React-RuntimeApple (from `../node_modules/react-native/ReactCommon/react/runtime/platform/ios`) + - React-RuntimeCore (from `../node_modules/react-native/ReactCommon/react/runtime`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - React-RuntimeHermes (from `../node_modules/react-native/ReactCommon/react/runtime`) + - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) + - React-timing (from `../node_modules/react-native/ReactCommon/react/timing`) + - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) + - React-webperformancenativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/webperformance`) + - ReactAppDependencyProvider (from `build/generated/ios/ReactAppDependencyProvider`) + - ReactCodegen (from `build/generated/ios/ReactCodegen`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +EXTERNAL SOURCES: + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + hermes-engine: + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :tag: hermes-v250829098.0.10 + RCTDeprecation: + :path: "../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation" + RCTRequired: + :path: "../node_modules/react-native/Libraries/Required" + RCTSwiftUI: + :path: "../node_modules/react-native/ReactApple/RCTSwiftUI" + RCTSwiftUIWrapper: + :path: "../node_modules/react-native/ReactApple/RCTSwiftUIWrapper" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Core: + :path: "../node_modules/react-native/" + React-Core-prebuilt: + :podspec: "../node_modules/react-native/React-Core-prebuilt.podspec" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-debug: + :path: "../node_modules/react-native/ReactCommon/react/debug" + React-defaultsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/defaults" + React-domnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/dom" + React-Fabric: + :path: "../node_modules/react-native/ReactCommon" + React-FabricComponents: + :path: "../node_modules/react-native/ReactCommon" + React-FabricImage: + :path: "../node_modules/react-native/ReactCommon" + React-featureflags: + :path: "../node_modules/react-native/ReactCommon/react/featureflags" + React-featureflagsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/featureflags" + React-graphics: + :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics" + React-hermes: + :path: "../node_modules/react-native/ReactCommon/hermes" + React-idlecallbacksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks" + React-ImageManager: + :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" + React-intersectionobservernativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver" + React-jserrorhandler: + :path: "../node_modules/react-native/ReactCommon/jserrorhandler" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern" + React-jsinspectorcdp: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/cdp" + React-jsinspectornetwork: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/network" + React-jsinspectortracing: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/tracing" + React-jsitooling: + :path: "../node_modules/react-native/ReactCommon/jsitooling" + React-jsitracing: + :path: "../node_modules/react-native/ReactCommon/hermes/executor/" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + React-Mapbuffer: + :path: "../node_modules/react-native/ReactCommon" + React-microtasksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" + react-native-pager-view: + :path: "../node_modules/react-native-pager-view" + react-native-slider: + :path: "../node_modules/@react-native-community/slider" + React-NativeModulesApple: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" + React-networking: + :path: "../node_modules/react-native/ReactCommon/react/networking" + React-oscompat: + :path: "../node_modules/react-native/ReactCommon/oscompat" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-performancecdpmetrics: + :path: "../node_modules/react-native/ReactCommon/react/performance/cdpmetrics" + React-performancetimeline: + :path: "../node_modules/react-native/ReactCommon/react/performance/timeline" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTFabric: + :path: "../node_modules/react-native/React" + React-RCTFBReactNativeSpec: + :path: "../node_modules/react-native/React" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTRuntime: + :path: "../node_modules/react-native/React/Runtime" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-rendererconsistency: + :path: "../node_modules/react-native/ReactCommon/react/renderer/consistency" + React-renderercss: + :path: "../node_modules/react-native/ReactCommon/react/renderer/css" + React-rendererdebug: + :path: "../node_modules/react-native/ReactCommon/react/renderer/debug" + React-RuntimeApple: + :path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios" + React-RuntimeCore: + :path: "../node_modules/react-native/ReactCommon/react/runtime" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + React-RuntimeHermes: + :path: "../node_modules/react-native/ReactCommon/react/runtime" + React-runtimescheduler: + :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" + React-timing: + :path: "../node_modules/react-native/ReactCommon/react/timing" + React-utils: + :path: "../node_modules/react-native/ReactCommon/react/utils" + React-webperformancenativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/webperformance" + ReactAppDependencyProvider: + :path: build/generated/ios/ReactAppDependencyProvider + ReactCodegen: + :path: build/generated/ios/ReactCodegen + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + ReactNativeDependencies: + :podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + FBLazyVector: ed7eadee1965b0b918ca9d0f2c2328f7eb3fd095 + hermes-engine: 9888add417dd3663e57cdee6f9191f5bcad329fc + RCTDeprecation: d69f6f20a20f669a0aa3115ab1109f28e98ae03e + RCTRequired: 305a8212b9d90fa335b6a6a960e5212bbb434484 + RCTSwiftUI: 00bb3e8491b1368a47563ef0c8824601d9875ed3 + RCTSwiftUIWrapper: 4d83c8f35bbd7de17c952e410f9b94490be244e5 + RCTTypeSafety: a5b1d1d5a4612ad3533a4a1302e158e0253b3dac + React: 6dbd7825a18782848e8c62f1feb16b344cb17ac6 + React-callinvoker: 90c70d14c7ca646fdae3e25e8d9fbb0fbb20459c + React-Core: 9dce76263f670de254e896f317676e7e95369ac2 + React-Core-prebuilt: 0a70ddc309d110be89fccf69445735be7aa29bdf + React-CoreModules: b9fadb43261b88cb0d3a2d59808603567e995095 + React-cxxreact: 6b36616248fea28ce6dfbffcf09322321eb96186 + React-debug: 8f85c5da52e386c83482e45744f6e61b39b9493d + React-defaultsnativemodule: 30e203c74356e3c888d65eedf57b17040e6f286e + React-domnativemodule: 1d12e55be7e23893a408080faa0254fb88b4e8ef + React-Fabric: e0865cdb1f6735f4d965205db8272abffa525fe9 + React-FabricComponents: 0ba4d4b82af3c632684b795471c87b6b3f3147bb + React-FabricImage: 697591b17442435a5adfa41f8ba604d739f0577d + React-featureflags: 4ef978e9c5b18e5dcc7cb769d45f8e5dbf0ad33c + React-featureflagsnativemodule: 0ab60626bedd0e6ad3cbd8f91418913622d322d4 + React-graphics: fc1a5a4e43ae3ef5e17c7506d63c0b2e9b6a00bd + React-hermes: 4c79117df85ff676fdac91a44cf9ac14eea27557 + React-idlecallbacksnativemodule: 9cb0992147d2d06c771c71b45a9248b2ed405b09 + React-ImageManager: ebb520b0ff9583be6be10164688e5be5f6c68ea9 + React-intersectionobservernativemodule: c6d0451bec89cfd948dd2fd94562c5ae91cd7581 + React-jserrorhandler: 15687ad69bc1ebe2995bb61dc5fca540f0a49d3b + React-jsi: bc4f2bc01f36aad1b90154f02f94b940f6b47706 + React-jsiexecutor: fda4aaa343879af8a9af8f4421893ead3158578b + React-jsinspector: 4e3b901a6310b055899532c387068a334d95788f + React-jsinspectorcdp: 676d3375831a3869d5ce59ec9ecc964930ad1468 + React-jsinspectornetwork: 06632002a54325a4409b70953a0a1d78afc83d52 + React-jsinspectortracing: 79cffa2fb1ff086386ea0e504088b417b0a92767 + React-jsitooling: 4833c1b0c927dca77b5ce7166006b4ad4bf550b8 + React-jsitracing: d277268ffb96d7ed41e4f1e83f6af47abb109558 + React-logger: 4e7583fb51ef2aa76b298c88e1b9a5cff83e03f7 + React-Mapbuffer: 820bc13d35de93c05aacefb3ab43f061b247c64e + React-microtasksnativemodule: d8115c4d1035b8671c036a47d82fe75d1ca44e44 + react-native-pager-view: a3cb9627d41fa2f31ad2b312af6e3f10f831f26d + react-native-slider: 15f5bd60a3e6a88f4613014355d5c19f5de1b653 + React-NativeModulesApple: 647d3ab78e02b3a40fedffd856744215219ff0a6 + React-networking: 8d40769c4823a7e26ae98ca5cd691edc87828743 + React-oscompat: 934d246490699f24fb70bbc5ca0da7e6808ab80c + React-perflogger: 07bc6f69585cfc2a4ec60d2bff09ca53f8dfcf63 + React-performancecdpmetrics: 34b7669344b3dfd7f41f5591612167a63f7d85bd + React-performancetimeline: c31fffd09036c52f072dfcc9a532ec5645debb28 + React-RCTActionSheet: 99fa17f6886320aaefcac26dde002c6a8eae6e71 + React-RCTAnimation: ff5b5c5f8ad41e785d269b7bd857d92d38b2e331 + React-RCTAppDelegate: a525c6504bafbeeef53e81daafcac858906e4765 + React-RCTBlob: 84a7029433dbb97e2803f7726e849e56c9ba1774 + React-RCTFabric: 4371d3abce8a3f2954f40cf37b21cd644fdfe3a6 + React-RCTFBReactNativeSpec: 84f80cbc48e04a96668e3aad6946ef6ea91aa874 + React-RCTImage: c12912d256e4bd60f2e5c62085ac51369a622e00 + React-RCTLinking: aee9b7e57759ca186e4580ffb3be1321cee06182 + React-RCTNetwork: fed489b87b9f47e6c5825cfd987fda66660c602d + React-RCTRuntime: 46fe512ae3cdcf799398a3ac5e446ea562823d12 + React-RCTSettings: 6c695d74d7f7a89a4a6aba9da20dac8c9e2c810b + React-RCTText: e3f9d1e47e924d316e3e5dc2a64d7c5b5b4d89ce + React-RCTVibration: 9156d7a314da49d274a3bd7d03f1cc85a7da9d15 + React-rendererconsistency: e55d5affcbfbb1e15ffa79c53f573e258a0da8ef + React-renderercss: bd23f6ac348b20fd73c47b1df2b9803da3373c45 + React-rendererdebug: 4c2d4c5515fd56a728331b6b845d21f94c972bb9 + React-RuntimeApple: be0fe2e0c96b42ab0625c2e44def8437a521c6a1 + React-RuntimeCore: c2ad50fc280f1580d34af94bebc0c525e84897dd + React-runtimeexecutor: 8246711ce4255caf2224258851a46253e12b07cc + React-RuntimeHermes: 47cf644941f77934cb186bda64e44b75743151c6 + React-runtimescheduler: 06c596f57cf78a170552efc0189476b6d557c89d + React-timing: 5801dfff49da731d6f982657d8bce8298fa353bf + React-utils: aaf9b3d810f6fbc359ff6a6fb0dd6ea739f0b9f8 + React-webperformancenativemodule: 349b21612ebbbc42316cc849d1942af519eef9b1 + ReactAppDependencyProvider: 52da2413bc956c40a4de19ad32a92b87248f7ce8 + ReactCodegen: aac672d7021359dc55fbd6d63f56192651664f09 + ReactCommon: 66763e5bd1b778828ff6cb82d771b7162a5215c2 + ReactNativeDependencies: 8a42720c7d2edfe6253811788a84becafffc84ac + Yoga: 2e5b12bb8c2f5ad748e7432ba14a4a3c66279050 + +PODFILE CHECKSUM: 590d34dd024e0761540771f5360d7f68941a85fd + +COCOAPODS: 1.16.2 diff --git a/example/ios/example.xcodeproj/project.pbxproj b/example/ios/example.xcodeproj/project.pbxproj index e3163ee6..02a5bb8a 100644 --- a/example/ios/example.xcodeproj/project.pbxproj +++ b/example/ios/example.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; + 9BF521CEDFD20C8F97F91B64 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -159,6 +160,7 @@ files = ( 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 9BF521CEDFD20C8F97F91B64 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -260,7 +262,7 @@ CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = NO; INFOPLIST_FILE = example/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.1; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -289,7 +291,7 @@ CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; INFOPLIST_FILE = example/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.1; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -358,7 +360,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.1; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", @@ -370,6 +372,10 @@ ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = ( + "$(inherited)", + "-DRCT_REMOVE_LEGACY_ARCH=1", + ); OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", @@ -377,8 +383,13 @@ "-DFOLLY_USE_LIBCPP=1", "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", + "-DRCT_REMOVE_LEGACY_ARCH=1", ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; + SWIFT_ENABLE_EXPLICIT_MODULES = NO; + USE_HERMES = true; }; name = Debug; }; @@ -424,7 +435,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.1; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", @@ -435,6 +446,10 @@ "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ( + "$(inherited)", + "-DRCT_REMOVE_LEGACY_ARCH=1", + ); OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", @@ -442,8 +457,12 @@ "-DFOLLY_USE_LIBCPP=1", "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", + "-DRCT_REMOVE_LEGACY_ARCH=1", ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; + SWIFT_ENABLE_EXPLICIT_MODULES = NO; + USE_HERMES = true; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/example/ios/example.xcworkspace/contents.xcworkspacedata b/example/ios/example.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..7f5c3aab --- /dev/null +++ b/example/ios/example.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/ios/example/AppDelegate.swift b/example/ios/example/AppDelegate.swift index eacabc88..edca63bc 100644 --- a/example/ios/example/AppDelegate.swift +++ b/example/ios/example/AppDelegate.swift @@ -24,7 +24,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { window = UIWindow(frame: UIScreen.main.bounds) factory.startReactNative( - withModuleName: "example", + withModuleName: "SliderExample", in: window, launchOptions: launchOptions ) diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-1024.png b/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-1024.png new file mode 100644 index 0000000000000000000000000000000000000000..ddbed368790f02d6767ae9de46619d3e508064d7 GIT binary patch literal 54258 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 JevQ>+|36`%6>k6l literal 0 HcmV?d00001 diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-20@2x.png b/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c46d6ba5c2a967b590602a2337d7355093d71acf GIT binary patch literal 1895 zcmV-t2blPYP)AHeWsnQGt+5@0Scwy65OgnMWE1@(w4SBTf0E%bfbWRsEPQ4iHSs9 zkiPBAa%U4t7d(oxyVjw6VKXWgJ&sVp69^Yh+hi_N*~*T z%Ec|HTD*m;Xe%N`t%wx2AzIvyXvsFjN;=?3xFQAj2+9^bhVq5$U9iH9Y|<(*VWfz( zRjI0Ii@Ok0i&Euc3DTnOH=%Se4i^(}@zU*ZOy?d!*RektsW>FEMD4)L|GRcy{vw49IOqol6J(|&2ob6{C!D>n0Ol-V?zf^hw_4v zs>{3K6ls~0WwqhrCEJiF-HvLysjOS5iz!jo$*%bW|DQTEC<(^l*!<-?kSy<+W znK=%(#f2;DM6$dasfr$?Dtd)_kYtnCu$|hXF0|Ku0i`>pfhE}*eQ-(^$lNs}M5Qg< z#KIgcYGvP)+~IJ&s0r;vO?Vgkn-2B)fOZQ|7uHv0Hk1w4i&Ur&>CjF%rP_}5l(w{k zEl4*KP$s+^naY0l*M#ille0y3@CB_XnDNk|{K3+pU8o7~hQmrr?y=HtVmnrMk0v9R z=q3gzq&u0e(A;E>y0HEdV^n1NJYY59eq<^K-~{bjzA@bF5ePvUfZ<(YQt4)&meF1g zYpB<_?hhuaR5^g!szEpv3uQCr*&{&eaTIEOb1*=eL0use(gh8W7~|gK16DbR+Nvi} zS2YC3Zpgg6?JR!@mOmFT?FZ-!I-lfyyNz;6*BD%62-(OmoX{ffUZrr4H|1@t4e$-J zL$sGZWTXAa#Rrf}3>xx>HRWF4?KI*6nt&+{@Y7GeKy%Zu z(yv#p;{4f5ICk`19DDXgbQ;H=<9hMA(-`b|S(MZZw=_ORfGt{i+g1K(2U8Dp0cR9o zCcY5`x7~}Twf*?@${)Cy*Z%x#B5z)}rHOGk?op~um6rqZ(*!kC>RC2mBHXM1&z-q| z_ulzz9?g05{yTG++WRWo3rSvzk5aO55b)Q;If?opGb_mAD5$NC2+(fp9EDKy;&me9AG+$gOgHk z`HBF4|Lq#O+Go(!#x?iZR|4>`fD0}yxmTZ@CcqA(tyBv*a&LOy@tbNPw8LqqQ%jnoj$`iAZ*D-}`bq*8-hQ74Fz3nMKG!`3I0GjL zj&hd@bz@a_5RFToWLljY!s^^G){vHxMsT;(GF_u8gQrfO!>Kp9u3r6<0d8b~Uib9! zu1HREKz}&%R4bpGb@~Hcoj69!mJuCAW8F9d{QK{JJmP@Q+z{YO2B>8&<#XiL507pi z^FmRkq_VM5v~D;c*$E@A;W7@>R0e`t; z3|I@&ZZig;UD7)3_keu_GQk7{%Z|Uu6&uzBGQi3LXk+Le6LeX%4e2__H_3!5@2bopI6=pqac1wq&nf@_002ovPDHLkV1l>HntcEO literal 0 HcmV?d00001 diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-20@3x.png b/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..236a2b9d9fc922ba33cf0666fb01d5ee1552ffd7 GIT binary patch literal 2687 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 literal 0 HcmV?d00001 diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-29@3x.png b/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6f00c64d1fd821c186cddcce561087013e34de8a GIT binary patch literal 3899 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 JPDHLkV1nR8Y^neN literal 0 HcmV?d00001 diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-40@2x.png b/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..19078cc28dd169b6c1639b49ffdcf9996e875c94 GIT binary patch literal 3607 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 literal 0 HcmV?d00001 diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-40@3x.png b/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a10d00ab670cb9f80f8fb33e733c303312b035e7 GIT binary patch literal 5277 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 literal 0 HcmV?d00001 diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-60@2x.png b/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a10d00ab670cb9f80f8fb33e733c303312b035e7 GIT binary patch literal 5277 zcmV;O6k_X%P)o|rS!Oa>+q5C+w1AriXlXKVGVgZZvpml^&pGdT4NR<=?=K+9y7zOR z=Pd75Sn!!!*@Dm9#%}nl+vD897Jl~5FpEBW7hCkXFR;a7{+cbm=8J5}HFvWm*WS&l zuKg0Ly7nGcb=^Iz`nr2r^>z2Ln(KqCV>Q?R4Xgcpko&{bEm$AtZ&`hi8#aV#xZ!~` z3pa*o4AZY>(S!c7kWas5q@Oqbdk=+a0<(!VEl$%MX0wkmaj%1L)v66)7wBOjR2XlwWo$nPaT1h_fGVc$H4Nz6up?}H&BI{|Zn)`q zE3{;#Y5~|qDlCTCvLwj>F+mmh`ye!v@oYYf13;w$s1C4g9Bh*{_X~|L5iesz} zwPmpmbI_0ha_l|;K7xVbsOT80z`|9V;C3Xy{&2aLEL3e;vGONfL>*+UNve_z8Nz*U z{IjkffD|GdB8;i~pblxP)de<8?HDT-D%u)vB-nW_6M+nsDD|jXy|$_Z$$ETCGIbniMujXYF_l z46So5D!0Lin~bq4Yzi8^kai&>NYd{?;T3R;im%EG60cNUwc5gV)Q*R^AuzT>B`<}@ zZ5e3EN!4Po0%lE;hmnkkk>J}1=&jc1S%ZKYs?{ELtODCv7i23dkZ`Y;w;kPaLD(3y zL&zu+@%t2b68IKPl|yj@q=N#eM%Ym;Y>;9A9L|`by=7<<1D!4FaMKA?g3H4SptYl{ zGt3y0sd=yADqV8)Jp2x=&^e^aHZs5;nA1$Kgijc_C2T*h5#LZ!py zV7uz4SXYCT@DEk7GgWmhJUegCEu$)^2DL+;dpN+B8iH(N1^aP#BW>KRPFr(2=EArs z=r-0Jr>hbkJ3Dlz@J3?TuJ8z?0E(fSsuhMUBCyH(SIE+ulS5|7E|uDvx%F*ay)bSJ z+gKJOVEd@(aRgebZX-G&wPw%`XvJU+E8=zu#ZeA`{kG<$dhynrjJat`PH>ktP7C3o zyL>>`>6cwN#Hb--_Nu4WW^ zD*}zJv9m?HrbkijU`q&W^uA38z_z#mF@U&(L1tGgYyTTiOPrV5>J8X)(gUd_=tX&oX>t3}z4-4(NT{!$l2kzG5PJ`>@ zE+ulyo-%HM7Uk4A2KrqnD1Tfx@abNKexY>uH{0g*xZzHMHj%=zzimvU^q5 zBICejWE!-HUUbT&0TV}cg~h5i!R=|@$qHEYV!Kv$hXci}NgP<-#hOM^c1G^1w}tkV zDGO9nE0$s5s!ec3U}E()FVWAQmGKt?u9x?p%Le2!9uygXZkSTv^gKaHsM%nb0q~wY@QJZ%YCUp0v(gKSXNJ zTey?w%)szbq;k&4ICfWq2xG)=fTIV^0!y#j05-}lRw>^#YSCs6A%~ zp2`PUi=73%45!fn)d99rwLnV_)4Ds(9#$|{F9tlUjKAs4lo0Tw2VlZFIrmHxvfVH%=3vpP-HBH%hkIj; z8w0ykFVvphf$v`=4RM{ip3VNpiu|RVxg;)Cv}B$vo~} zc4OOKR*05HYV|^sEBg2=U$KA#uk75(p83Y>%-7d1e)>B$K6uU&!e=m4Dy+F`buF34 ztpM{k8k4J6+?rI|Gk?*P3-G}DdG_{Oe_%epo;>m0PY@~wyTcL|Z^;5~47)tcYygZ^ zFW#Q<@mHNe%fLkmcyPlBcKMxmJp;d(J7xvc5*3EEsamWhtGFR><@S6P;7#D<%4Ynv z0p7g+7`yzA-wHlEeTZi;3vETpP9d8 zI0a}sJx!GC$ON0IC3EAgj2i*-W3TQ`I6!-rFIuJmmx#dczxRLa^!z`txq}zby#D>4 zpcU*F&=)ElHY@ImI0Z`e(%LhyM9KjC{Bz%9H4DDT7JlvyG+&-R2?9TT=DX~|xmP}> zyc*@aJ{RN6?fbSKx78hYMf*Mo*igN?@fVn2$>#x6fxq+Z*Vv+K?$iR$Y@27F_OHut zzstr4pEk5)c)T^?hQKz}o3%X`>(#BwzjWaL|KLxo{P4wGa94CZngDOoRPUg%danYz ze|_-5AKB!Vr*gqvSpl}LUc5cq%%HCV$H2o+0pqQCjcdYlKm;~E4G;bxU+lqYT zEk@mT<1X_|S;4iRR7JQvum(5p>J3iM$rm^~Y_B7%in}`p+r7&LJM)-tE*m@ z$yEZ}f8XQmcfWnxEAWY<&k; zfBGN20{{2r_t?mT=N)lfXU$^ua=`HO@O-xB5*c?|d!o2``QtVle)8mteh=io^Df)c zf7Tza#l$MXje&>Z4Gm3eHchOG#MbN=m#`_JnGHXA;sx)(!yC^KaCNQOZp|xK@2cWs z959NjU-PQfJ85XmR~nbH%)x=*d-s3YD=+^L%^UypGdeJb>)x7aV{eeY1lWk{IPPw^ z`zV_jKF219&vSVyJcB{a(`;&l&sQti7Uu7aDGRv}N3xb4Wp4*3T#>Billay!R*?8ioN-p|3ZP6=M7xMfma8>dEf@SRKb4__PNDJyh9lX z&n%2GSV?OYciBv}oZ&ES8N)v+J~&Y?kG*I;uFLqlA02;FTpn2S6lqsn{_Zy6e{W1u z77~6>Qx^r--MrN;gEZ$m z0VlI*53(c47ud3T5n!7M)@mNugsVUFSGLF1-NCKd2kag)Y!d&63;z%U&pNedZ@_xo z$sBQQZ)0GFwL+D)5O+>pU~j+mKi+^}e(A^TuD*jGFK|}?Tu0x2ERl}s=7pOPRoXI? z6Pz|QGj*O_IR6s6@RU9m4LLLa9NTcuq44$D0Y8!lu=LPjDz0)i2IVOrGgl7Q04gVV zJ*~k^e#vGp2`+sJ{(c*Tm3TydcD9>-^52e#xuNg725(IVFlVOIZI34MZd`x z086S?1ayU`Sb_VjVjsZSt9HivnF4UtT2^aLnD*d~&{oK4n-*u%WMJ1>GO=oX!ID7t zd5A5vFJwX$TL7<#fc;OT%(ua{fHk7-y8_7oZP~Jw-*0NuCg6OkRyWR4V0EZOln%#a zg3d4jLy^@h8_d9SJn$8)TI}{f#%eV|J}O=H?j9Pr1u_U~Itg!9Tg8^Zv`2;8RjtM4 zlHe6}j~GE$UXhrvv39KkHf*6*fMi(Q!(ZZ?7R=@}{-=?{lv<%EIkvQNP!fupHJ9dM00ZrG3 z_OZt{BWD9nk>NIN1`cr7bU)4tSte25U@bw_Yh!(c1Mj3jTOcFA#)BtP73+Z?Lx8=u z<5|+3Vr*ga0VQHnp#fyIie=nAV9+Yo0hdr5A~D?0(7+*R8Zr(np$cbv^2l5jQ-HY%*3BWX zmv*cfV-2u)`$aH|>h(Bof#LPo@)&K4i~xu4?d~*S6`NbMT)j7UA5DPWo@|NUZjS^@ zMD>E{08W7>B12V-;zGzWaDp2H_vwMNJ^auH_9hS(t5OQeW0mv~l77DhHVTcm>~waG zSFsE%7S`@cyM}=E?Rl=!o06u|y0APr%kdLoHiv)nXM_CRqaT zt~hBG^S~sHFKA{hZC6@MuAu5&+YUA#577Sj{?Q09rW#&wXjMHm=@VdXBMzb34YySOr#U!xU5l<{A&7forf8 zXufS9aDdjFizOW%q_pO>J;&HBJ;!5UZ&i!H0@bRFqX?*q^SGzz&?(ri(BjyfB)uk> zaP|h;n#JmkfUh{L9@U81?KucIh^>PzSweT}PcFDgIjE29Id`X<8Zz#!z4NRiSTih!Y6JNd zL#XH&xQwloQ-|trUxuJt8;IUrKxO;1F1bkZvoHs0`S~*lJz@?5M;@e~E+BY=& zK7<|}>r<}Sm&aTP_ZYjSH?7{=mYrk;{zv#V4?O4gSta{fJZA_#y+CQ?xO6VNjr7i&nB?C j*|J=@0q*TLo@Rdrs{tyLpXKRk00000NkvXXu0mjfEmJJ1 literal 0 HcmV?d00001 diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-60@3x.png b/example/ios/example/Images.xcassets/AppIcon.appiconset/AppIcon-60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6e0add067b3a3fcc67bb6ca09a8765dfff9394a6 GIT binary patch literal 7853 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 en CFBundleDisplayName - example + Slider Example CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -28,7 +28,6 @@ NSAppTransportSecurity - NSAllowsArbitraryLoads NSAllowsLocalNetworking @@ -36,6 +35,8 @@ NSLocationWhenInUseUsageDescription + RCTNewArchEnabled + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/example/ios/example/LaunchScreen.storyboard b/example/ios/example/LaunchScreen.storyboard index a2139fff..4d6c54ad 100644 --- a/example/ios/example/LaunchScreen.storyboard +++ b/example/ios/example/LaunchScreen.storyboard @@ -16,12 +16,12 @@ -

    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 literal 0 HcmV?d00001 diff --git a/package/android/build.gradle b/package/android/build.gradle index 53c7de7b..5744ce1f 100644 --- a/package/android/build.gradle +++ b/package/android/build.gradle @@ -9,12 +9,12 @@ buildscript { classpath("com.android.tools.build:gradle:7.1.1") classpath("com.facebook.react:react-native-gradle-plugin") classpath("de.undercouch:gradle-download-task:5.0.1") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.20") } } plugins { - id 'org.jetbrains.kotlin.plugin.compose' version '2.0.21' + id 'org.jetbrains.kotlin.plugin.compose' version '2.1.20' } apply plugin: 'com.android.library' @@ -22,11 +22,15 @@ apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'com.facebook.react' def getExtOrDefault(name) { - return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeSlider_' + name] + return rootProject.ext.has(name) + ? rootProject.ext.get(name) + : project.properties['ReactNativeSlider_' + name] } def getExtOrIntegerDefault(name) { - return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['ReactNativeSlider_' + name]).toInteger() + return rootProject.ext.has(name) + ? rootProject.ext.get(name) + : (project.properties['ReactNativeSlider_' + name]).toInteger() } android { diff --git a/package/android/gradle.properties b/package/android/gradle.properties new file mode 100644 index 00000000..d7ade578 --- /dev/null +++ b/package/android/gradle.properties @@ -0,0 +1,4 @@ +ReactNativeSlider_compileSdkVersion=36 +ReactNativeSlider_buildToolsVersion=36.0.0 +ReactNativeSlider_targetSdkVersion=36 +ReactNativeSlider_minSdkVersion=24 diff --git a/package/android/src/main/java/com/callstack/slider/InlineComposeView.kt b/package/android/src/main/java/com/callstack/slider/InlineComposeView.kt index 7991aeff..f52c8615 100644 --- a/package/android/src/main/java/com/callstack/slider/InlineComposeView.kt +++ b/package/android/src/main/java/com/callstack/slider/InlineComposeView.kt @@ -51,6 +51,7 @@ abstract class RNCustomRenderComposeView( setViewCompositionStrategy( ViewCompositionStrategy.DisposeOnLifecycleDestroyed(lifecycle), ) + ensureRecomposer() } override fun onAttachedToWindow() { diff --git a/package/android/src/main/java/com/callstack/slider/SliderEvents.kt b/package/android/src/main/java/com/callstack/slider/SliderEvents.kt index 892a339a..f21edd58 100644 --- a/package/android/src/main/java/com/callstack/slider/SliderEvents.kt +++ b/package/android/src/main/java/com/callstack/slider/SliderEvents.kt @@ -18,3 +18,33 @@ class ValueChangedEvent(surfaceId: Int, viewId: Int, private val value: Float) : const val EVENT_NAME = "topValueChange" } } + +class SlidingStartEvent(surfaceId: Int, viewId: Int, private val value: Float) : + Event(surfaceId, viewId) { + + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap = + Arguments.createMap().apply { + putDouble("value", value.toDouble()) + } + + companion object { + const val EVENT_NAME = "topSlidingStart" + } +} + +class SlidingCompleteEvent(surfaceId: Int, viewId: Int, private val value: Float) : + Event(surfaceId, viewId) { + + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap = + Arguments.createMap().apply { + putDouble("value", value.toDouble()) + } + + companion object { + const val EVENT_NAME = "topSlidingComplete" + } +} diff --git a/package/android/src/main/java/com/callstack/slider/SliderView.kt b/package/android/src/main/java/com/callstack/slider/SliderView.kt index 928c7624..8b669fb3 100644 --- a/package/android/src/main/java/com/callstack/slider/SliderView.kt +++ b/package/android/src/main/java/com/callstack/slider/SliderView.kt @@ -1,20 +1,21 @@ package com.callstack.slider +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Slider +import androidx.compose.material3.SliderDefaults +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue -import com.facebook.react.uimanager.ThemedReactContext -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.sizeIn -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.foundation.layout.Box import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import com.facebook.react.uimanager.ThemedReactContext +import kotlin.math.max +import kotlin.math.min @OptIn(ExperimentalMaterial3Api::class) internal class SliderView(reactContext: ThemedReactContext) : @@ -23,33 +24,143 @@ internal class SliderView(reactContext: ThemedReactContext) : private val minValue = mutableStateOf(0f) private val maxValue = mutableStateOf(1f) private val steps = mutableStateOf(0) + private val sliderValue = mutableStateOf(0f) + private val lowerLimit = mutableStateOf(Float.NEGATIVE_INFINITY) + private val upperLimit = mutableStateOf(Float.POSITIVE_INFINITY) + private val disabled = mutableStateOf(false) + private val inverted = mutableStateOf(false) + private val minimumTrackTintColor = mutableStateOf(null) + private val maximumTrackTintColor = mutableStateOf(null) + private val thumbTintColor = mutableStateOf(null) + private val thumbSize = mutableStateOf(0f) + private var isSliding = false fun setMinValue(value: Float) { minValue.value = value + normalizeRange() + clampSliderValue() } fun setMaxValue(value: Float) { maxValue.value = value + normalizeRange() + clampSliderValue() + } + + fun setStep(value: Double) { + steps.value = max(value.toInt(), 0) + } + + fun setValue(value: Float) { + sliderValue.value = clampedValue(value) + } + + fun setLowerLimit(value: Float) { + lowerLimit.value = value + clampSliderValue() + } + + fun setUpperLimit(value: Float) { + upperLimit.value = value + clampSliderValue() + } + + fun setDisabled(value: Boolean) { + disabled.value = value + } + + fun setInverted(value: Boolean) { + inverted.value = value } - fun setStep(value: Int) { - steps.value = value + fun setMinimumTrackTintColor(value: Int?) { + minimumTrackTintColor.value = value + } + + fun setMaximumTrackTintColor(value: Int?) { + maximumTrackTintColor.value = value + } + + fun setThumbTintColor(value: Int?) { + thumbTintColor.value = value + } + + fun setThumbSize(value: Float) { + thumbSize.value = max(value, 0f) } @Composable override fun ComposeContent() { - var sliderPosition by rememberSaveable { mutableStateOf(0f) } val interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } - - Slider( - value = sliderPosition, - onValueChange = { - sliderPosition = it - dispatchEvent(ValueChangedEvent(getSurfaceId(), id, it)) - }, - steps = steps.value, - valueRange = minValue.value..maxValue.value, - interactionSource = interactionSource, + val layoutDirection = + if (inverted.value) { + LayoutDirection.Rtl + } else { + LayoutDirection.Ltr + } + val sliderColors = SliderDefaults.colors( + thumbColor = thumbTintColor.value?.let { Color(it) } ?: Color.Unspecified, + activeTrackColor = minimumTrackTintColor.value?.let { Color(it) } ?: Color.Unspecified, + inactiveTrackColor = maximumTrackTintColor.value?.let { Color(it) } ?: Color.Unspecified, ) + + CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) { + Slider( + value = sliderValue.value, + onValueChange = { + if (!isSliding) { + isSliding = true + dispatchEvent(SlidingStartEvent(getSurfaceId(), id, sliderValue.value)) + } + + val nextValue = clampedValue(it) + sliderValue.value = nextValue + dispatchEvent(ValueChangedEvent(getSurfaceId(), id, nextValue)) + }, + onValueChangeFinished = { + if (isSliding) { + isSliding = false + dispatchEvent(SlidingCompleteEvent(getSurfaceId(), id, sliderValue.value)) + } + }, + steps = steps.value, + valueRange = minValue.value..maxValue.value, + enabled = !disabled.value, + interactionSource = interactionSource, + colors = sliderColors, + thumb = { + if (thumbSize.value > 0f) { + SliderDefaults.Thumb( + interactionSource = interactionSource, + colors = sliderColors, + enabled = !disabled.value, + thumbSize = DpSize(thumbSize.value.dp, thumbSize.value.dp), + ) + } else { + SliderDefaults.Thumb( + interactionSource = interactionSource, + colors = sliderColors, + enabled = !disabled.value, + ) + } + }, + ) + } + } + + private fun normalizeRange() { + if (maxValue.value < minValue.value) { + maxValue.value = minValue.value + } + } + + private fun clampSliderValue() { + sliderValue.value = clampedValue(sliderValue.value) + } + + private fun clampedValue(value: Float): Float { + val lower = max(minValue.value, lowerLimit.value) + val upper = min(maxValue.value, upperLimit.value) + return min(max(value, lower), max(lower, upper)) } } diff --git a/package/android/src/main/java/com/callstack/slider/SliderViewManager.kt b/package/android/src/main/java/com/callstack/slider/SliderViewManager.kt index fa6ec22f..0b23485f 100644 --- a/package/android/src/main/java/com/callstack/slider/SliderViewManager.kt +++ b/package/android/src/main/java/com/callstack/slider/SliderViewManager.kt @@ -1,6 +1,7 @@ package com.callstack.slider import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap import com.facebook.react.module.annotations.ReactModule import com.facebook.react.uimanager.SimpleViewManager import com.facebook.react.uimanager.ThemedReactContext @@ -28,18 +29,70 @@ internal class SliderViewManager : view.onDropInstance() } - override fun setStep(view: SliderView, value: Int) { + override fun setStep(view: SliderView, value: Double) { view.setStep(value) } - override fun setMinValue(view: SliderView, value: Float) { - view.setMinValue(value) + override fun setMinValue(view: SliderView, value: Double) { + view.setMinValue(value.toFloat()) } - override fun setMaxValue(view: SliderView, value: Float) { - view.setMaxValue(value) + override fun setMaxValue(view: SliderView, value: Double) { + view.setMaxValue(value.toFloat()) } + override fun setValue(view: SliderView, value: Float) { + view.setValue(value) + } + + override fun setLowerLimit(view: SliderView, value: Float) { + view.setLowerLimit(value) + } + + override fun setUpperLimit(view: SliderView, value: Float) { + view.setUpperLimit(value) + } + + override fun setDisabled(view: SliderView, value: Boolean) { + view.setDisabled(value) + } + + override fun setInverted(view: SliderView, value: Boolean) { + view.setInverted(value) + } + + override fun setTapToSeek(view: SliderView, value: Boolean) = Unit + + override fun setMinimumTrackTintColor(view: SliderView, value: Int?) { + view.setMinimumTrackTintColor(value) + } + + override fun setMaximumTrackTintColor(view: SliderView, value: Int?) { + view.setMaximumTrackTintColor(value) + } + + override fun setThumbTintColor(view: SliderView, value: Int?) { + view.setThumbTintColor(value) + } + + override fun setThumbSize(view: SliderView, value: Float) { + view.setThumbSize(value) + } + + override fun setVertical(view: SliderView, value: Boolean) = Unit + + override fun setAccessibilityUnits(view: SliderView, value: String?) = Unit + + override fun setAccessibilityIncrements(view: SliderView, value: ReadableArray?) = Unit + + override fun setMaximumTrackImage(view: SliderView, value: ReadableMap?) = Unit + + override fun setMinimumTrackImage(view: SliderView, value: ReadableMap?) = Unit + + override fun setThumbImage(view: SliderView, value: ReadableMap?) = Unit + + override fun setTrackImage(view: SliderView, value: ReadableMap?) = Unit + override fun addEventEmitters(reactContext: ThemedReactContext, view: SliderView) { view.eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id) } diff --git a/package/ios/Slider-Bridging-Header.h b/package/ios/Slider-Bridging-Header.h index 16eb5eb1..b23da03e 100644 --- a/package/ios/Slider-Bridging-Header.h +++ b/package/ios/Slider-Bridging-Header.h @@ -1 +1,2 @@ -#import +#import "RCTComponent.h" +#import "RCTViewManager.h" diff --git a/package/ios/Slider.xcodeproj/project.pbxproj b/package/ios/Slider.xcodeproj/project.pbxproj index ecdc3473..95a2f18d 100644 --- a/package/ios/Slider.xcodeproj/project.pbxproj +++ b/package/ios/Slider.xcodeproj/project.pbxproj @@ -7,8 +7,10 @@ objects = { /* Begin PBXBuildFile section */ - 5E555C0D2413F4C50049A1A2 /* Slider.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* Slider.m */; }; - F4FF95D7245B92E800C19C63 /* Slider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* Slider.swift */; }; + 17E6A4A12CF7B8D100000001 /* SliderComponentView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17E6A4A02CF7B8D100000001 /* SliderComponentView.mm */; }; + 5E555C0D2413F4C50049A1A2 /* SliderViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* SliderViewManager.m */; }; + F4FF95D7245B92E800C19C63 /* SliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* SliderView.swift */; }; + F4FF95D9245B92E800C19C63 /* SliderViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D8245B92E800C19C63 /* SliderViewManager.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -25,9 +27,12 @@ /* Begin PBXFileReference section */ 134814201AA4EA6300B7C361 /* libSlider.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSlider.a; sourceTree = BUILT_PRODUCTS_DIR; }; - B3E7B5891CC2AC0600A0062D /* Slider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Slider.m; sourceTree = ""; }; + 17E6A4A02CF7B8D100000001 /* SliderComponentView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SliderComponentView.mm; sourceTree = ""; }; + 17E6A4A22CF7B8D100000001 /* slider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = slider.h; sourceTree = ""; }; + B3E7B5891CC2AC0600A0062D /* SliderViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SliderViewManager.m; sourceTree = ""; }; F4FF95D5245B92E700C19C63 /* Slider-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Slider-Bridging-Header.h"; sourceTree = ""; }; - F4FF95D6245B92E800C19C63 /* Slider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Slider.swift; sourceTree = ""; }; + F4FF95D6245B92E800C19C63 /* SliderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderView.swift; sourceTree = ""; }; + F4FF95D8245B92E800C19C63 /* SliderViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderViewManager.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -52,8 +57,11 @@ 58B511D21A9E6C8500147676 = { isa = PBXGroup; children = ( - F4FF95D6245B92E800C19C63 /* Slider.swift */, - B3E7B5891CC2AC0600A0062D /* Slider.m */, + 17E6A4A02CF7B8D100000001 /* SliderComponentView.mm */, + F4FF95D6245B92E800C19C63 /* SliderView.swift */, + F4FF95D8245B92E800C19C63 /* SliderViewManager.swift */, + B3E7B5891CC2AC0600A0062D /* SliderViewManager.m */, + 17E6A4A22CF7B8D100000001 /* slider.h */, F4FF95D5245B92E700C19C63 /* Slider-Bridging-Header.h */, 134814211AA4EA7D00B7C361 /* Products */, ); @@ -116,8 +124,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - F4FF95D7245B92E800C19C63 /* Slider.swift in Sources */, - B3E7B58A1CC2AC0600A0062D /* Slider.m in Sources */, + 17E6A4A12CF7B8D100000001 /* SliderComponentView.mm in Sources */, + F4FF95D7245B92E800C19C63 /* SliderView.swift in Sources */, + F4FF95D9245B92E800C19C63 /* SliderViewManager.swift in Sources */, + 5E555C0D2413F4C50049A1A2 /* SliderViewManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -222,12 +232,13 @@ 58B511F01A9E6C8500147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/../../../React/**", - "$(SRCROOT)/../../react-native/React/**", - ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../../../React/**", + "$(SRCROOT)/../../react-native/React/**", + ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = Slider; @@ -241,12 +252,13 @@ 58B511F11A9E6C8500147676 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/../../../React/**", - "$(SRCROOT)/../../react-native/React/**", - ); + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../../../React/**", + "$(SRCROOT)/../../react-native/React/**", + ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = Slider; diff --git a/package/ios/SliderComponentView.mm b/package/ios/SliderComponentView.mm new file mode 100644 index 00000000..bc34c4d1 --- /dev/null +++ b/package/ios/SliderComponentView.mm @@ -0,0 +1,291 @@ +#import +#import +#import +#import +#import + +#if __has_include("slider-Swift.h") +#import "slider-Swift.h" +#elif __has_include("Slider-Swift.h") +#import "Slider-Swift.h" +#endif + +#import +#import +#import +#import + +using namespace facebook::react; + +@interface SliderComponentView : RCTViewComponentView +@end + +typedef void (^SliderLoadImageCompletionBlock)(NSError *error, UIImage *image); +typedef void (^SliderLoadImageFailureBlock)(void); + +@implementation SliderComponentView { + SliderView *_sliderView; +} + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + + _sliderView = [[SliderView alloc] initWithFrame:self.bounds]; + __weak __typeof(self) weakSelf = self; + _sliderView.onValueChange = ^(NSDictionary *event) { + __strong __typeof(self) strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + auto eventEmitter = std::static_pointer_cast(strongSelf->_eventEmitter); + if (eventEmitter == nullptr) { + return; + } + + NSNumber *value = event[@"value"]; + eventEmitter->onValueChange(SliderViewEventEmitter::OnValueChange{ + .value = value.doubleValue + }); + }; + _sliderView.onSlidingStart = ^(NSDictionary *event) { + __strong __typeof(self) strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + auto eventEmitter = std::static_pointer_cast(strongSelf->_eventEmitter); + if (eventEmitter == nullptr) { + return; + } + + NSNumber *value = event[@"value"]; + eventEmitter->onSlidingStart(SliderViewEventEmitter::OnSlidingStart{ + .value = value.doubleValue + }); + }; + _sliderView.onSlidingComplete = ^(NSDictionary *event) { + __strong __typeof(self) strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + auto eventEmitter = std::static_pointer_cast(strongSelf->_eventEmitter); + if (eventEmitter == nullptr) { + return; + } + + NSNumber *value = event[@"value"]; + eventEmitter->onSlidingComplete(SliderViewEventEmitter::OnSlidingComplete{ + .value = value.doubleValue + }); + }; + + self.contentView = _sliderView; + } + + return self; +} + +- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps +{ + const auto &oldSliderProps = *std::static_pointer_cast(_props); + const auto &newSliderProps = *std::static_pointer_cast(props); + + if (oldSliderProps.minValue != newSliderProps.minValue) { + _sliderView.minValue = newSliderProps.minValue; + } + + if (oldSliderProps.maxValue != newSliderProps.maxValue) { + _sliderView.maxValue = newSliderProps.maxValue; + } + + if (oldSliderProps.step != newSliderProps.step) { + _sliderView.step = newSliderProps.step; + } + + if (oldSliderProps.value != newSliderProps.value) { + _sliderView.value = newSliderProps.value; + } + + if (oldSliderProps.lowerLimit != newSliderProps.lowerLimit) { + _sliderView.lowerLimit = newSliderProps.lowerLimit; + } + + if (oldSliderProps.upperLimit != newSliderProps.upperLimit) { + _sliderView.upperLimit = newSliderProps.upperLimit; + } + + if (oldSliderProps.disabled != newSliderProps.disabled) { + _sliderView.disabled = newSliderProps.disabled; + } + + if (oldSliderProps.inverted != newSliderProps.inverted) { + _sliderView.inverted = newSliderProps.inverted; + } + + if (oldSliderProps.tapToSeek != newSliderProps.tapToSeek) { + _sliderView.tapToSeek = newSliderProps.tapToSeek; + } + + if (oldSliderProps.minimumTrackTintColor != newSliderProps.minimumTrackTintColor) { + _sliderView.minimumTrackTintColor = RCTUIColorFromSharedColor(newSliderProps.minimumTrackTintColor); + } + + if (oldSliderProps.maximumTrackTintColor != newSliderProps.maximumTrackTintColor) { + _sliderView.maximumTrackTintColor = RCTUIColorFromSharedColor(newSliderProps.maximumTrackTintColor); + } + + if (oldSliderProps.thumbTintColor != newSliderProps.thumbTintColor) { + _sliderView.thumbTintColor = RCTUIColorFromSharedColor(newSliderProps.thumbTintColor); + } + + if (oldSliderProps.thumbSize != newSliderProps.thumbSize) { + _sliderView.thumbSize = newSliderProps.thumbSize; + } + + if (oldSliderProps.thumbImage != newSliderProps.thumbImage) { + [self loadImageFromImageSource:newSliderProps.thumbImage + completionBlock:^(__unused NSError *error, UIImage *image) { + dispatch_async(dispatch_get_main_queue(), ^{ + self->_sliderView.thumbImage = image; + }); + } + failureBlock:^{ + self->_sliderView.thumbImage = nil; + }]; + } + + if (oldSliderProps.trackImage != newSliderProps.trackImage) { + [self loadImageFromImageSource:newSliderProps.trackImage + completionBlock:^(__unused NSError *error, UIImage *image) { + dispatch_async(dispatch_get_main_queue(), ^{ + self->_sliderView.trackImage = image; + }); + } + failureBlock:^{ + self->_sliderView.trackImage = nil; + }]; + } + + if (oldSliderProps.minimumTrackImage != newSliderProps.minimumTrackImage) { + [self loadImageFromImageSource:newSliderProps.minimumTrackImage + completionBlock:^(__unused NSError *error, UIImage *image) { + dispatch_async(dispatch_get_main_queue(), ^{ + self->_sliderView.minimumTrackImage = image; + }); + } + failureBlock:^{ + self->_sliderView.minimumTrackImage = nil; + }]; + } + + if (oldSliderProps.maximumTrackImage != newSliderProps.maximumTrackImage) { + [self loadImageFromImageSource:newSliderProps.maximumTrackImage + completionBlock:^(__unused NSError *error, UIImage *image) { + dispatch_async(dispatch_get_main_queue(), ^{ + self->_sliderView.maximumTrackImage = image; + }); + } + failureBlock:^{ + self->_sliderView.maximumTrackImage = nil; + }]; + } + + [super updateProps:props oldProps:oldProps]; +} + +- (void)loadImageFromImageSource:(ImageSource)source + completionBlock:(SliderLoadImageCompletionBlock)completionBlock + failureBlock:(SliderLoadImageFailureBlock)failureBlock +{ + NSString *uri = [[NSString alloc] initWithUTF8String:source.uri.c_str()]; + if (!(BOOL)uri.length) { + failureBlock(); + return; + } + + NSURL *url = NSURLFromImageSource(source); + UIImage *localImage = [self localImageForURL:url uri:uri]; + if (localImage != nil) { + completionBlock(nil, localImage); + return; + } + + if ([url.scheme isEqualToString:@"http"] || [url.scheme isEqualToString:@"https"]) { + NSURLSessionDataTask *task = [NSURLSession.sharedSession + dataTaskWithURL:url + completionHandler:^(NSData *data, __unused NSURLResponse *response, NSError *error) { + UIImage *image = data == nil ? nil : [UIImage imageWithData:data scale:source.scale]; + if (image != nil) { + completionBlock(error, image); + } else { + failureBlock(); + } + }]; + [task resume]; + return; + } + + RCTBridge *bridge = [RCTBridge currentBridge]; + id imageLoader = [bridge moduleForName:@"ImageLoader"]; + if (imageLoader == nil) { + failureBlock(); + return; + } + + [imageLoader loadImageWithURLRequest:NSURLRequestFromImageSource(source) + size:CGSizeMake(source.size.width, source.size.height) + scale:source.scale + clipped:NO + resizeMode:RCTResizeModeCover + progressBlock:nil + partialLoadBlock:nil + completionBlock:completionBlock]; +} + +- (UIImage *)localImageForURL:(NSURL *)url uri:(NSString *)uri +{ + if (url.fileURL) { + UIImage *fileImage = [UIImage imageWithContentsOfFile:url.path]; + if (fileImage != nil) { + return fileImage; + } + } + + NSArray *names = @[ + uri, + uri.lastPathComponent, + uri.lastPathComponent.stringByDeletingPathExtension, + ]; + + for (NSString *name in names) { + UIImage *namedImage = [UIImage imageNamed:name]; + if (namedImage != nil) { + return namedImage; + } + + NSString *extension = name.pathExtension; + NSString *resourceName = extension.length > 0 ? name.stringByDeletingPathExtension : name; + NSString *resourcePath = [NSBundle.mainBundle pathForResource:resourceName + ofType:extension.length > 0 ? extension : nil]; + if (resourcePath != nil) { + UIImage *resourceImage = [UIImage imageWithContentsOfFile:resourcePath]; + if (resourceImage != nil) { + return resourceImage; + } + } + } + + return nil; +} + +@end diff --git a/package/ios/SliderView.swift b/package/ios/SliderView.swift index 4baf462d..32795b62 100644 --- a/package/ios/SliderView.swift +++ b/package/ios/SliderView.swift @@ -1,43 +1,607 @@ import SwiftUI +import UIKit struct SliderComponent: View { - @EnvironmentObject var state: SliderState + @ObservedObject var state: SliderState - @State private var value: Double = 0 + private var value: Binding { + Binding( + get: { state.value }, + set: { state.setValue($0, notify: true) } + ) + } - var body: some View { - VStack { + @ViewBuilder + private var nativeSlider: some View { + if state.step > 0 { Slider( - value: $value, - in: state.minValue...state.maxValue, - step: state.step + value: value, + in: state.valueRange, + step: state.step, + onEditingChanged: state.setEditing(_:)) + } else { + Slider( + value: value, + in: state.valueRange, + onEditingChanged: state.setEditing(_:)) + } + } + + var body: some View { + GeometryReader { geometry in + ZStack { + nativeSlider + .opacity(state.usesCustomVisuals ? 0 : 1) + .tint(state.minimumTrackTintColor.map { Color(uiColor: $0) }) + .environment(\.layoutDirection, state.inverted ? .rightToLeft : .leftToRight) + .allowsHitTesting(!state.usesCustomVisuals) + + if state.usesCustomVisuals { + SliderVisual(state: state, width: geometry.size.width) + } + } + .disabled(state.disabled) + .contentShape(Rectangle()) + .sliderGesture( + state: state, + width: geometry.size.width, + enabled: state.tapToSeek || state.usesCustomVisuals, + minimumDistance: state.tapToSeek ? 0 : 1 + ) + } + } +} + +private struct SliderVisual: View { + @ObservedObject var state: SliderState + let width: CGFloat + + private let defaultThumbSize = CGSize(width: 28, height: 28) + + private var trackHeight: CGFloat { + let imageHeight = [ + state.trackImage?.size.height, + state.minimumTrackImage?.size.height, + state.maximumTrackImage?.size.height, + ] + .compactMap { $0 } + .max() ?? 0 + + return max(4, min(imageHeight, 18)) + } + + private var thumbSize: CGSize { + if state.thumbSize > 0 { + let size = CGFloat(state.thumbSize) + return CGSize(width: size, height: size) + } + + if let thumbImage = state.thumbImage { + let maxSide = max(thumbImage.size.width, thumbImage.size.height) + guard maxSide > 0 else { + return defaultThumbSize + } + + let scale = min(1, defaultThumbSize.width / maxSide) + return CGSize(width: thumbImage.size.width * scale, height: thumbImage.size.height * scale) + } + + return defaultThumbSize + } + + var body: some View { + let percent = state.visualPercent + let resolvedThumbSize = thumbSize + let trackInset = resolvedThumbSize.width / 2 + let trackWidth = max(width - resolvedThumbSize.width, 0) + let thumbCenterX = trackInset + trackWidth * percent + let progressWidth = state.inverted ? trackWidth * (1 - percent) : trackWidth * percent + let progressOffset = state.inverted ? trackWidth - progressWidth : 0 + + ZStack(alignment: .leading) { + ZStack(alignment: .leading) { + SliderTrackSegment( + width: trackWidth, + height: trackHeight, + color: state.maximumTrackTintColor ?? UIColor.systemGray4, + image: state.maximumTrackVisualImage + ) + + SliderTrackSegment( + width: progressWidth, + height: trackHeight, + color: state.minimumTrackTintColor ?? UIColor.systemBlue, + image: state.minimumTrackVisualImage + ) + .offset(x: progressOffset) + } + .frame(width: trackWidth, height: trackHeight, alignment: .leading) + .clipShape(Capsule()) + .offset(x: trackInset) + + SliderThumb( + color: state.thumbTintColor ?? UIColor.white, + image: state.thumbImage, + size: resolvedThumbSize ) + .offset(x: thumbCenterX - resolvedThumbSize.width / 2) + } + .frame(width: width, height: max(resolvedThumbSize.height, trackHeight), alignment: .center) + } +} + +private struct SliderTrackImage { + let image: UIImage + let leftCap: CGFloat + let rightCap: CGFloat +} + +private struct SliderTrackSegment: View { + let width: CGFloat + let height: CGFloat + let color: UIColor + let image: SliderTrackImage? + + var body: some View { + let resolvedWidth = max(width, 0) + + Group { + if let image { + Image( + uiImage: image.image.renderedSliderTrackImage( + width: resolvedWidth, + height: height, + leftCap: image.leftCap, + rightCap: image.rightCap + ) + ) + } else { + Color(uiColor: color) + } + } + .frame(width: resolvedWidth, height: height) + } +} + +private struct SliderThumb: View { + let color: UIColor + let image: UIImage? + let size: CGSize + + private var shadowOpacity: Double { + color.cgColor.alpha > 0 ? 0.12 : 0 + } + + var body: some View { + Group { + if let image { + Image(uiImage: image) + .resizable() + } else { + Circle() + .fill(Color(uiColor: color)) + .shadow(color: Color.black.opacity(shadowOpacity), radius: 4, x: 0, y: 1) + } + } + .frame(width: size.width, height: size.height) + } +} + +private extension View { + @ViewBuilder + func sliderGesture(state: SliderState, width: CGFloat, enabled: Bool, minimumDistance: CGFloat) -> some View { + if enabled { + gesture( + DragGesture(minimumDistance: minimumDistance) + .onChanged { gesture in + guard !state.disabled else { + return + } + + state.setEditing(true) + state.setValueFromLocation( + x: gesture.location.x, + width: width, + inset: state.gestureInset(for: width) + ) + } + .onEnded { _ in + state.setEditing(false) + } + ) + } else { + self } } } class SliderState: ObservableObject { + @Published var value: Double = 0 @Published var minValue: Double = 0 @Published var maxValue: Double = 1 - @Published var step: Double = 1 - @Published var color: Color = .accentColor - @Published var onValueChange: (Double) -> Void = { _ in } + @Published var step: Double = 0 + @Published var lowerLimit: Double = -Double.greatestFiniteMagnitude + @Published var upperLimit: Double = Double.greatestFiniteMagnitude + @Published var disabled: Bool = false + @Published var inverted: Bool = false + @Published var tapToSeek: Bool = false + @Published var minimumTrackTintColor: UIColor? + @Published var maximumTrackTintColor: UIColor? + @Published var thumbTintColor: UIColor? + @Published var thumbImage: UIImage? + @Published var thumbSize: Double = 0 + @Published var trackImage: UIImage? + @Published var minimumTrackImage: UIImage? + @Published var maximumTrackImage: UIImage? + + var onValueChange: RCTDirectEventBlock? + var onSlidingStart: RCTDirectEventBlock? + var onSlidingComplete: RCTDirectEventBlock? + + private var isEditing = false + + var valueRange: ClosedRange { + minValue...max(minValue, maxValue) + } + + var usesCustomVisuals: Bool { + maximumTrackTintColor != nil || + thumbTintColor != nil || + thumbImage != nil || + thumbSize > 0 || + trackImage != nil || + minimumTrackImage != nil || + maximumTrackImage != nil + } + + fileprivate var minimumTrackVisualImage: SliderTrackImage? { + if let minimumTrackImage { + return SliderTrackImage(image: minimumTrackImage, leftCap: minimumTrackImage.size.width - 1, rightCap: 0) + } + + if let trackImage { + let capWidth = floor((trackImage.size.width - 1) / 2) + return SliderTrackImage(image: trackImage, leftCap: capWidth, rightCap: capWidth) + } + + return nil + } + + fileprivate var maximumTrackVisualImage: SliderTrackImage? { + if let maximumTrackImage { + return SliderTrackImage(image: maximumTrackImage, leftCap: 0, rightCap: maximumTrackImage.size.width - 1) + } + + if let trackImage { + let capWidth = floor((trackImage.size.width - 1) / 2) + return SliderTrackImage(image: trackImage, leftCap: capWidth, rightCap: capWidth) + } + + return nil + } + + var visualPercent: CGFloat { + guard maxValue > minValue else { + return inverted ? 1 : 0 + } + + let percent = min(max((value - minValue) / (maxValue - minValue), 0), 1) + return CGFloat(inverted ? 1 - percent : percent) + } + + func setMinValue(_ nextValue: Double) { + minValue = nextValue + normalizeRange() + clampValue() + } + + func setMaxValue(_ nextValue: Double) { + maxValue = nextValue + normalizeRange() + clampValue() + } + + func setStep(_ nextValue: Double) { + step = max(nextValue, 0) + clampValue() + } + + func setValue(_ nextValue: Double, notify: Bool) { + let nextValue = clampedValue(snappedValue(nextValue)) + + if value != nextValue { + value = nextValue + } + + if notify { + onValueChange?(eventPayload()) + } + } + + func setEditing(_ editing: Bool) { + guard editing != isEditing else { + return + } + + isEditing = editing + + if editing { + onSlidingStart?(eventPayload()) + } else { + onSlidingComplete?(eventPayload()) + } + } + + func gestureInset(for width: CGFloat) -> CGFloat { + if thumbSize > 0 { + return min(CGFloat(thumbSize) / 2, width / 2) + } + + if let thumbImage { + return min(thumbImage.size.width / 2, width / 2) + } + + return usesCustomVisuals ? min(14, width / 2) : 0 + } + + func setValueFromLocation(x: CGFloat, width: CGFloat, inset: CGFloat = 0) { + guard !disabled else { + return + } + + let usableWidth = max(width - inset * 2, 1) + let percent = min(max(Double((x - inset) / usableWidth), 0), 1) + let directedPercent = inverted ? 1 - percent : percent + let nextValue = minValue + directedPercent * (maxValue - minValue) + setValue(nextValue, notify: true) + } + + private func normalizeRange() { + if maxValue < minValue { + maxValue = minValue + } + } + + private func clampValue() { + setValue(value, notify: false) + } + + private func clampedValue(_ nextValue: Double) -> Double { + let lower = max(minValue, lowerLimit) + let upper = min(maxValue, upperLimit) + return min(max(nextValue, lower), max(lower, upper)) + } + + private func snappedValue(_ nextValue: Double) -> Double { + guard step > 0 else { + return nextValue + } + + return minValue + round((nextValue - minValue) / step) * step + } + + private func eventPayload() -> [String: Any] { + ["value": value] + } +} + +private extension UIImage { + func renderedSliderTrackImage(width: CGFloat, height: CGFloat, leftCap: CGFloat, rightCap: CGFloat) -> UIImage { + let targetSize = CGSize(width: max(width, 1), height: max(height, 1)) + let imageWidth = max(size.width, 1) + let sourceLeftCap = min(max(leftCap, 0), imageWidth) + let sourceRightCap = min(max(rightCap, 0), imageWidth - sourceLeftCap) + let sourceCenterWidth = max(imageWidth - sourceLeftCap - sourceRightCap, 0) + + let targetLeftCap = min(sourceLeftCap, targetSize.width) + let targetRightCap = min(sourceRightCap, max(targetSize.width - targetLeftCap, 0)) + let targetCenterWidth = max(targetSize.width - targetLeftCap - targetRightCap, 0) + + let format = UIGraphicsImageRendererFormat() + format.scale = UIScreen.main.scale + format.opaque = false + + return UIGraphicsImageRenderer(size: targetSize, format: format).image { _ in + drawSliderTrackSlice( + sourceX: 0, + sourceWidth: sourceLeftCap, + destination: CGRect(x: 0, y: 0, width: targetLeftCap, height: targetSize.height) + ) + + drawSliderTrackSlice( + sourceX: sourceLeftCap, + sourceWidth: sourceCenterWidth, + destination: CGRect(x: targetLeftCap, y: 0, width: targetCenterWidth, height: targetSize.height) + ) + + drawSliderTrackSlice( + sourceX: imageWidth - sourceRightCap, + sourceWidth: sourceRightCap, + destination: CGRect( + x: targetSize.width - targetRightCap, + y: 0, + width: targetRightCap, + height: targetSize.height + ) + ) + } + } + + private func drawSliderTrackSlice(sourceX: CGFloat, sourceWidth: CGFloat, destination: CGRect) { + guard sourceWidth > 0, destination.width > 0, destination.height > 0 else { + return + } + + guard let cgImage else { + draw(in: destination) + return + } + + let scaleX = CGFloat(cgImage.width) / max(size.width, 1) + let sourceRect = CGRect( + x: sourceX * scaleX, + y: 0, + width: sourceWidth * scaleX, + height: CGFloat(cgImage.height) + ) + .integral + + guard let slice = cgImage.cropping(to: sourceRect) else { + draw(in: destination) + return + } + + UIImage(cgImage: slice, scale: scale, orientation: imageOrientation).draw(in: destination) + } } -class SliderView: UIView { - private var state: SliderState = SliderState() - - override init(frame: CGRect) { +@objc(SliderView) +public class SliderView: UIView { + private let state = SliderState() + private var hostingController: UIHostingController? + + @objc public var minValue: Double = 0 { + didSet { + state.setMinValue(minValue) + } + } + + @objc public var maxValue: Double = 1 { + didSet { + state.setMaxValue(maxValue) + } + } + + @objc public var step: Double = 0 { + didSet { + state.setStep(step) + } + } + + @objc public var value: Double = 0 { + didSet { + state.setValue(value, notify: false) + } + } + + @objc public var lowerLimit: Double = -Double.greatestFiniteMagnitude { + didSet { + state.lowerLimit = lowerLimit + state.setValue(state.value, notify: false) + } + } + + @objc public var upperLimit: Double = Double.greatestFiniteMagnitude { + didSet { + state.upperLimit = upperLimit + state.setValue(state.value, notify: false) + } + } + + @objc public var disabled: Bool = false { + didSet { + state.disabled = disabled + } + } + + @objc public var inverted: Bool = false { + didSet { + state.inverted = inverted + } + } + + @objc public var tapToSeek: Bool = false { + didSet { + state.tapToSeek = tapToSeek + } + } + + @objc public var minimumTrackTintColor: UIColor? { + didSet { + state.minimumTrackTintColor = minimumTrackTintColor + } + } + + @objc public var maximumTrackTintColor: UIColor? { + didSet { + state.maximumTrackTintColor = maximumTrackTintColor + } + } + + @objc public var thumbTintColor: UIColor? { + didSet { + state.thumbTintColor = thumbTintColor + } + } + + @objc public var thumbImage: UIImage? { + didSet { + state.thumbImage = thumbImage + } + } + + @objc public var thumbSize: Double = 0 { + didSet { + state.thumbSize = thumbSize + } + } + + @objc public var trackImage: UIImage? { + didSet { + state.trackImage = trackImage + } + } + + @objc public var minimumTrackImage: UIImage? { + didSet { + state.minimumTrackImage = minimumTrackImage + } + } + + @objc public var maximumTrackImage: UIImage? { + didSet { + state.maximumTrackImage = maximumTrackImage + } + } + + @objc public var onValueChange: RCTDirectEventBlock? { + didSet { + state.onValueChange = onValueChange + } + } + + @objc public var onSlidingStart: RCTDirectEventBlock? { + didSet { + state.onSlidingStart = onSlidingStart + } + } + + @objc public var onSlidingComplete: RCTDirectEventBlock? { + didSet { + state.onSlidingComplete = onSlidingComplete + } + } + + public override init(frame: CGRect) { super.init(frame: frame) - let hostingController = UIHostingController(rootView: SliderComponent().environmentObject(state)) + + clipsToBounds = false + layer.masksToBounds = false + + let hostingController = UIHostingController(rootView: SliderComponent(state: state)) + hostingController.view.backgroundColor = .clear + hostingController.view.clipsToBounds = false + hostingController.view.layer.masksToBounds = false addSubview(hostingController.view) + self.hostingController = hostingController } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override func layoutSubviews() { - subviews.first?.frame = self.frame + public override func layoutSubviews() { + super.layoutSubviews() + hostingController?.view.frame = bounds } } diff --git a/package/ios/SliderViewManager.m b/package/ios/SliderViewManager.m index 76976d71..93cacc2f 100644 --- a/package/ios/SliderViewManager.m +++ b/package/ios/SliderViewManager.m @@ -1,10 +1,26 @@ -#import +#import "RCTViewManager.h" @interface RCT_EXTERN_MODULE(SliderViewManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(minValue, double) RCT_EXPORT_VIEW_PROPERTY(maxValue, double) RCT_EXPORT_VIEW_PROPERTY(step, double) +RCT_EXPORT_VIEW_PROPERTY(value, double) +RCT_EXPORT_VIEW_PROPERTY(lowerLimit, double) +RCT_EXPORT_VIEW_PROPERTY(upperLimit, double) +RCT_EXPORT_VIEW_PROPERTY(disabled, BOOL) +RCT_EXPORT_VIEW_PROPERTY(inverted, BOOL) +RCT_EXPORT_VIEW_PROPERTY(tapToSeek, BOOL) +RCT_EXPORT_VIEW_PROPERTY(minimumTrackTintColor, UIColor) +RCT_EXPORT_VIEW_PROPERTY(maximumTrackTintColor, UIColor) +RCT_EXPORT_VIEW_PROPERTY(thumbTintColor, UIColor) +RCT_EXPORT_VIEW_PROPERTY(thumbImage, UIImage) +RCT_EXPORT_VIEW_PROPERTY(thumbSize, double) +RCT_EXPORT_VIEW_PROPERTY(trackImage, UIImage) +RCT_EXPORT_VIEW_PROPERTY(minimumTrackImage, UIImage) +RCT_EXPORT_VIEW_PROPERTY(maximumTrackImage, UIImage) RCT_EXPORT_VIEW_PROPERTY(onValueChange, RCTDirectEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onSlidingStart, RCTDirectEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onSlidingComplete, RCTDirectEventBlock) @end diff --git a/package/ios/SliderViewManager.swift b/package/ios/SliderViewManager.swift index b01f9d01..06b8a01a 100644 --- a/package/ios/SliderViewManager.swift +++ b/package/ios/SliderViewManager.swift @@ -1,15 +1,13 @@ - +import UIKit @objc(SliderViewManager) class SliderViewManager: RCTViewManager { - - override func view() -> (SliderView) { - return SliderView() - } - - @objc override static func requiresMainQueueSetup() -> Bool { - return false - } -} + override func view() -> UIView! { + return SliderView() + } + @objc override static func requiresMainQueueSetup() -> Bool { + return false + } +} diff --git a/package/ios/slider.h b/package/ios/slider.h new file mode 100644 index 00000000..aa06e866 --- /dev/null +++ b/package/ios/slider.h @@ -0,0 +1,2 @@ +#import +#import diff --git a/package/package.json b/package/package.json index e4975ae9..ca3fe4eb 100644 --- a/package/package.json +++ b/package/package.json @@ -2,20 +2,21 @@ "name": "@react-native-community/slider", "version": "5.2.0", "license": "MIT", - "author": "react-native-community", + "author": "Callstack", "homepage": "https://github.com/callstack/react-native-slider#readme", "description": "React Native component used to select a single value from a range of values.", "publishConfig": { "access": "public" }, "main": "dist/Slider.js", + "types": "typings/index.d.ts", "keywords": [ "react-native", "react native", "slider" ], "scripts": { - "prepare": "babel --extensions \".ts,.tsx\" --out-dir dist src", + "prepare": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && babel --extensions \".ts,.tsx\" --out-dir dist src", "lint": "npx eslint src", "test": "jest", "prepack": "npx copyfiles \"./../README.md\" ./README.md" @@ -64,7 +65,7 @@ ] }, "prettier": { - "singleQuote": false, + "singleQuote": true, "trailingComma": "all", "bracketSpacing": false, "jsxBracketSameLine": true @@ -78,7 +79,7 @@ }, "ios": { "componentProvider": { - "SliderView": "SliderView" + "SliderView": "SliderComponentView" } } } diff --git a/package/slider.podspec b/package/react-native-slider.podspec similarity index 93% rename from package/slider.podspec rename to package/react-native-slider.podspec index 745f6b39..67c781fb 100644 --- a/package/slider.podspec +++ b/package/react-native-slider.podspec @@ -4,7 +4,7 @@ package = JSON.parse(File.read(File.join(__dir__, "package.json"))) folly_compiler_flags = "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32" Pod::Spec.new do |s| - s.name = "slider" + s.name = "react-native-slider" s.version = package["version"] s.summary = package["description"] s.license = package["license"] @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.homepage = package["homepage"] s.platforms = { :ios => "16.0" } - s.source = { :git => "https://github.com/callstack/react-native-slider.git", :tag => "#{s.version}" } + s.source = { :git => "https://github.com/callstack/react-native-slider.git", :tag => "v#{s.version}" } s.source_files = "ios/**/*.{h,m,mm,swift}" diff --git a/package/src/RNCSliderNativeComponent.web.tsx b/package/src/RNCSliderNativeComponent.web.tsx deleted file mode 100644 index 1c29678b..00000000 --- a/package/src/RNCSliderNativeComponent.web.tsx +++ /dev/null @@ -1,398 +0,0 @@ -import React, {RefObject, useCallback} from "react"; -import { - Animated, - View, - ColorValue, - ViewStyle, - GestureResponderEvent, - LayoutChangeEvent, - Image, - ImageSourcePropType, -} from "react-native"; -//@ts-ignore -import type {ImageSource} from "react-native/Libraries/Image/ImageSource"; -import {constants} from "./utils/constants"; - -type Event = Readonly<{ - nativeEvent: { - value: number; - }; -}>; - -type AnimationValues = { - val: Animated.Value; - min: Animated.Value; - max: Animated.Value; - diff: Animated.Value; -}; - -export interface Props { - value: number; - minimumValue: number; - maximumValue: number; - lowerLimit?: number; - upperLimit?: number; - step: number; - minimumTrackTintColor: ColorValue; - maximumTrackTintColor: ColorValue; - thumbTintColor: ColorValue; - thumbStyle: ViewStyle; - style: ViewStyle; - inverted: boolean; - disabled: boolean; - trackHeight: number; - thumbImage?: ImageSource; - onSliderSlidingStart: (event: Event) => void; - onSliderSlidingComplete: (event: Event) => void; - onSliderValueChange: (event: Event) => void; -} - -const valueToEvent = (value: number): Event => ({nativeEvent: {value}}); - -const RCTSliderWebComponent = React.forwardRef( - ( - { - value: initialValue = 0, - minimumValue = 0, - maximumValue = 0, - lowerLimit = 0, - upperLimit = 0, - step = 1, - minimumTrackTintColor = "#009688", - maximumTrackTintColor = "#939393", - thumbTintColor = "#009688", - thumbStyle = {}, - style = {}, - inverted = false, - disabled = false, - trackHeight = 4, - thumbImage, - onSliderSlidingStart = (_: Event) => {}, - onSliderSlidingComplete = (_: Event) => {}, - onSliderValueChange = (_: Event) => {}, - ...others - }: Props, - forwardedRef: any, - ) => { - const containerSize = React.useRef({width: 0, height: 0}); - const containerPositionX = React.useRef(0); - const containerRef = forwardedRef || React.createRef(); - const containerPositionInvalidated = React.useRef(false); - const [value, setValue] = React.useState(initialValue || minimumValue); - const lastInitialValue = React.useRef(0); - const animationValues = React.useRef({ - val: new Animated.Value(value), - min: new Animated.Value(minimumValue), - max: new Animated.Value(maximumValue), - // make sure we never divide by 0 - diff: new Animated.Value(maximumValue - minimumValue || 1), - }).current; - - // update minimumValue & maximumValue animations - React.useEffect(() => { - animationValues.min.setValue(minimumValue); - animationValues.max.setValue(maximumValue); - // make sure we never divide by 0 - animationValues.diff.setValue(maximumValue - minimumValue || 1); - }, [animationValues, minimumValue, maximumValue]); - - // compute animated slider position based on animated value - const minPercent = React.useRef( - Animated.multiply( - new Animated.Value(100), - Animated.divide( - Animated.subtract(animationValues.val, animationValues.min), - animationValues.diff, - ), - ), - ).current; - const maxPercent = React.useRef( - Animated.subtract(new Animated.Value(100), minPercent), - ).current; - - const onValueChange = useCallback( - (value: number) => { - onSliderValueChange && onSliderValueChange(valueToEvent(value)); - }, - [onSliderValueChange], - ); - - const onSlidingStart = useCallback( - (value: number) => { - isUserInteracting.current = true; - onSliderSlidingStart && onSliderSlidingStart(valueToEvent(value)); - }, - [onSliderSlidingStart], - ); - - const onSlidingComplete = useCallback( - (value: number) => { - isUserInteracting.current = false; - onSliderSlidingComplete && - onSliderSlidingComplete(valueToEvent(value)); - }, - [onSliderSlidingComplete], - ); - // Add a ref to track user interaction - const isUserInteracting = React.useRef(false); - const updateValue = useCallback( - (newValue: number) => { - // Ensure that the value is correctly rounded - const hardRounded = - decimalPrecision.current < 20 - ? Number.parseFloat(newValue.toFixed(decimalPrecision.current)) - : newValue; - - // Ensure that the new value is still between the bounds - const withinBounds = Math.max( - minimumValue, - Math.min(hardRounded, maximumValue), - ); - if (value !== withinBounds) { - setValue(withinBounds); - if (isUserInteracting.current) { - onValueChange(withinBounds); - } - return withinBounds; - } - return hardRounded; - }, - [minimumValue, maximumValue, value, onValueChange], - ); - - React.useLayoutEffect(() => { - // we have to do this check because `initialValue` gets default to `0` by - // Slider. If we don't this will get called every time `value` changes - // as `updateValue` is mutated when value changes. The result of not - // checking this is that the value constantly gets reset to `0` in - // contexts where `value` is not managed externally. - if (initialValue !== lastInitialValue.current) { - lastInitialValue.current = initialValue; - const newValue = updateValue(initialValue); - animationValues.val.setValue(newValue); - } - }, [initialValue, updateValue, animationValues]); - - React.useEffect(() => { - const invalidateContainerPosition = () => { - containerPositionInvalidated.current = true; - }; - const onDocumentScroll = (e: Event) => { - const isAlreadyInvalidated = !containerPositionInvalidated.current; - if ( - isAlreadyInvalidated && - containerRef.current && - // @ts-ignore - e.target.contains(containerRef.current) - ) { - invalidateContainerPosition(); - } - }; - //@ts-ignore - window.addEventListener("resize", invalidateContainerPosition); - //@ts-ignore - document.addEventListener("scroll", onDocumentScroll, {capture: true}); - - return () => { - //@ts-ignore - window.removeEventListener("resize", invalidateContainerPosition); - - //@ts-ignore - document.removeEventListener("scroll", onDocumentScroll, { - capture: true, - }); - }; - }, [containerRef]); - - const containerStyle = [ - { - flexGrow: 1, - flexShrink: 1, - flexBasis: "auto", - flexDirection: "row", - alignItems: "center", - }, - style, - ] as ViewStyle[]; - - const trackStyle = { - height: trackHeight, - borderRadius: trackHeight / 2, - userSelect: "none", - }; - - const minimumTrackStyle = { - ...trackStyle, - backgroundColor: minimumTrackTintColor, - flexGrow: minPercent, - }; - - const maximumTrackStyle = { - ...trackStyle, - backgroundColor: maximumTrackTintColor, - flexGrow: maxPercent, - }; - - const thumbSize = constants.THUMB_SIZE; - const thumbViewStyle = [ - { - width: thumbSize, - height: thumbSize, - backgroundColor: thumbTintColor, - zIndex: 1, - borderRadius: thumbSize / 2, - overflow: "hidden", - }, - thumbStyle, - ] as ViewStyle[]; - - const decimalPrecision = React.useRef( - calculatePrecision(minimumValue, maximumValue, step), - ); - React.useEffect(() => { - decimalPrecision.current = calculatePrecision( - minimumValue, - maximumValue, - step, - ); - }, [maximumValue, minimumValue, step]); - - const updateContainerPositionX = () => { - const positionX = ( - containerRef as RefObject - ).current?.getBoundingClientRect().x; - containerPositionX.current = positionX ?? 0; - }; - - const getValueFromNativeEvent = (pageX: number) => { - const adjustForThumbSize = (containerSize.current.width || 1) > thumbSize; - const width = - (containerSize.current.width || 1) - - (adjustForThumbSize ? thumbSize : 0); - - if (containerPositionInvalidated.current) { - containerPositionInvalidated.current = false; - updateContainerPositionX(); - } - - const containerX = - containerPositionX.current + (adjustForThumbSize ? thumbSize / 2 : 0); - const lowerValue = minimumValue < lowerLimit ? lowerLimit : minimumValue; - const upperValue = maximumValue > upperLimit ? upperLimit : maximumValue; - - if (pageX < containerX) { - return inverted ? upperValue : lowerValue; - } else if (pageX > containerX + width) { - return inverted ? lowerValue : upperValue; - } else { - const x = pageX - containerX; - const newValue = inverted - ? maximumValue - ((maximumValue - minimumValue) * x) / width - : minimumValue + ((maximumValue - minimumValue) * x) / width; - - const valueAfterStep = step - ? Math.round(newValue / step) * step - : newValue; - const valueAfterLowerLimit = - valueAfterStep < lowerLimit ? lowerLimit : valueAfterStep; - const valueInLimitRange = - valueAfterLowerLimit > upperLimit ? upperLimit : valueAfterLowerLimit; - return valueInLimitRange; - } - }; - - const onTouchEnd = ({nativeEvent}: GestureResponderEvent) => { - const newValue = updateValue(getValueFromNativeEvent(nativeEvent.pageX)); - animationValues.val.setValue(newValue); - onSlidingComplete(newValue); - }; - - const onMove = ({nativeEvent}: GestureResponderEvent) => { - const newValue = getValueFromNativeEvent(nativeEvent.pageX); - animationValues.val.setValue(newValue); - updateValue(newValue); - }; - - const accessibilityActions = (event: any) => { - const tenth = (maximumValue - minimumValue) / 10; - switch (event.nativeEvent.actionName) { - case "increment": - updateValue(value + (step || tenth)); - break; - case "decrement": - updateValue(value - (step || tenth)); - break; - } - }; - - React.useImperativeHandle( - forwardedRef, - () => ({ - updateValue: (val: number) => { - updateValue(val); - }, - }), - [updateValue], - ); - - return ( - { - containerSize.current.height = layout.height; - containerSize.current.width = layout.width; - if ((containerRef as RefObject).current) { - updateContainerPositionX(); - } - }} - accessibilityActions={[ - {name: "increment", label: "increment"}, - {name: "decrement", label: "decrement"}, - ]} - onAccessibilityAction={accessibilityActions} - accessible={true} - accessibilityRole={"adjustable"} - style={containerStyle} - {...others} - // NOTE: gesture responders should all fall _after_ the {...others} - // spread operator, or they may not work appropriately. - onStartShouldSetResponder={() => !disabled} - onMoveShouldSetResponder={() => !disabled} - onResponderGrant={() => onSlidingStart(value)} - onResponderRelease={onTouchEnd} - onResponderMove={onMove}> - - - {thumbImage !== undefined ? ( - - ) : null} - - - - ); - }, -); - -// We should round number with the same precision as the min, max or step values if provided -function calculatePrecision( - minimumValue: number, - maximumValue: number, - step: number, -) { - if (!step) { - return Infinity; - } else { - // Calculate the number of decimals we can encounter in the results - const decimals = [minimumValue, maximumValue, step].map( - (value) => ((value + "").split(".").pop() || "").length, - ); - return Math.max(...decimals); - } -} - -RCTSliderWebComponent.displayName = "RTCSliderWebComponent"; - -export default RCTSliderWebComponent; diff --git a/package/src/Slider.tsx b/package/src/Slider.tsx index 9fbf44c7..defb5663 100644 --- a/package/src/Slider.tsx +++ b/package/src/Slider.tsx @@ -1,56 +1,307 @@ -import React, {FunctionComponent, useCallback, useMemo} from "react"; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import { + AccessibilityActionEvent, + Image, + type ColorValue, Platform, StyleSheet, type NativeSyntheticEvent, + type ImageSource, + type ImageSourcePropType, type StyleProp, + View, + type ViewProps, type ViewStyle, -} from "react-native"; +} from 'react-native'; import SliderNativeComponent, { type NativeSliderProps, type SliderChangeEvent, -} from "./SliderNativeComponent"; - -export type SliderProps = { - style?: StyleProp; - onValueChange?: (value: number) => void; -} & NativeSliderProps; - -export const Slider: FunctionComponent = ({ - minValue, - maxValue, - step, - onValueChange, - style, -}) => { - const steps = useMemo(() => { - if (!step) { - return undefined; - } else { - return Platform.OS === "android" - ? Math.round(Math.abs(((maxValue || 1) - (minValue || 0)) / step)) - 1 - : step; - } - }, [minValue, maxValue, step]); - - const handleValueChange = useCallback( - (event: NativeSyntheticEvent) => { - onValueChange?.(event.nativeEvent.value); +} from './SliderNativeComponent'; +import {StepsIndicator} from './components/StepsIndicator'; +import type {MarkerProps} from './components/TrackMark'; +import {constants} from './utils/constants'; +import {styles as sliderStyles} from './utils/styles'; + +type IOSProps = Readonly<{ + trackImage?: ImageSource; + minimumTrackImage?: ImageSource; + maximumTrackImage?: ImageSource; + tapToSeek?: boolean; +}>; + +type WindowsProps = Readonly<{ + vertical?: boolean; +}>; + +export type SliderProps = ViewProps & + IOSProps & + WindowsProps & + Readonly<{ + style?: StyleProp; + value?: number; + step?: number; + minimumValue?: number; + maximumValue?: number; + minValue?: number; + maxValue?: number; + lowerLimit?: number; + upperLimit?: number; + minimumTrackTintColor?: ColorValue; + maximumTrackTintColor?: ColorValue; + thumbTintColor?: ColorValue; + disabled?: boolean; + onValueChange?: (value: number) => void; + onSlidingStart?: (value: number) => void; + onSlidingComplete?: (value: number) => void; + thumbImage?: ImageSource; + thumbSize?: number; + inverted?: boolean; + StepMarker?: React.FC; + renderStepNumber?: boolean; + accessibilityUnits?: string; + accessibilityIncrements?: Array; + }>; + +const clamp = (nextValue: number, minimumValue: number, maximumValue: number) => + Math.min(Math.max(nextValue, minimumValue), maximumValue); + +const resolveImageSource = (source?: ImageSource) => + source ? Image.resolveAssetSource(source as ImageSourcePropType) : undefined; + +export const Slider = React.forwardRef< + React.ElementRef, + SliderProps +>( + ( + { + minValue, + maxValue, + minimumValue = minValue ?? 0, + maximumValue = maxValue ?? 1, + value = constants.SLIDER_DEFAULT_INITIAL_VALUE, + lowerLimit = Platform.select({ + web: minimumValue, + default: constants.LIMIT_MIN_VALUE, + }), + upperLimit = Platform.select({ + web: maximumValue, + default: constants.LIMIT_MAX_VALUE, + }), + step = 0, + inverted = false, + tapToSeek = false, + onValueChange, + onSlidingStart, + onSlidingComplete, + onAccessibilityAction, + style, + StepMarker, + renderStepNumber, + accessibilityState, + trackImage, + minimumTrackImage, + maximumTrackImage, + thumbImage, + thumbSize, + thumbTintColor, + ...props }, - [onValueChange], - ); - - return ( - - ); -}; + forwardedRef, + ) => { + const [currentValue, setCurrentValue] = useState( + clamp(value ?? minimumValue, minimumValue, maximumValue), + ); + const [width, setWidth] = useState(0); + + useEffect(() => { + if (lowerLimit >= upperLimit) { + console.warn( + 'Invalid configuration: lower limit is supposed to be smaller than upper limit', + ); + } + }, [lowerLimit, upperLimit]); + + useEffect(() => { + setCurrentValue(clamp(value ?? minimumValue, minimumValue, maximumValue)); + }, [maximumValue, minimumValue, value]); + + const stepResolution = step || constants.DEFAULT_STEP_RESOLUTION; + const defaultStep = (maximumValue - minimumValue) / stepResolution; + const stepLength = step || defaultStep; + const options = useMemo( + () => + Array.from( + { + length: + Math.max(Math.round(step ? defaultStep : stepResolution), 0) + 1, + }, + (_, index) => minimumValue + index * stepLength, + ), + [defaultStep, minimumValue, step, stepLength, stepResolution], + ); + + const nativeStep = useMemo(() => { + if (!step) { + return 0; + } + + if (Platform.OS === 'android') { + return Math.max( + Math.round(Math.abs((maximumValue - minimumValue) / step)) - 1, + 0, + ); + } + + return step; + }, [maximumValue, minimumValue, step]); + + const handleValueChange = useCallback( + (event: NativeSyntheticEvent) => { + const nextValue = event.nativeEvent.value; + setCurrentValue(nextValue); + onValueChange?.(nextValue); + }, + [onValueChange], + ); + + const handleSlidingStart = useCallback( + (event: NativeSyntheticEvent) => { + onSlidingStart?.(event.nativeEvent.value); + }, + [onSlidingStart], + ); + + const handleSlidingComplete = useCallback( + (event: NativeSyntheticEvent) => { + onSlidingComplete?.(event.nativeEvent.value); + }, + [onSlidingComplete], + ); + + const handleAccessibilityAction = onAccessibilityAction + ? (event: AccessibilityActionEvent) => { + onAccessibilityAction(event); + } + : undefined; + + const disabled = + typeof props.disabled === 'boolean' + ? props.disabled + : accessibilityState?.disabled === true; + + const nextAccessibilityState = + typeof props.disabled === 'boolean' + ? {...accessibilityState, disabled: props.disabled} + : accessibilityState; + + const defaultStyle = + Platform.OS === 'ios' + ? sliderStyles.defaultSlideriOS + : sliderStyles.defaultSlider; + + const shouldRenderStepOverlay = !!StepMarker || !!renderStepNumber; + const shouldRenderCustomStepMarker = !!StepMarker; + + const resolvedTrackImage = + Platform.OS === 'web' ? trackImage : resolveImageSource(trackImage); + const resolvedMinimumTrackImage = + Platform.OS === 'web' + ? minimumTrackImage + : resolveImageSource(minimumTrackImage); + const resolvedMaximumTrackImage = + Platform.OS === 'web' + ? maximumTrackImage + : resolveImageSource(maximumTrackImage); + const resolvedThumbImage = + Platform.OS === 'web' || shouldRenderStepOverlay + ? thumbImage + : resolveImageSource(thumbImage); + + return ( + { + setWidth(event.nativeEvent.layout.width); + }} + style={[ + defaultStyle, + style, + {justifyContent: 'center', overflow: 'visible'}, + ]}> + {shouldRenderStepOverlay ? ( + + ) : null} + )} + accessibilityState={nextAccessibilityState} + disabled={disabled} + inverted={inverted} + tapToSeek={tapToSeek} + minValue={minimumValue} + maxValue={maximumValue} + lowerLimit={lowerLimit} + upperLimit={upperLimit} + value={Number.isNaN(value) ? undefined : value} + step={nativeStep} + trackImage={resolvedTrackImage} + minimumTrackImage={resolvedMinimumTrackImage} + maximumTrackImage={resolvedMaximumTrackImage} + thumbImage={ + shouldRenderCustomStepMarker ? undefined : resolvedThumbImage + } + thumbSize={thumbSize} + thumbTintColor={ + shouldRenderCustomStepMarker || + (thumbImage && shouldRenderStepOverlay) + ? 'transparent' + : thumbTintColor + } + ref={forwardedRef} + onValueChange={handleValueChange} + onSlidingStart={onSlidingStart ? handleSlidingStart : undefined} + onSlidingComplete={ + onSlidingComplete ? handleSlidingComplete : undefined + } + onAccessibilityAction={handleAccessibilityAction} + onStartShouldSetResponder={() => true} + onResponderTerminationRequest={() => false} + style={[ + styles.base, + defaultStyle, + { + alignContent: 'center', + alignItems: 'center', + overflow: 'visible', + width, + }, + ]} + /> + + ); + }, +); + +export type {MarkerProps}; + +Slider.displayName = 'Slider'; export default Slider; diff --git a/package/src/SliderNativeComponent.ts b/package/src/SliderNativeComponent.ts index aeb274aa..dcc67a65 100644 --- a/package/src/SliderNativeComponent.ts +++ b/package/src/SliderNativeComponent.ts @@ -1,26 +1,48 @@ import { + type ColorValue, codegenNativeComponent, type HostComponent, + type ImageSource, type ViewProps, -} from "react-native"; +} from 'react-native'; import type { DirectEventHandler, Double, Float, - Int32, -} from "react-native/Libraries/Types/CodegenTypes"; + WithDefault, +} from 'react-native/Libraries/Types/CodegenTypes'; export type SliderChangeEvent = Readonly<{ value: Double; + fromUser?: boolean; }>; export interface NativeSliderProps extends ViewProps { - step?: Int32; - minValue?: Float; - maxValue?: Float; + accessibilityUnits?: string; + accessibilityIncrements?: ReadonlyArray; + disabled?: WithDefault; + inverted?: WithDefault; + vertical?: WithDefault; + tapToSeek?: WithDefault; + maximumTrackImage?: ImageSource; + maximumTrackTintColor?: ColorValue; + minimumTrackImage?: ImageSource; + minimumTrackTintColor?: ColorValue; + thumbImage?: ImageSource; + thumbTintColor?: ColorValue; + thumbSize?: Float; + trackImage?: ImageSource; + step?: Double; + minValue?: Double; + maxValue?: Double; + value?: Float; + lowerLimit?: Float; + upperLimit?: Float; onValueChange?: DirectEventHandler | null; + onSlidingStart?: DirectEventHandler | null; + onSlidingComplete?: DirectEventHandler | null; } export default codegenNativeComponent( - "SliderView", + 'SliderView', ) as HostComponent; diff --git a/package/src/SliderNativeComponent.web.tsx b/package/src/SliderNativeComponent.web.tsx new file mode 100644 index 00000000..ac553bc5 --- /dev/null +++ b/package/src/SliderNativeComponent.web.tsx @@ -0,0 +1,273 @@ +import React, { + useCallback, + useEffect, + useState, + type ForwardedRef, +} from 'react'; +import { + Image, + View, + type ColorValue, + type GestureResponderEvent, + type HostComponent, + type ImageSourcePropType, + type LayoutChangeEvent, +} from 'react-native'; + +import type {NativeSliderProps} from './SliderNativeComponent'; + +const TRACK_HEIGHT = 4; +const THUMB_SIZE = 20; + +const clamp = (value: number, minValue: number, maxValue: number) => + Math.min(Math.max(value, minValue), maxValue); + +const snapToStep = (value: number, minValue: number, step?: number) => { + if (!step) { + return value; + } + + return minValue + Math.round((value - minValue) / step) * step; +}; + +const getImageUri = (source: unknown): string | undefined => { + if (!source) { + return undefined; + } + + if (typeof source === 'string') { + return source; + } + + if (Array.isArray(source)) { + return getImageUri(source[0]); + } + + if (typeof source === 'object') { + const imageSource = source as {default?: unknown; uri?: unknown}; + + if (typeof imageSource.uri === 'string') { + return imageSource.uri; + } + + return getImageUri(imageSource.default); + } + + return undefined; +}; + +const getTrackImageStyle = (source: unknown, width: number) => { + const uri = getImageUri(source); + + if (!uri) { + return undefined; + } + + return { + backgroundImage: `url(${JSON.stringify(uri)})`, + backgroundPosition: 'left center', + backgroundRepeat: 'no-repeat', + backgroundSize: `${Math.max(width, 1)}px 100%`, + } as never; +}; + +const SliderNativeComponent = React.forwardRef( + ( + { + minValue = 0, + maxValue = 1, + value: valueProp, + step, + onValueChange, + onSlidingStart, + onSlidingComplete, + onLayout, + style, + disabled, + inverted, + lowerLimit = minValue, + upperLimit = maxValue, + minimumTrackTintColor = '#007aff', + maximumTrackTintColor = '#b3b3b3', + thumbTintColor = '#ffffff', + accessibilityIncrements: _accessibilityIncrements, + accessibilityUnits: _accessibilityUnits, + maximumTrackImage, + minimumTrackImage, + tapToSeek: _tapToSeek, + thumbImage, + thumbSize: thumbSizeProp, + trackImage, + vertical: _vertical, + ...props + }: NativeSliderProps, + ref: ForwardedRef, + ) => { + const [width, setWidth] = useState(0); + const [value, setValue] = useState(valueProp ?? minValue); + const thumbSize = thumbSizeProp ?? (thumbImage ? 48 : THUMB_SIZE); + + useEffect(() => { + setValue(valueProp ?? minValue); + }, [minValue, valueProp]); + + const updateValue = useCallback( + (event: GestureResponderEvent) => { + if (disabled) { + return; + } + + const nextPercent = width > 0 ? event.nativeEvent.locationX / width : 0; + const percent = inverted ? 1 - nextPercent : nextPercent; + const nextValue = clamp( + snapToStep( + minValue + percent * (maxValue - minValue), + minValue, + step, + ), + lowerLimit, + upperLimit, + ); + + setValue(nextValue); + onValueChange?.({nativeEvent: {value: nextValue}} as never); + }, + [ + disabled, + inverted, + lowerLimit, + maxValue, + minValue, + onValueChange, + step, + upperLimit, + width, + ], + ); + + const startSliding = useCallback( + (event: GestureResponderEvent) => { + if (disabled) { + return; + } + + onSlidingStart?.({nativeEvent: {value}} as never); + updateValue(event); + }, + [disabled, onSlidingStart, updateValue, value], + ); + + const completeSliding = useCallback(() => { + if (disabled) { + return; + } + + onSlidingComplete?.({nativeEvent: {value}} as never); + }, [disabled, onSlidingComplete, value]); + + const handleLayout = useCallback( + (event: LayoutChangeEvent) => { + setWidth(event.nativeEvent.layout.width); + onLayout?.(event); + }, + [onLayout], + ); + + const percent = + maxValue === minValue + ? 0 + : ((value - minValue) / (maxValue - minValue)) * 100; + const renderedPercent = inverted ? 100 - percent : percent; + const hasTrackImage = !!getImageUri(trackImage); + const maximumTrackImageStyle = getTrackImageStyle( + maximumTrackImage ?? trackImage, + width, + ); + const minimumTrackImageStyle = getTrackImageStyle(minimumTrackImage, width); + const trackHeight = + maximumTrackImageStyle || minimumTrackImageStyle || hasTrackImage + ? 20 + : TRACK_HEIGHT; + + return ( + true} + onMoveShouldSetResponder={() => true} + onResponderGrant={startSliding} + onResponderMove={updateValue} + onResponderRelease={completeSliding} + onResponderTerminate={completeSliding}> + + + + {thumbImage ? ( + + ) : ( + + )} + + ); + }, +); + +export default SliderNativeComponent as unknown as HostComponent; diff --git a/package/src/components/StepNumber.tsx b/package/src/components/StepNumber.tsx new file mode 100644 index 00000000..d7e8e5f0 --- /dev/null +++ b/package/src/components/StepNumber.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import {type StyleProp, Text, type TextStyle, View} from 'react-native'; + +import {styles} from '../utils/styles'; + +export const StepNumber = ({ + i, + index, + style, +}: { + i: number; + index: number; + style: StyleProp; +}) => { + return ( + + + {i} + + + ); +}; diff --git a/package/src/components/StepsIndicator.tsx b/package/src/components/StepsIndicator.tsx new file mode 100644 index 00000000..11a61893 --- /dev/null +++ b/package/src/components/StepsIndicator.tsx @@ -0,0 +1,124 @@ +import React, {type FC, Fragment, useCallback, useMemo} from 'react'; +import {Platform, View} from 'react-native'; +import type {ImageSource} from 'react-native/Libraries/Image/ImageSource'; + +import {StepNumber} from './StepNumber'; +import {type MarkerProps, SliderTrackMark} from './TrackMark'; +import {constants} from '../utils/constants'; +import {styles} from '../utils/styles'; + +export const StepsIndicator = ({ + options, + sliderWidth, + currentValue, + StepMarker, + renderStepNumber, + thumbImage, + isLTR, + thumbSize, +}: { + options: number[]; + sliderWidth: number; + currentValue: number; + StepMarker?: FC; + renderStepNumber?: boolean; + thumbImage?: ImageSource; + isLTR?: boolean; + thumbSize?: number; +}) => { + const stepNumberFontStyle = useMemo(() => { + return { + fontSize: + options.length > 9 + ? constants.STEP_NUMBER_TEXT_FONT_SMALL + : constants.STEP_NUMBER_TEXT_FONT_BIG, + }; + }, [options.length]); + + const platformDependentStyles = useMemo(() => { + const isWeb = Platform.OS === 'web'; + const isIOS = Platform.OS === 'ios'; + const trackInset = isIOS + ? (thumbSize || constants.IOS_DEFAULT_THUMB_SIZE) / 2 + : sliderWidth * constants.MARGIN_HORIZONTAL_PADDING; + + return { + stepIndicatorContainerStyle: isWeb + ? styles.stepsIndicator + : isIOS + ? { + ...styles.stepsIndicator, + left: trackInset, + position: 'absolute' as const, + right: trackInset, + } + : { + ...styles.stepsIndicator, + marginHorizontal: trackInset, + }, + stepIndicatorElementStyle: isWeb + ? { + ...styles.stepIndicatorElement, + width: constants.THUMB_SIZE, + justifyContent: 'space-between' as const, + } + : styles.stepIndicatorElement, + }; + }, [sliderWidth, thumbSize]); + + const values = useMemo( + () => (isLTR ? [...options].reverse() : options), + [isLTR, options], + ); + + const renderStepIndicator = useCallback( + (i: number, index: number) => { + return ( + + + + {renderStepNumber ? ( + + ) : null} + + + ); + }, + [ + currentValue, + StepMarker, + options, + thumbImage, + renderStepNumber, + stepNumberFontStyle, + platformDependentStyles.stepIndicatorElementStyle, + ], + ); + + return ( + + {values.map((i, index) => renderStepIndicator(i, index))} + + ); +}; diff --git a/package/src/components/TrackMark.tsx b/package/src/components/TrackMark.tsx new file mode 100644 index 00000000..3ee3af1c --- /dev/null +++ b/package/src/components/TrackMark.tsx @@ -0,0 +1,57 @@ +import React, {type FC} from 'react'; +import {Image, type ImageSourcePropType, View} from 'react-native'; +import type {ImageSource} from 'react-native/Libraries/Image/ImageSource'; + +import {styles} from '../utils/styles'; + +export type MarkerProps = { + stepMarked: boolean; + currentValue: number; + index: number; + min: number; + max: number; +}; + +export type TrackMarksProps = { + isTrue: boolean; + index: number; + thumbImage?: ImageSource; + StepMarker?: FC; + currentValue: number; + min: number; + max: number; +}; + +export const SliderTrackMark = ({ + isTrue, + index, + thumbImage, + StepMarker, + currentValue, + min, + max, +}: TrackMarksProps) => { + return ( + + {StepMarker ? ( + + ) : null} + {thumbImage && isTrue ? ( + + + + ) : null} + + ); +}; diff --git a/package/src/index.ts b/package/src/index.ts index a6b80558..c255d266 100644 --- a/package/src/index.ts +++ b/package/src/index.ts @@ -1,2 +1,4 @@ -import Slider from "./Slider"; +import Slider from './Slider'; + +export type {MarkerProps, SliderProps} from './Slider'; export default Slider; diff --git a/package/src/utils/constants.ts b/package/src/utils/constants.ts new file mode 100644 index 00000000..a1b75cdb --- /dev/null +++ b/package/src/utils/constants.ts @@ -0,0 +1,13 @@ +import {Platform} from 'react-native'; + +export const constants = { + SLIDER_DEFAULT_INITIAL_VALUE: 0, + IOS_DEFAULT_THUMB_SIZE: 28, + MARGIN_HORIZONTAL_PADDING: 0.05, + THUMB_SIZE: 20, + STEP_NUMBER_TEXT_FONT_SMALL: 8, + STEP_NUMBER_TEXT_FONT_BIG: 12, + LIMIT_MIN_VALUE: Number.MIN_SAFE_INTEGER, + LIMIT_MAX_VALUE: Number.MAX_SAFE_INTEGER, + DEFAULT_STEP_RESOLUTION: Platform.OS === 'android' ? 128 : 1000, +}; diff --git a/package/src/utils/styles.ts b/package/src/utils/styles.ts new file mode 100644 index 00000000..96e1df1d --- /dev/null +++ b/package/src/utils/styles.ts @@ -0,0 +1,55 @@ +import {Platform, StyleSheet} from 'react-native'; + +export const styles = StyleSheet.create({ + stepNumber: { + marginTop: 20, + alignItems: 'center', + position: 'absolute', + }, + sliderMainContainer: {zIndex: 1, width: '100%'}, + defaultSlideriOS: { + height: 40, + }, + defaultSlider: {}, + stepsIndicator: { + flex: 1, + flexDirection: 'row', + justifyContent: 'space-between', + top: Platform.OS === 'ios' ? 10 : 0, + zIndex: 2, + }, + trackMarkContainer: { + alignItems: 'center', + alignContent: 'center', + alignSelf: 'center', + justifyContent: 'center', + position: 'absolute', + zIndex: 3, + }, + thumbImageContainer: { + position: 'absolute', + zIndex: 3, + justifyContent: 'center', + alignItems: 'center', + alignContent: 'center', + }, + thumbImage: { + alignContent: 'center', + alignItems: 'center', + position: 'absolute', + }, + stepIndicatorElement: { + alignItems: 'center', + alignContent: 'center', + }, + defaultIndicatorMarked: { + height: 20, + width: 5, + backgroundColor: '#CCCCCC', + }, + defaultIndicatorIdle: { + height: 10, + width: 2, + backgroundColor: '#C0C0C0', + }, +}); diff --git a/package/typings/index.d.ts b/package/typings/index.d.ts new file mode 100644 index 00000000..f6166748 --- /dev/null +++ b/package/typings/index.d.ts @@ -0,0 +1,90 @@ +import * as React from "react"; +import {type FC} from "react"; +import * as ReactNative from "react-native"; +import {type ImageURISource} from "react-native"; + +type Constructor = new (...args: any[]) => T; + +type SliderReferenceType = + | (React.MutableRefObject & React.LegacyRef) + | undefined; + +export interface SliderPropsAndroid extends ReactNative.ViewProps { + /** + * Color of the foreground switch grip. + */ + thumbTintColor?: string; +} + +export interface SliderRef { + updateValue(value: number): void; +} + +export type TrackMarksProps = { + isTrue: boolean; + index: number; + thumbImage?: ImageURISource; + StepMarker?: FC | boolean; + currentValue: number; +}; + +export type MarkerProps = { + stepMarked: boolean; + currentValue: number; + index: number; + min: number; + max: number; +}; + +export interface SliderPropsIOS extends ReactNative.ViewProps { + maximumTrackImage?: ReactNative.ImageURISource; + minimumTrackImage?: ReactNative.ImageURISource; + tapToSeek?: boolean; + thumbImage?: ReactNative.ImageURISource; + trackImage?: ReactNative.ImageURISource; +} + +export interface SliderPropsWindows extends ReactNative.ViewProps { + /** + * Controls the orientation of the slider, default value is false. + */ + vertical?: boolean; +} + +export interface SliderProps + extends SliderPropsIOS, + SliderPropsAndroid, + SliderPropsWindows { + disabled?: boolean; + maximumTrackTintColor?: string; + maximumValue?: number; + maxValue?: number; + lowerLimit?: number; + upperLimit?: number; + minimumTrackTintColor?: string; + minimumValue?: number; + minValue?: number; + onSlidingStart?: (value: number) => void; + onSlidingComplete?: (value: number) => void; + onValueChange?: (value: number) => void; + step?: number; + style?: ReactNative.StyleProp; + testID?: string; + value?: number; + inverted?: boolean; + thumbSize?: number; + StepMarker?: FC; + renderStepNumber?: boolean; + accessibilityUnits?: string; + accessibilityIncrements?: Array; + ref?: SliderReferenceType; +} + +/** + * A component used to select a single value from a range of values. + */ +declare class SliderComponent extends React.Component {} +declare const SliderBase: Constructor & + typeof SliderComponent; +export default class Slider extends SliderBase {} +export type SliderIOS = Slider; From 2abd25f8049673b284766291da3803da8b1f2d4c Mon Sep 17 00:00:00 2001 From: Maciej Lodygowski Date: Thu, 25 Jun 2026 08:58:22 +0200 Subject: [PATCH 7/7] Add package slider tests --- example/package-lock.json | 3817 +++++++++++------------------ package/__tests__/Slider.test.tsx | 135 + package/package.json | 1 + 3 files changed, 1516 insertions(+), 2437 deletions(-) create mode 100644 package/__tests__/Slider.test.tsx diff --git a/example/package-lock.json b/example/package-lock.json index 2c5d4c09..306098bc 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -1,51 +1,45 @@ { - "name": "example", + "name": "slider-example", "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "example", + "name": "slider-example", "version": "0.0.1", "hasInstallScript": true, "dependencies": { + "@mgcrea/react-native-jetpack-compose": "^0.8.0", "@react-native-community/slider": "file:../package", - "babel-preset-expo": "^9.2.0", - "react": "^19.0.0", - "react-native": "^0.79.2", - "react-native-pager-view": "^6.6.0" + "react": "19.2.3", + "react-native": "0.85.1", + "react-native-pager-view": "^6.9.1" }, "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "@babel/runtime": "^7.25.0", - "@react-native-community/cli": "^20.0.2", - "@react-native-community/cli-debugger-ui": "^16.0.0", - "@react-native-community/cli-platform-android": "^20.0.2", - "@react-native-community/cli-platform-ios": "^20.0.2", - "@react-native-community/eslint-config": "^3.2.0", - "@react-native/babel-preset": "0.79.2", - "@react-native/eslint-config": "0.79.2", - "@react-native/metro-config": "0.79.2", - "@react-native/typescript-config": "0.79.2", + "@react-native-community/cli": "20.1.0", + "@react-native-community/cli-platform-android": "20.1.0", + "@react-native-community/cli-platform-ios": "20.1.0", + "@react-native/babel-preset": "0.85.1", + "@react-native/eslint-config": "0.85.1", + "@react-native/jest-preset": "0.85.1", + "@react-native/metro-config": "0.85.1", + "@react-native/typescript-config": "0.85.1", "@types/jest": "^29.5.13", - "@types/react": "^19.0.0", - "@types/react-test-renderer": "^19.0.0", - "@typescript-eslint/eslint-plugin": "^5.36.2", - "@typescript-eslint/parser": "^5.36.2", - "babel-jest": "^29.6.3", + "@types/react": "^19.2.0", + "@types/react-test-renderer": "^19.1.0", "copyfiles": "^2.4.1", "eslint": "^8.19.0", - "eslint-plugin-prettier": "4.2.1", "jest": "^29.6.3", - "metro-config": "^0.80.7", "prettier": "2.8.8", - "react-test-renderer": "19.0.0", + "react-test-renderer": "19.2.3", "rimraf": "^5.0.5", - "typescript": "5.0.4" + "typescript": "^5.8.3" }, "engines": { - "node": ">=18" + "node": ">= 22.11.0" } }, "../package": { @@ -12474,6 +12468,7 @@ }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.27.3", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.3" @@ -12498,6 +12493,7 @@ }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -12517,6 +12513,7 @@ }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.28.5", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -12532,6 +12529,7 @@ }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.6.8", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.28.6", @@ -12544,16 +12542,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-globals": { "version": "7.29.7", "license": "MIT", @@ -12563,6 +12551,7 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.28.5", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.5", @@ -12600,6 +12589,7 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.27.1", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.1" @@ -12610,6 +12600,7 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.29.7", + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -12617,6 +12608,7 @@ }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.27.1", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -12632,6 +12624,7 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.28.5", @@ -12647,6 +12640,7 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.27.1", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -12679,6 +12673,7 @@ }, "node_modules/@babel/helper-wrap-function": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -12715,6 +12710,7 @@ }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { "version": "7.28.5", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -12729,6 +12725,7 @@ }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -12742,6 +12739,7 @@ }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -12755,6 +12753,7 @@ }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -12770,6 +12769,7 @@ }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -12782,53 +12782,9 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "license": "MIT", - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.29.0", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-syntax-decorators": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-proposal-export-default-from": { "version": "7.27.1", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -12840,82 +12796,9 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -12926,6 +12809,7 @@ }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -12936,6 +12820,7 @@ }, "node_modules/@babel/plugin-syntax-bigint": { "version": "7.8.3", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -12946,6 +12831,7 @@ }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" @@ -12956,6 +12842,7 @@ }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -12967,21 +12854,9 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.28.6", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -12992,6 +12867,7 @@ }, "node_modules/@babel/plugin-syntax-export-default-from": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13005,6 +12881,7 @@ }, "node_modules/@babel/plugin-syntax-flow": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13018,6 +12895,7 @@ }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13031,6 +12909,7 @@ }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13044,6 +12923,7 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -13054,6 +12934,7 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -13064,6 +12945,7 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13077,6 +12959,7 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -13087,6 +12970,7 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -13097,6 +12981,7 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -13107,6 +12992,7 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -13117,6 +13003,7 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -13127,6 +13014,7 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -13137,6 +13025,7 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -13150,6 +13039,7 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -13163,6 +13053,7 @@ }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13176,6 +13067,7 @@ }, "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", @@ -13190,6 +13082,7 @@ }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13203,6 +13096,7 @@ }, "node_modules/@babel/plugin-transform-async-generator-functions": { "version": "7.29.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -13218,6 +13112,7 @@ }, "node_modules/@babel/plugin-transform-async-to-generator": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -13233,6 +13128,7 @@ }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13246,6 +13142,7 @@ }, "node_modules/@babel/plugin-transform-block-scoping": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13259,6 +13156,7 @@ }, "node_modules/@babel/plugin-transform-class-properties": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", @@ -13273,6 +13171,7 @@ }, "node_modules/@babel/plugin-transform-class-static-block": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", @@ -13287,6 +13186,7 @@ }, "node_modules/@babel/plugin-transform-classes": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -13305,6 +13205,7 @@ }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -13319,6 +13220,7 @@ }, "node_modules/@babel/plugin-transform-destructuring": { "version": "7.28.5", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -13333,6 +13235,7 @@ }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -13347,6 +13250,7 @@ }, "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13360,6 +13264,7 @@ }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { "version": "7.29.0", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -13374,6 +13279,7 @@ }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13387,6 +13293,7 @@ }, "node_modules/@babel/plugin-transform-explicit-resource-management": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -13401,6 +13308,7 @@ }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13414,6 +13322,7 @@ }, "node_modules/@babel/plugin-transform-export-namespace-from": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13427,6 +13336,7 @@ }, "node_modules/@babel/plugin-transform-flow-strip-types": { "version": "7.27.1", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -13441,6 +13351,7 @@ }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.27.1", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -13455,6 +13366,7 @@ }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", @@ -13470,6 +13382,7 @@ }, "node_modules/@babel/plugin-transform-json-strings": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13483,6 +13396,7 @@ }, "node_modules/@babel/plugin-transform-literals": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13496,6 +13410,7 @@ }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13509,6 +13424,7 @@ }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13522,6 +13438,7 @@ }, "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.27.1", @@ -13536,6 +13453,7 @@ }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.28.6", @@ -13550,6 +13468,7 @@ }, "node_modules/@babel/plugin-transform-modules-systemjs": { "version": "7.29.7", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.29.7", @@ -13566,6 +13485,7 @@ }, "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.27.1", @@ -13580,6 +13500,7 @@ }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "version": "7.29.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -13594,6 +13515,7 @@ }, "node_modules/@babel/plugin-transform-new-target": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13607,6 +13529,7 @@ }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13620,6 +13543,7 @@ }, "node_modules/@babel/plugin-transform-numeric-separator": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13633,6 +13557,7 @@ }, "node_modules/@babel/plugin-transform-object-rest-spread": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.28.6", @@ -13650,6 +13575,7 @@ }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -13664,6 +13590,7 @@ }, "node_modules/@babel/plugin-transform-optional-catch-binding": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13677,6 +13604,7 @@ }, "node_modules/@babel/plugin-transform-optional-chaining": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -13691,6 +13619,7 @@ }, "node_modules/@babel/plugin-transform-parameters": { "version": "7.27.7", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13704,6 +13633,7 @@ }, "node_modules/@babel/plugin-transform-private-methods": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", @@ -13718,6 +13648,7 @@ }, "node_modules/@babel/plugin-transform-private-property-in-object": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -13733,6 +13664,7 @@ }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13746,6 +13678,7 @@ }, "node_modules/@babel/plugin-transform-react-display-name": { "version": "7.28.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13759,6 +13692,7 @@ }, "node_modules/@babel/plugin-transform-react-jsx": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -13774,21 +13708,9 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.27.1", - "license": "MIT", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.27.1", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13802,6 +13724,7 @@ }, "node_modules/@babel/plugin-transform-react-jsx-source": { "version": "7.27.1", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13813,22 +13736,9 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.27.1", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.29.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -13842,6 +13752,7 @@ }, "node_modules/@babel/plugin-transform-regexp-modifiers": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -13856,6 +13767,7 @@ }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13869,6 +13781,7 @@ }, "node_modules/@babel/plugin-transform-runtime": { "version": "7.29.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -13887,6 +13800,7 @@ }, "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-corejs3": { "version": "0.13.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", @@ -13898,6 +13812,7 @@ }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13911,6 +13826,7 @@ }, "node_modules/@babel/plugin-transform-spread": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -13925,6 +13841,7 @@ }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13938,6 +13855,7 @@ }, "node_modules/@babel/plugin-transform-template-literals": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13951,6 +13869,7 @@ }, "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13964,6 +13883,7 @@ }, "node_modules/@babel/plugin-transform-typescript": { "version": "7.28.6", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -13981,6 +13901,7 @@ }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.27.1", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -13994,6 +13915,7 @@ }, "node_modules/@babel/plugin-transform-unicode-property-regex": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -14008,6 +13930,7 @@ }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.27.1", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -14022,6 +13945,7 @@ }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { "version": "7.28.6", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", @@ -14036,6 +13960,7 @@ }, "node_modules/@babel/preset-env": { "version": "7.29.2", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.29.0", @@ -14118,6 +14043,7 @@ }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -14128,24 +14054,6 @@ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/preset-react": { - "version": "7.28.5", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-transform-react-display-name": "^7.28.0", - "@babel/plugin-transform-react-jsx": "^7.27.1", - "@babel/plugin-transform-react-jsx-development": "^7.27.1", - "@babel/plugin-transform-react-pure-annotations": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/runtime": { "version": "7.29.2", "license": "MIT", @@ -14181,23 +14089,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse--for-generate-function-map": { - "name": "@babel/traverse", - "version": "7.29.0", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { "version": "7.29.7", "license": "MIT", @@ -14308,11 +14199,15 @@ }, "node_modules/@hapi/hoek": { "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", "devOptional": true, "license": "BSD-3-Clause" }, "node_modules/@hapi/topo": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -14440,6 +14335,8 @@ }, "node_modules/@isaacs/ttlcache": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", "license": "ISC", "engines": { "node": ">=12" @@ -14447,6 +14344,7 @@ }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", + "devOptional": true, "license": "ISC", "dependencies": { "camelcase": "^5.3.1", @@ -14461,6 +14359,7 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { "version": "4.1.0", + "devOptional": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -14472,6 +14371,7 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { "version": "5.0.0", + "devOptional": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -14482,6 +14382,7 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { "version": "2.3.0", + "devOptional": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -14495,6 +14396,7 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { "version": "4.1.0", + "devOptional": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -14505,6 +14407,7 @@ }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -14574,6 +14477,7 @@ }, "node_modules/@jest/create-cache-key-function": { "version": "29.7.0", + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3" @@ -14584,6 +14488,7 @@ }, "node_modules/@jest/environment": { "version": "29.7.0", + "devOptional": true, "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.7.0", @@ -14620,6 +14525,7 @@ }, "node_modules/@jest/fake-timers": { "version": "29.7.0", + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -14768,6 +14674,7 @@ }, "node_modules/@jest/transform": { "version": "29.7.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", @@ -14830,6 +14737,8 @@ }, "node_modules/@jridgewell/source-map": { "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -14848,6 +14757,19 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mgcrea/react-native-jetpack-compose": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@mgcrea/react-native-jetpack-compose/-/react-native-jetpack-compose-0.8.0.tgz", + "integrity": "sha512-DFk1TBfoYeL734onXPa5DHvoz0+PQUoVCLsE6pxWzrwHKbusIob/jZ4QF/Kx6qfegOqscSn0YXHuLayhMWhyXA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": ">=18.2.0", + "react-native": ">=0.76.0" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "dev": true, @@ -14856,17 +14778,6 @@ "eslint-scope": "5.1.1" } }, - "node_modules/@nodable/entities": { - "version": "2.2.0", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/nodable" - } - ], - "license": "MIT" - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "devOptional": true, @@ -14909,16 +14820,18 @@ } }, "node_modules/@react-native-community/cli": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-20.1.0.tgz", + "integrity": "sha512-441WsVtRe4nGJ9OzA+QMU1+22lA6Q2hRWqqIMKD0wjEMLqcSfOZyu2UL9a/yRpL/dRpyUsU4n7AxqKfTKO/Csg==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-clean": "20.1.3", - "@react-native-community/cli-config": "20.1.3", - "@react-native-community/cli-doctor": "20.1.3", - "@react-native-community/cli-server-api": "20.1.3", - "@react-native-community/cli-tools": "20.1.3", - "@react-native-community/cli-types": "20.1.3", + "@react-native-community/cli-clean": "20.1.0", + "@react-native-community/cli-config": "20.1.0", + "@react-native-community/cli-doctor": "20.1.0", + "@react-native-community/cli-server-api": "20.1.0", + "@react-native-community/cli-tools": "20.1.0", + "@react-native-community/cli-types": "20.1.0", "commander": "^9.4.1", "deepmerge": "^4.3.0", "execa": "^5.0.0", @@ -14937,22 +14850,26 @@ } }, "node_modules/@react-native-community/cli-clean": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-20.1.0.tgz", + "integrity": "sha512-77L4DifWfxAT8ByHnkypge7GBMYpbJAjBGV+toowt5FQSGaTBDcBHCX+FFqFRukD5fH6i8sZ41Gtw+nbfCTTIA==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-tools": "20.1.3", + "@react-native-community/cli-tools": "20.1.0", "execa": "^5.0.0", "fast-glob": "^3.3.2", "picocolors": "^1.1.1" } }, "node_modules/@react-native-community/cli-config": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-20.1.0.tgz", + "integrity": "sha512-1x9rhLLR/dKKb92Lb5O0l0EmUG08FHf+ZVyVEf9M+tX+p5QIm52MRiy43R0UAZ2jJnFApxRk+N3sxoYK4Dtnag==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-tools": "20.1.3", + "@react-native-community/cli-tools": "20.1.0", "cosmiconfig": "^9.0.0", "deepmerge": "^4.3.0", "fast-glob": "^3.3.2", @@ -14961,45 +14878,43 @@ } }, "node_modules/@react-native-community/cli-config-android": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config-android/-/cli-config-android-20.1.0.tgz", + "integrity": "sha512-3A01ZDyFeCALzzPcwP/fleHoP3sGNq1UX7FzxkTrOFX8RRL9ntXNXQd27E56VU4BBxGAjAJT4Utw8pcOjJceIA==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-tools": "20.1.3", + "@react-native-community/cli-tools": "20.1.0", "fast-glob": "^3.3.2", - "fast-xml-parser": "^5.3.6", + "fast-xml-parser": "^4.4.1", "picocolors": "^1.1.1" } }, "node_modules/@react-native-community/cli-config-apple": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config-apple/-/cli-config-apple-20.1.0.tgz", + "integrity": "sha512-n6JVs8Q3yxRbtZQOy05ofeb1kGtspGN3SgwPmuaqvURF9fsuS7c4/9up2Kp9C+1D2J1remPJXiZLNGOcJvfpOA==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-tools": "20.1.3", + "@react-native-community/cli-tools": "20.1.0", "execa": "^5.0.0", "fast-glob": "^3.3.2", "picocolors": "^1.1.1" } }, - "node_modules/@react-native-community/cli-debugger-ui": { - "version": "16.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "serve-static": "^1.13.1" - } - }, "node_modules/@react-native-community/cli-doctor": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-20.1.0.tgz", + "integrity": "sha512-QfJF1GVjA4PBrIT3SJ0vFFIu0km1vwOmLDlOYVqfojajZJ+Dnvl0f94GN1il/jT7fITAxom///XH3/URvi7YTQ==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-config": "20.1.3", - "@react-native-community/cli-platform-android": "20.1.3", - "@react-native-community/cli-platform-apple": "20.1.3", - "@react-native-community/cli-platform-ios": "20.1.3", - "@react-native-community/cli-tools": "20.1.3", + "@react-native-community/cli-config": "20.1.0", + "@react-native-community/cli-platform-android": "20.1.0", + "@react-native-community/cli-platform-apple": "20.1.0", + "@react-native-community/cli-platform-ios": "20.1.0", + "@react-native-community/cli-tools": "20.1.0", "command-exists": "^1.2.8", "deepmerge": "^4.3.0", "envinfo": "^7.13.0", @@ -15013,7 +14928,9 @@ } }, "node_modules/@react-native-community/cli-doctor/node_modules/semver": { - "version": "7.7.4", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "devOptional": true, "license": "ISC", "bin": { @@ -15024,44 +14941,52 @@ } }, "node_modules/@react-native-community/cli-platform-android": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-20.1.0.tgz", + "integrity": "sha512-TeHPDThOwDppQRpndm9kCdRCBI8AMy3HSIQ+iy7VYQXL5BtZ5LfmGdusoj7nVN/ZGn0Lc6Gwts5qowyupXdeKg==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-config-android": "20.1.3", - "@react-native-community/cli-tools": "20.1.3", + "@react-native-community/cli-config-android": "20.1.0", + "@react-native-community/cli-tools": "20.1.0", "execa": "^5.0.0", "logkitty": "^0.7.1", "picocolors": "^1.1.1" } }, "node_modules/@react-native-community/cli-platform-apple": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-apple/-/cli-platform-apple-20.1.0.tgz", + "integrity": "sha512-0ih1hrYezSM2cuOlVnwBEFtMwtd8YgpTLmZauDJCv50rIumtkI1cQoOgLoS4tbPCj9U/Vn2a9BFH0DLFOOIacg==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-config-apple": "20.1.3", - "@react-native-community/cli-tools": "20.1.3", + "@react-native-community/cli-config-apple": "20.1.0", + "@react-native-community/cli-tools": "20.1.0", "execa": "^5.0.0", - "fast-xml-parser": "^5.3.6", + "fast-xml-parser": "^4.4.1", "picocolors": "^1.1.1" } }, "node_modules/@react-native-community/cli-platform-ios": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-20.1.0.tgz", + "integrity": "sha512-XN7Da9z4WsJxtqVtEzY8q2bv22OsvzaFP5zy5+phMWNoJlU4lf7IvBSxqGYMpQ9XhYP7arDw5vmW4W34s06rnA==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-platform-apple": "20.1.3" + "@react-native-community/cli-platform-apple": "20.1.0" } }, "node_modules/@react-native-community/cli-server-api": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-20.1.0.tgz", + "integrity": "sha512-Tb415Oh8syXNT2zOzLzFkBXznzGaqKCiaichxKzGCDKg6JGHp3jSuCmcTcaPeYC7oc32n/S3Psw7798r4Q/7lA==", "devOptional": true, "license": "MIT", "dependencies": { - "@react-native-community/cli-tools": "20.1.3", - "body-parser": "^2.2.2", + "@react-native-community/cli-tools": "20.1.0", + "body-parser": "^1.20.3", "compression": "^1.7.1", "connect": "^3.6.5", "errorhandler": "^1.5.1", @@ -15069,12 +14994,13 @@ "open": "^6.2.0", "pretty-format": "^29.7.0", "serve-static": "^1.13.1", - "strict-url-sanitise": "0.0.1", "ws": "^6.2.3" } }, "node_modules/@react-native-community/cli-tools": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-20.1.0.tgz", + "integrity": "sha512-/YmzHGOkY6Bgrv4OaA1L8rFqsBlQd1EB2/ipAoKPiieV0EcB5PUamUSuNeFU3sBZZTYQCUENwX4wgOHgFUlDnQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -15091,7 +15017,9 @@ } }, "node_modules/@react-native-community/cli-tools/node_modules/semver": { - "version": "7.7.4", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "devOptional": true, "license": "ISC", "bin": { @@ -15102,7 +15030,9 @@ } }, "node_modules/@react-native-community/cli-types": { - "version": "20.1.3", + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-20.1.0.tgz", + "integrity": "sha512-D0kDspcwgbVXyNjwicT7Bb1JgXjijTw1JJd+qxyF/a9+sHv7TU4IchV+gN38QegeXqVyM4Ym7YZIvXMFBmyJqA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -15120,61 +15050,38 @@ "node": ">=10" } }, - "node_modules/@react-native-community/eslint-config": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.14.0", - "@babel/eslint-parser": "^7.18.2", - "@react-native-community/eslint-plugin": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.30.5", - "@typescript-eslint/parser": "^5.30.5", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-ft-flow": "^2.0.1", - "eslint-plugin-jest": "^26.5.3", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "^7.30.1", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-native": "^4.0.0" - }, - "peerDependencies": { - "eslint": ">=8", - "prettier": ">=2" - } - }, - "node_modules/@react-native-community/eslint-plugin": { - "version": "1.3.0", - "dev": true, - "license": "MIT" - }, "node_modules/@react-native-community/slider": { "resolved": "../package", "link": true }, "node_modules/@react-native/assets-registry": { - "version": "0.79.7", + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.85.1.tgz", + "integrity": "sha512-QODQ15teXThKaKdb7lnx4RifNUGnsGZ/NMKtkNBE89nJuK93+mPsb1ozp5xkGyLw7ZNVYO4Nkqsp4MsBOuAX8g==", "license": "MIT", "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/@react-native/babel-plugin-codegen": { - "version": "0.79.2", - "dev": true, + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.85.1.tgz", + "integrity": "sha512-Klex4kTsRxoswZmo7EBXobvpg+HO6h7xeGo87CLXSKPq3qHlJ8ilpgtmzYCTK+Qr/0Mk3cz2zv3bA9VTXR+NDA==", + "devOptional": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.3", - "@react-native/codegen": "0.79.2" + "@babel/traverse": "^7.29.0", + "@react-native/codegen": "0.85.1" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/@react-native/babel-preset": { - "version": "0.79.2", - "dev": true, + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.85.1.tgz", + "integrity": "sha512-Mplsn13fCxQElOfWg6wIuXJP+tyO980etTQ1gQFTt5Zstj3rs33GzTLMNlo6EnT8PQghO3GxIrg/2im5GwodnA==", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -15183,27 +15090,19 @@ "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", - "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.25.1", - "@babel/plugin-transform-literals": "^7.25.2", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", @@ -15212,1226 +15111,654 @@ "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/template": "^7.25.0", - "@react-native/babel-plugin-codegen": "0.79.2", - "babel-plugin-syntax-hermes-parser": "0.25.1", + "@react-native/babel-plugin-codegen": "0.85.1", + "babel-plugin-syntax-hermes-parser": "0.33.3", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, "peerDependencies": { "@babel/core": "*" } }, "node_modules/@react-native/codegen": { - "version": "0.79.2", - "dev": true, + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.85.1.tgz", + "integrity": "sha512-Ge8F5VejnI7ng/NGObqBBovuLbItvmmZDFQ1Qwt/nBhHtk7l2tOffNMVNTta9Jt8TW0oXxVj6FG3hr6nx03JrQ==", "license": "MIT", "dependencies": { - "glob": "^7.1.1", - "hermes-parser": "0.25.1", + "@babel/core": "^7.25.2", + "@babel/parser": "^7.29.0", + "hermes-parser": "0.33.3", "invariant": "^2.2.4", "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", "yargs": "^17.6.2" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, "peerDependencies": { "@babel/core": "*" } }, "node_modules/@react-native/community-cli-plugin": { - "version": "0.79.7", + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.85.1.tgz", + "integrity": "sha512-vZtNEYv5qMYvbA9cTBMuZ3QkCqyJ7lDQgbxh4MpoZHZ0+62qjJpCXn9xzFM0Rm5ZG2hO8WDDxcFdI581BdASdg==", "license": "MIT", "dependencies": { - "@react-native/dev-middleware": "0.79.7", - "chalk": "^4.0.0", - "debug": "^2.2.0", + "@react-native/dev-middleware": "0.85.1", + "debug": "^4.4.0", "invariant": "^2.2.4", - "metro": "^0.82.0", - "metro-config": "^0.82.0", - "metro-core": "^0.82.0", + "metro": "^0.84.0", + "metro-config": "^0.84.0", + "metro-core": "^0.84.0", "semver": "^7.1.3" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, "peerDependencies": { - "@react-native-community/cli": "*" + "@react-native-community/cli": "*", + "@react-native/metro-config": "0.85.1" }, "peerDependenciesMeta": { "@react-native-community/cli": { "optional": true + }, + "@react-native/metro-config": { + "optional": true } } }, - "node_modules/@react-native/community-cli-plugin/node_modules/ci-info": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/@react-native/community-cli-plugin/node_modules/cosmiconfig": { - "version": "5.2.1", - "license": "MIT", - "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "node_modules/@react-native/community-cli-plugin/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=4" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node": ">=10" } }, - "node_modules/@react-native/community-cli-plugin/node_modules/hermes-estree": { - "version": "0.29.1", - "license": "MIT" - }, - "node_modules/@react-native/community-cli-plugin/node_modules/hermes-parser": { - "version": "0.29.1", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.29.1" + "node_modules/@react-native/debugger-frontend": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.85.1.tgz", + "integrity": "sha512-GUC2ZEy+J/Goc4l243XeeY/8NdNXVXPXoRTc6Yy14OiDcy7Yk87VyrMARbp23wCbzhnrz0dnYB8rxJ+AJvMzCg==", + "license": "BSD-3-Clause", + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/@react-native/community-cli-plugin/node_modules/import-fresh": { - "version": "2.0.0", + "node_modules/@react-native/debugger-shell": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.85.1.tgz", + "integrity": "sha512-M/ogODh0uDFJ7xOlCc+v9nKUucUXGJwVOupl+zb3VT8tJnI2Cie/Fiv9NszAD/bzRQhJSrPZkJSAO6VW0XbWyA==", "license": "MIT", "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "cross-spawn": "^7.0.6", + "debug": "^4.4.0", + "fb-dotslash": "0.5.8" }, "engines": { - "node": ">=4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro": { - "version": "0.82.5", + "node_modules/@react-native/dev-middleware": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.85.1.tgz", + "integrity": "sha512-vJSIZP7yymZMnwOrdNjalVf8jqcAFtmi6zT3sC9MRMgJPGkDy05g8y5zgAkgTxpNtVsv+/q5pst8woYp7pgRkA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", - "@babel/types": "^7.25.2", - "accepts": "^1.3.7", - "chalk": "^4.0.0", - "ci-info": "^2.0.0", + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.85.1", + "@react-native/debugger-shell": "0.85.1", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.3.0", "connect": "^3.6.5", "debug": "^4.4.0", - "error-stack-parser": "^2.0.6", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "hermes-parser": "0.29.1", - "image-size": "^1.0.2", "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "jsc-safe-url": "^0.2.2", - "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.82.5", - "metro-cache": "0.82.5", - "metro-cache-key": "0.82.5", - "metro-config": "0.82.5", - "metro-core": "0.82.5", - "metro-file-map": "0.82.5", - "metro-resolver": "0.82.5", - "metro-runtime": "0.82.5", - "metro-source-map": "0.82.5", - "metro-symbolicate": "0.82.5", - "metro-transform-plugins": "0.82.5", - "metro-transform-worker": "0.82.5", - "mime-types": "^2.1.27", "nullthrows": "^1.1.1", - "serialize-error": "^2.1.0", - "source-map": "^0.5.6", - "throat": "^5.0.0", - "ws": "^7.5.10", - "yargs": "^17.6.2" - }, - "bin": { - "metro": "src/cli.js" + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^7.5.10" }, "engines": { - "node": ">=18.18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-babel-transformer": { - "version": "0.82.5", + "node_modules/@react-native/dev-middleware/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "license": "MIT", "dependencies": { - "@babel/core": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.29.1", - "nullthrows": "^1.1.1" + "is-docker": "^2.0.0" }, "engines": { - "node": ">=18.18" + "node": ">=8" } }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-cache": { - "version": "0.82.5", + "node_modules/@react-native/dev-middleware/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "license": "MIT", "dependencies": { - "exponential-backoff": "^3.1.1", - "flow-enums-runtime": "^0.0.6", - "https-proxy-agent": "^7.0.5", - "metro-core": "0.82.5" + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" }, "engines": { - "node": ">=18.18" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-cache-key": { - "version": "0.82.5", + "node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, "engines": { - "node": ">=18.18" + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-config": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/eslint-config/-/eslint-config-0.85.1.tgz", + "integrity": "sha512-iowegGInEgNrllpsGZz6rRzLXm+3pl5ZVvVlLeCydNrtRAXygowGHgrCt/+GoTBq0NDvItSbULLR3X9nF/tlUw==", + "dev": true, "license": "MIT", "dependencies": { - "connect": "^3.6.5", - "cosmiconfig": "^5.0.5", - "flow-enums-runtime": "^0.0.6", - "jest-validate": "^29.7.0", - "metro": "0.82.5", - "metro-cache": "0.82.5", - "metro-core": "0.82.5", - "metro-runtime": "0.82.5" + "@babel/core": "^7.25.2", + "@babel/eslint-parser": "^7.25.1", + "@react-native/eslint-plugin": "0.85.1", + "@typescript-eslint/eslint-plugin": "^8.36.0", + "@typescript-eslint/parser": "^8.36.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-ft-flow": "^2.0.1", + "eslint-plugin-jest": "^29.0.1", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-native": "^5.0.0" }, "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-core": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "lodash.throttle": "^4.1.1", - "metro-resolver": "0.82.5" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-file-map": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "fb-watchman": "^2.0.0", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "nullthrows": "^1.1.1", - "walker": "^1.0.7" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-file-map/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-file-map/node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-minify-terser": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "terser": "^5.15.0" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-resolver": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-source-map": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.3", - "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", - "@babel/types": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-symbolicate": "0.82.5", - "nullthrows": "^1.1.1", - "ob1": "0.82.5", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-symbolicate": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-source-map": "0.82.5", - "nullthrows": "^1.1.1", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "bin": { - "metro-symbolicate": "src/index.js" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-transform-plugins": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", - "flow-enums-runtime": "^0.0.6", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro-transform-worker": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/types": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "metro": "0.82.5", - "metro-babel-transformer": "0.82.5", - "metro-cache": "0.82.5", - "metro-cache-key": "0.82.5", - "metro-minify-terser": "0.82.5", - "metro-source-map": "0.82.5", - "metro-transform-plugins": "0.82.5", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/metro/node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, - "node_modules/@react-native/community-cli-plugin/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/@react-native/community-cli-plugin/node_modules/ob1": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/parse-json": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/resolve-from": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/semver": { - "version": "7.7.4", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/source-map": { - "version": "0.5.7", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@react-native/community-cli-plugin/node_modules/ws": { - "version": "7.5.11", - "license": "MIT", - "engines": { - "node": ">=8.3.0" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@react-native/debugger-frontend": { - "version": "0.79.7", - "license": "BSD-3-Clause", - "engines": { - "node": ">=18" - } - }, - "node_modules/@react-native/dev-middleware": { - "version": "0.79.7", - "license": "MIT", - "dependencies": { - "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.79.7", - "chrome-launcher": "^0.15.2", - "chromium-edge-launcher": "^0.2.0", - "connect": "^3.6.5", - "debug": "^2.2.0", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "open": "^7.0.3", - "serve-static": "^1.16.2", - "ws": "^6.2.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@react-native/dev-middleware/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/@react-native/dev-middleware/node_modules/is-wsl": { - "version": "2.2.0", - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@react-native/dev-middleware/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/@react-native/dev-middleware/node_modules/open": { - "version": "7.4.2", - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@react-native/eslint-config": { - "version": "0.79.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/eslint-parser": "^7.25.1", - "@react-native/eslint-plugin": "0.79.2", - "@typescript-eslint/eslint-plugin": "^7.1.1", - "@typescript-eslint/parser": "^7.1.1", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-ft-flow": "^2.0.1", - "eslint-plugin-jest": "^27.9.0", - "eslint-plugin-react": "^7.30.1", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-native": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": ">=8", + "eslint": "^8.0.0 || ^9.0.0", "prettier": ">=2" } }, - "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.18.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/type-utils": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.18.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/parser": { - "version": "7.18.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/type-utils": { - "version": "7.18.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "7.18.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/types": { - "version": "7.18.0", + "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.0.tgz", + "integrity": "sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==", "dev": true, "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/type-utils": "8.62.0", + "@typescript-eslint/utils": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.62.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", + "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/parser": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.0.tgz", + "integrity": "sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "debug": "^4.4.3" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", + "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/scope-manager": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz", + "integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@react-native/eslint-config/node_modules/brace-expansion": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@react-native/eslint-config/node_modules/eslint-plugin-jest": { - "version": "27.9.0", + "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/type-utils": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.0.tgz", + "integrity": "sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^5.10.0" + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/utils": "8.62.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0", - "eslint": "^7.0.0 || ^8.0.0", - "jest": "*" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@react-native/eslint-config/node_modules/eslint-visitor-keys": { - "version": "3.4.3", + "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/types": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", + "integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@react-native/eslint-config/node_modules/minimatch": { - "version": "9.0.9", + "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz", + "integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.2" + "@typescript-eslint/project-service": "8.62.0", + "@typescript-eslint/tsconfig-utils": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@react-native/eslint-config/node_modules/semver": { - "version": "7.7.4", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@react-native/eslint-plugin": { - "version": "0.79.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@react-native/gradle-plugin": { - "version": "0.79.7", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@react-native/js-polyfills": { - "version": "0.79.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@react-native/metro-babel-transformer": { - "version": "0.79.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@react-native/babel-preset": "0.79.2", - "hermes-parser": "0.25.1", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">=18" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@babel/core": "*" + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@react-native/metro-config": { - "version": "0.79.2", + "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/utils": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.0.tgz", + "integrity": "sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==", "dev": true, "license": "MIT", "dependencies": { - "@react-native/js-polyfills": "0.79.2", - "@react-native/metro-babel-transformer": "0.79.2", - "metro-config": "^0.82.0", - "metro-runtime": "^0.82.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0" }, "engines": { - "node": ">=18" - } - }, - "node_modules/@react-native/metro-config/node_modules/ci-info": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@react-native/metro-config/node_modules/cosmiconfig": { - "version": "5.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@react-native/metro-config/node_modules/hermes-estree": { - "version": "0.29.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@react-native/metro-config/node_modules/hermes-parser": { - "version": "0.29.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hermes-estree": "0.29.1" - } - }, - "node_modules/@react-native/metro-config/node_modules/import-fresh": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@react-native/metro-config/node_modules/metro": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz", + "integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", - "@babel/types": "^7.25.2", - "accepts": "^1.3.7", - "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "connect": "^3.6.5", - "debug": "^4.4.0", - "error-stack-parser": "^2.0.6", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "hermes-parser": "0.29.1", - "image-size": "^1.0.2", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "jsc-safe-url": "^0.2.2", - "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.82.5", - "metro-cache": "0.82.5", - "metro-cache-key": "0.82.5", - "metro-config": "0.82.5", - "metro-core": "0.82.5", - "metro-file-map": "0.82.5", - "metro-resolver": "0.82.5", - "metro-runtime": "0.82.5", - "metro-source-map": "0.82.5", - "metro-symbolicate": "0.82.5", - "metro-transform-plugins": "0.82.5", - "metro-transform-worker": "0.82.5", - "mime-types": "^2.1.27", - "nullthrows": "^1.1.1", - "serialize-error": "^2.1.0", - "source-map": "^0.5.6", - "throat": "^5.0.0", - "ws": "^7.5.10", - "yargs": "^17.6.2" - }, - "bin": { - "metro": "src/cli.js" + "@typescript-eslint/types": "8.62.0", + "eslint-visitor-keys": "^5.0.0" }, "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-babel-transformer": { - "version": "0.82.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.29.1", - "nullthrows": "^1.1.1" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "engines": { - "node": ">=18.18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@react-native/metro-config/node_modules/metro-cache": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", - "dependencies": { - "exponential-backoff": "^3.1.1", - "flow-enums-runtime": "^0.0.6", - "https-proxy-agent": "^7.0.5", - "metro-core": "0.82.5" - }, "engines": { - "node": ">=18.18" + "node": "18 || 20 || >=22" } }, - "node_modules/@react-native/metro-config/node_modules/metro-cache-key": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { - "flow-enums-runtime": "^0.0.6" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=18.18" + "node": "18 || 20 || >=22" } }, - "node_modules/@react-native/metro-config/node_modules/metro-config": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/eslint-plugin-jest": { + "version": "29.15.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.2.tgz", + "integrity": "sha512-kEN4r9RZl1xcsb4arGq89LrcVdOUFII/JSCwtTPJyv16mDwmPrcuEQwpxqZHeINvcsd7oK5O/rhdGlxFRaZwvQ==", "dev": true, "license": "MIT", "dependencies": { - "connect": "^3.6.5", - "cosmiconfig": "^5.0.5", - "flow-enums-runtime": "^0.0.6", - "jest-validate": "^29.7.0", - "metro": "0.82.5", - "metro-cache": "0.82.5", - "metro-core": "0.82.5", - "metro-runtime": "0.82.5" + "@typescript-eslint/utils": "^8.0.0" }, "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-core": { - "version": "0.82.5", - "dev": true, - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "lodash.throttle": "^4.1.1", - "metro-resolver": "0.82.5" + "node": "^20.12.0 || ^22.0.0 || >=24.0.0" }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-file-map": { - "version": "0.82.5", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "fb-watchman": "^2.0.0", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "nullthrows": "^1.1.1", - "walker": "^1.0.7" + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "jest": "*", + "typescript": ">=4.8.4 <7.0.0" }, - "engines": { - "node": ">=18.18" + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + }, + "typescript": { + "optional": true + } } }, - "node_modules/@react-native/metro-config/node_modules/metro-minify-terser": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", "dev": true, "license": "MIT", "dependencies": { - "flow-enums-runtime": "^0.0.6", - "terser": "^5.15.0" + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" }, "engines": { - "node": ">=18.18" + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/@react-native/metro-config/node_modules/metro-resolver": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/eslint-plugin-react-native": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-5.0.0.tgz", + "integrity": "sha512-VyWlyCC/7FC/aONibOwLkzmyKg4j9oI8fzrk9WYNs4I8/m436JuOTAFwLvEn1CVvc7La4cPfbCyspP4OYpP52Q==", "dev": true, "license": "MIT", "dependencies": { - "flow-enums-runtime": "^0.0.6" + "eslint-plugin-react-native-globals": "^0.1.1" }, + "peerDependencies": { + "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/@react-native/eslint-config/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=18.18" + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@react-native/metro-config/node_modules/metro-source-map": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/eslint-config/node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.3", - "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", - "@babel/types": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-symbolicate": "0.82.5", - "nullthrows": "^1.1.1", - "ob1": "0.82.5", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "engines": { - "node": ">=18.18" + "hermes-estree": "0.25.1" } }, - "node_modules/@react-native/metro-config/node_modules/metro-symbolicate": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-source-map": "0.82.5", - "nullthrows": "^1.1.1", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "bin": { - "metro-symbolicate": "src/index.js" - }, "engines": { - "node": ">=18.18" + "node": ">= 4" } }, - "node_modules/@react-native/metro-config/node_modules/metro-transform-plugins": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", - "flow-enums-runtime": "^0.0.6", - "nullthrows": "^1.1.1" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">=18.18" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@react-native/metro-config/node_modules/metro-transform-worker": { - "version": "0.82.5", + "node_modules/@react-native/eslint-config/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/types": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "metro": "0.82.5", - "metro-babel-transformer": "0.82.5", - "metro-cache": "0.82.5", - "metro-cache-key": "0.82.5", - "metro-minify-terser": "0.82.5", - "metro-source-map": "0.82.5", - "metro-transform-plugins": "0.82.5", - "nullthrows": "^1.1.1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=18.18" + "node": ">=10" } }, - "node_modules/@react-native/metro-config/node_modules/ob1": { - "version": "0.82.5", + "node_modules/@react-native/eslint-plugin": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/eslint-plugin/-/eslint-plugin-0.85.1.tgz", + "integrity": "sha512-FkAq0dbkvSM5cJnSCDDR/5VrduPGN2P1ASCF6J4cTEL1vtAFUApTFpoNyIedRglfrWG85UZzD/WYj1E2y+I3hw==", "dev": true, "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, "engines": { - "node": ">=18.18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/@react-native/metro-config/node_modules/parse-json": { - "version": "4.0.0", - "dev": true, + "node_modules/@react-native/gradle-plugin": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.85.1.tgz", + "integrity": "sha512-KeTntbnsH/NOdzZrSE8tgep+9jEMlEfklVDtgxnjjb5nDhhBD016judwyo9bsinZnuwXxmemXnOOqOfcEawxbg==", "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, "engines": { - "node": ">=4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/@react-native/metro-config/node_modules/resolve-from": { - "version": "3.0.0", - "dev": true, + "node_modules/@react-native/jest-preset": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/jest-preset/-/jest-preset-0.85.1.tgz", + "integrity": "sha512-SoD4J18a+yZXjpc/0R2Kaxh++yCEAsMuiVX/lYnIUahBv/Fz/kkaXkrU9Cw4IYtg2YbHkOBNgAeSRfEHwEu44g==", + "devOptional": true, "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.7.0", + "@react-native/js-polyfills": "0.85.1", + "babel-jest": "^29.7.0", + "jest-environment-node": "^29.7.0", + "regenerator-runtime": "^0.13.2" + }, "engines": { - "node": ">=4" + "node": ">= 20.19.4" + }, + "peerDependencies": { + "react": "^19.2.3" } }, - "node_modules/@react-native/metro-config/node_modules/source-map": { - "version": "0.5.7", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@react-native/js-polyfills": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.85.1.tgz", + "integrity": "sha512-VseQZAKnDbmpZThLWviDIJ0NmuSiwiHA6vc2HNJTTVqTy2mQR0+858y9kDdDBQPYe0HH8+W1mYui2i4eUWGh4g==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/@react-native/metro-config/node_modules/ws": { - "version": "7.5.11", - "dev": true, + "node_modules/@react-native/metro-babel-transformer": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.85.1.tgz", + "integrity": "sha512-oXAVv9GfGYxkqdf20o+gbJSw4yqaUZr7AZMZ4bJG8Nom/T9GmLu/Pd2kJo5U6NQYIndgfgU73pzRgL8H7YCIWw==", + "devOptional": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@react-native/babel-preset": "0.85.1", + "hermes-parser": "0.33.3", + "nullthrows": "^1.1.1" + }, "engines": { - "node": ">=8.3.0" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "@babel/core": "*" + } + }, + "node_modules/@react-native/metro-config": { + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.85.1.tgz", + "integrity": "sha512-Na0OD2YFM7rESHJ3ETuYHnXNc5TJU/fpwlLmN2/uDTM9ZDb6EaEfFKZaXGbUm2lBYyeo/FG3Ur4glu8jLWMNgQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@react-native/js-polyfills": "0.85.1", + "@react-native/metro-babel-transformer": "0.85.1", + "metro-config": "^0.84.0", + "metro-runtime": "^0.84.0" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/@react-native/normalize-colors": { - "version": "0.79.7", + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.85.1.tgz", + "integrity": "sha512-w+4ZZ2PvvtC0IODEmxizYOrHmeDgdzpM7CKhtTNWoNtDWZoi7/ZY3UmNntn9poPorUy5cwFbfYiP/8rJFEsFvQ==", "license": "MIT" }, "node_modules/@react-native/typescript-config": { - "version": "0.79.2", + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/typescript-config/-/typescript-config-0.85.1.tgz", + "integrity": "sha512-Smy8J4WRfsJU/ym5tMftaXaCK8A/KFzgRNlFdDhDwW5iEBUSaRdTjhewGLlL7czHWXc/iHLTFLBBfB9hhi3BfQ==", "dev": true, "license": "MIT" }, "node_modules/@react-native/virtualized-lists": { - "version": "0.79.7", + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.85.1.tgz", + "integrity": "sha512-RLpoATkxeTaYxna5dDLIxEtoStp9UL7ryHIIOmKnE9NQW3ggR+U9DWQPXQkOfRc7/kPYba4ynKA2fIISGysVTg==", "license": "MIT", "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, "peerDependencies": { - "@types/react": "^19.0.0", + "@types/react": "^19.2.0", "react": "*", - "react-native": "*" + "react-native": "0.85.1" }, "peerDependenciesMeta": { "@types/react": { @@ -16441,6 +15768,8 @@ }, "node_modules/@sideway/address": { "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -16449,11 +15778,15 @@ }, "node_modules/@sideway/formula": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", "devOptional": true, "license": "BSD-3-Clause" }, "node_modules/@sideway/pinpoint": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", "devOptional": true, "license": "BSD-3-Clause" }, @@ -16463,6 +15796,7 @@ }, "node_modules/@sinonjs/commons": { "version": "3.0.1", + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" @@ -16470,6 +15804,7 @@ }, "node_modules/@sinonjs/fake-timers": { "version": "10.3.0", + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0" @@ -16477,6 +15812,7 @@ }, "node_modules/@types/babel__core": { "version": "7.20.5", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", @@ -16488,6 +15824,7 @@ }, "node_modules/@types/babel__generator": { "version": "7.27.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -16495,6 +15832,7 @@ }, "node_modules/@types/babel__template": { "version": "7.4.4", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", @@ -16503,6 +15841,7 @@ }, "node_modules/@types/babel__traverse": { "version": "7.28.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.2" @@ -16510,6 +15849,7 @@ }, "node_modules/@types/graceful-fs": { "version": "4.1.9", + "devOptional": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -16542,276 +15882,96 @@ "pretty-format": "^29.0.0" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.5.2", - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.14", - "devOptional": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-test-renderer": { - "version": "19.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/semver": { - "version": "7.7.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "license": "MIT" - }, - "node_modules/@types/yargs": { - "version": "17.0.35", - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.7.4", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "dev": true, + "node_modules/@types/node": { + "version": "25.5.2", "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "undici-types": "~7.18.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "dev": true, + "node_modules/@types/react": { + "version": "19.2.14", + "devOptional": true, "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "dependencies": { + "csstype": "^3.2.2" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", + "node_modules/@types/react-test-renderer": { + "version": "19.1.0", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@types/react": "*" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.4", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" } }, - "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "license": "MIT" + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz", + "integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@typescript-eslint/tsconfig-utils": "^8.62.0", + "@typescript-eslint/types": "^8.62.0", + "debug": "^4.4.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.7.4", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", + "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", + "integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.4.3", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz", + "integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@ungap/structured-clone": { @@ -16821,6 +15981,8 @@ }, "node_modules/@vscode/sudo-prompt": { "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@vscode/sudo-prompt/-/sudo-prompt-9.3.2.tgz", + "integrity": "sha512-gcXoCN00METUNFeQOFJ+C9xUI0DKB+0EGMVg7wbVYRHBw2Eq3fKisDZOkRdOz3kqXRKOENMfShPOmypw1/8nOw==", "devOptional": true, "license": "MIT" }, @@ -16836,6 +15998,7 @@ }, "node_modules/accepts": { "version": "1.3.8", + "devOptional": true, "license": "MIT", "dependencies": { "mime-types": "~2.1.34", @@ -16847,6 +16010,7 @@ }, "node_modules/accepts/node_modules/negotiator": { "version": "0.6.3", + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -16872,6 +16036,8 @@ }, "node_modules/agent-base": { "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", "engines": { "node": ">= 14" @@ -16923,6 +16089,8 @@ }, "node_modules/ansi-fragments": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-fragments/-/ansi-fragments-0.2.1.tgz", + "integrity": "sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -16933,6 +16101,8 @@ }, "node_modules/ansi-fragments/node_modules/ansi-regex": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "devOptional": true, "license": "MIT", "engines": { @@ -16941,6 +16111,8 @@ }, "node_modules/ansi-fragments/node_modules/strip-ansi": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -16972,6 +16144,7 @@ }, "node_modules/anymatch": { "version": "3.1.3", + "devOptional": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -16981,24 +16154,16 @@ "node": ">= 8" } }, - "node_modules/anynum": { - "version": "1.0.1", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT" - }, "node_modules/appdirsjs": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz", + "integrity": "sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==", "devOptional": true, "license": "MIT" }, "node_modules/argparse": { "version": "1.0.10", + "devOptional": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -17040,14 +16205,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "dev": true, @@ -17142,6 +16299,8 @@ }, "node_modules/astral-regex": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "devOptional": true, "license": "MIT", "engines": { @@ -17158,6 +16317,9 @@ }, "node_modules/async-limiter": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "devOptional": true, "license": "MIT" }, "node_modules/available-typed-arrays": { @@ -17176,6 +16338,7 @@ }, "node_modules/babel-jest": { "version": "29.7.0", + "devOptional": true, "license": "MIT", "dependencies": { "@jest/transform": "^29.7.0", @@ -17195,6 +16358,7 @@ }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -17209,6 +16373,7 @@ }, "node_modules/babel-plugin-jest-hoist": { "version": "29.6.3", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", @@ -17220,55 +16385,9 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-plugin-module-resolver": { - "version": "5.0.3", - "license": "MIT", - "dependencies": { - "find-babel-config": "^2.1.1", - "glob": "^9.3.3", - "pkg-up": "^3.1.0", - "reselect": "^4.1.7", - "resolve": "^1.22.8" - } - }, - "node_modules/babel-plugin-module-resolver/node_modules/brace-expansion": { - "version": "2.0.3", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/babel-plugin-module-resolver/node_modules/glob": { - "version": "9.3.5", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/babel-plugin-module-resolver/node_modules/minimatch": { - "version": "8.0.7", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.17", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -17281,6 +16400,7 @@ }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.14.2", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.8", @@ -17292,6 +16412,7 @@ }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.6.8", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.8" @@ -17300,19 +16421,18 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/babel-plugin-react-native-web": { - "version": "0.18.12", - "license": "MIT" - }, "node_modules/babel-plugin-syntax-hermes-parser": { - "version": "0.25.1", + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.33.3.tgz", + "integrity": "sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==", "license": "MIT", "dependencies": { - "hermes-parser": "0.25.1" + "hermes-parser": "0.33.3" } }, "node_modules/babel-plugin-transform-flow-enums": { "version": "0.0.2", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-flow": "^7.12.1" @@ -17320,6 +16440,7 @@ }, "node_modules/babel-preset-current-node-syntax": { "version": "1.2.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -17342,23 +16463,9 @@ "@babel/core": "^7.0.0 || ^8.0.0-0" } }, - "node_modules/babel-preset-expo": { - "version": "9.9.0", - "license": "MIT", - "dependencies": { - "@babel/plugin-proposal-decorators": "^7.12.9", - "@babel/plugin-proposal-object-rest-spread": "^7.12.13", - "@babel/plugin-transform-export-namespace-from": "^7.22.11", - "@babel/plugin-transform-parameters": "^7.22.15", - "@babel/preset-env": "^7.20.0", - "@babel/preset-react": "^7.22.15", - "babel-plugin-module-resolver": "^5.0.0", - "babel-plugin-react-native-web": "~0.18.10", - "metro-react-native-babel-preset": "0.76.8" - } - }, "node_modules/babel-preset-jest": { "version": "29.6.3", + "devOptional": true, "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", @@ -17373,6 +16480,7 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "devOptional": true, "license": "MIT" }, "node_modules/base64-js": { @@ -17405,6 +16513,8 @@ }, "node_modules/bl": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -17415,6 +16525,8 @@ }, "node_modules/bl/node_modules/readable-stream": { "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -17428,6 +16540,8 @@ }, "node_modules/bl/node_modules/string_decoder": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -17435,30 +16549,50 @@ } }, "node_modules/body-parser": { - "version": "2.2.2", + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", "devOptional": true, "license": "MIT", "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "devOptional": true, + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.13", + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -17515,6 +16649,8 @@ }, "node_modules/buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "devOptional": true, "funding": [ { @@ -17542,6 +16678,8 @@ }, "node_modules/bytes": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "devOptional": true, "license": "MIT", "engines": { @@ -17592,33 +16730,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-callsite/node_modules/callsites": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/callsites": { "version": "3.1.0", "devOptional": true, @@ -17629,6 +16740,7 @@ }, "node_modules/camelcase": { "version": "5.3.1", + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -17676,6 +16788,8 @@ }, "node_modules/chrome-launcher": { "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", "license": "Apache-2.0", "dependencies": { "@types/node": "*", @@ -17692,6 +16806,8 @@ }, "node_modules/chrome-launcher/node_modules/is-wsl": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -17701,19 +16817,22 @@ } }, "node_modules/chromium-edge-launcher": { - "version": "0.2.0", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.3.0.tgz", + "integrity": "sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==", "license": "Apache-2.0", "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", - "lighthouse-logger": "^1.0.0", - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4" } }, "node_modules/chromium-edge-launcher/node_modules/is-wsl": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -17722,19 +16841,6 @@ "node": ">=8" } }, - "node_modules/chromium-edge-launcher/node_modules/rimraf": { - "version": "3.0.2", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ci-info": { "version": "3.9.0", "funding": [ @@ -17755,6 +16861,8 @@ }, "node_modules/cli-cursor": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -17766,6 +16874,8 @@ }, "node_modules/cli-spinners": { "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "devOptional": true, "license": "MIT", "engines": { @@ -17789,6 +16899,8 @@ }, "node_modules/clone": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "devOptional": true, "license": "MIT", "engines": { @@ -17825,11 +16937,15 @@ }, "node_modules/colorette": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", "devOptional": true, "license": "MIT" }, "node_modules/command-exists": { "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", "devOptional": true, "license": "MIT" }, @@ -17843,6 +16959,8 @@ }, "node_modules/compressible": { "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -17854,6 +16972,8 @@ }, "node_modules/compression": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -17871,6 +16991,8 @@ }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -17879,11 +17001,14 @@ }, "node_modules/compression/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "devOptional": true, "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", + "devOptional": true, "license": "MIT" }, "node_modules/connect": { @@ -17912,6 +17037,8 @@ }, "node_modules/content-type": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "devOptional": true, "license": "MIT", "engines": { @@ -17977,6 +17104,7 @@ }, "node_modules/core-js-compat": { "version": "3.49.0", + "devOptional": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.1" @@ -17992,7 +17120,9 @@ "license": "MIT" }, "node_modules/cosmiconfig": { - "version": "9.0.1", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -18018,11 +17148,15 @@ }, "node_modules/cosmiconfig/node_modules/argparse": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "devOptional": true, "license": "Python-2.0" }, "node_modules/cosmiconfig/node_modules/js-yaml": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "devOptional": true, "funding": [ { @@ -18064,7 +17198,6 @@ }, "node_modules/cross-spawn": { "version": "7.0.6", - "devOptional": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -18129,7 +17262,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.20", + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", "devOptional": true, "license": "MIT" }, @@ -18150,6 +17285,8 @@ }, "node_modules/decamelize": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "devOptional": true, "license": "MIT", "engines": { @@ -18184,6 +17321,8 @@ }, "node_modules/defaults": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -18225,11 +17364,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/denodeify": { - "version": "1.2.1", - "dev": true, - "license": "MIT" - }, "node_modules/depd": { "version": "2.0.0", "license": "MIT", @@ -18261,17 +17395,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { "version": "3.0.0", "dev": true, @@ -18333,6 +17456,8 @@ }, "node_modules/env-paths": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "devOptional": true, "license": "MIT", "engines": { @@ -18341,6 +17466,8 @@ }, "node_modules/envinfo": { "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", "devOptional": true, "license": "MIT", "bin": { @@ -18352,6 +17479,7 @@ }, "node_modules/error-ex": { "version": "1.3.4", + "devOptional": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -18359,6 +17487,8 @@ }, "node_modules/error-stack-parser": { "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", "license": "MIT", "dependencies": { "stackframe": "^1.3.4" @@ -18366,6 +17496,8 @@ }, "node_modules/errorhandler": { "version": "1.5.2", + "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.2.tgz", + "integrity": "sha512-kNAL7hESndBCrWwS72QyV3IVOTrVmj9D062FV5BQswNL5zEdeRmz/WJFyh6Aj/plvvSOrzddkxW57HgkZcR9Fw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -18670,49 +17802,6 @@ "eslint": "^8.1.0" } }, - "node_modules/eslint-plugin-jest": { - "version": "26.9.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/utils": "^5.10.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "4.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-plugin-react": { "version": "7.37.5", "dev": true, @@ -18744,28 +17833,6 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react-native": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-plugin-react-native-globals": "^0.1.1" - }, - "peerDependencies": { - "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, "node_modules/eslint-plugin-react-native-globals": { "version": "0.1.2", "dev": true, @@ -18913,6 +17980,7 @@ }, "node_modules/esprima": { "version": "4.0.1", + "devOptional": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -18954,6 +18022,7 @@ }, "node_modules/esutils": { "version": "2.0.3", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -19019,6 +18088,8 @@ }, "node_modules/exponential-backoff": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", "license": "Apache-2.0" }, "node_modules/fast-deep-equal": { @@ -19026,11 +18097,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-diff": { - "version": "1.3.0", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/fast-glob": { "version": "3.3.3", "devOptional": true, @@ -19059,6 +18125,7 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", + "devOptional": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -19066,23 +18133,10 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-xml-builder": { - "version": "1.2.0", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "dependencies": { - "path-expression-matcher": "^1.5.0", - "xml-naming": "^0.1.0" - } - }, "node_modules/fast-xml-parser": { - "version": "5.9.3", + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.6.tgz", + "integrity": "sha512-Yd4vkROfJf8AuJrDIVMVmYfULKmIJszVsMv7Vo71aocsKgFxpdlpSHXSaInvyYfgw2PRuObQSW2GFpVMUjxu9A==", "devOptional": true, "funding": [ { @@ -19092,12 +18146,7 @@ ], "license": "MIT", "dependencies": { - "@nodable/entities": "^2.2.0", - "fast-xml-builder": "^1.2.0", - "is-unsafe": "^1.0.1", - "path-expression-matcher": "^1.5.0", - "strnum": "^2.4.1", - "xml-naming": "^0.1.0" + "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" @@ -19111,6 +18160,18 @@ "reusify": "^1.0.4" } }, + "node_modules/fb-dotslash": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", + "integrity": "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "dotslash": "bin/dotslash" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/fb-watchman": { "version": "2.0.2", "license": "Apache-2.0", @@ -19176,13 +18237,6 @@ "node": ">= 0.8" } }, - "node_modules/find-babel-config": { - "version": "2.1.2", - "license": "MIT", - "dependencies": { - "json5": "^2.2.3" - } - }, "node_modules/find-up": { "version": "5.0.0", "devOptional": true, @@ -19296,10 +18350,12 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "devOptional": true, "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -19311,6 +18367,7 @@ }, "node_modules/function-bind": { "version": "1.1.2", + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -19390,6 +18447,7 @@ }, "node_modules/get-package-type": { "version": "0.1.0", + "devOptional": true, "license": "MIT", "engines": { "node": ">=8.0.0" @@ -19436,6 +18494,7 @@ }, "node_modules/glob": { "version": "7.2.3", + "devOptional": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -19492,25 +18551,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { "version": "1.2.0", "devOptional": true, @@ -19601,6 +18641,7 @@ }, "node_modules/hasown": { "version": "2.0.2", + "devOptional": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -19609,15 +18650,25 @@ "node": ">= 0.4" } }, + "node_modules/hermes-compiler": { + "version": "250829098.0.10", + "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.10.tgz", + "integrity": "sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w==", + "license": "MIT" + }, "node_modules/hermes-estree": { - "version": "0.25.1", + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", + "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", "license": "MIT" }, "node_modules/hermes-parser": { - "version": "0.25.1", + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", + "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", "license": "MIT", "dependencies": { - "hermes-estree": "0.25.1" + "hermes-estree": "0.33.3" } }, "node_modules/html-escaper": { @@ -19652,6 +18703,8 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -19670,22 +18723,22 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.2", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "devOptional": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" } }, "node_modules/ieee754": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "devOptional": true, "funding": [ { @@ -19713,6 +18766,8 @@ }, "node_modules/image-size": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", "license": "MIT", "dependencies": { "queue": "6.0.2" @@ -19767,6 +18822,7 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -19774,6 +18830,7 @@ }, "node_modules/inflight": { "version": "1.0.6", + "devOptional": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -19822,6 +18879,7 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", + "devOptional": true, "license": "MIT" }, "node_modules/is-async-function": { @@ -19884,6 +18942,7 @@ }, "node_modules/is-core-module": { "version": "2.16.1", + "devOptional": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -19926,15 +18985,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-directory": { - "version": "0.3.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-docker": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "license": "MIT", "bin": { "is-docker": "cli.js" @@ -19970,6 +19024,8 @@ }, "node_modules/is-fullwidth-code-point": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", "devOptional": true, "license": "MIT", "engines": { @@ -20015,6 +19071,8 @@ }, "node_modules/is-interactive": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "devOptional": true, "license": "MIT", "engines": { @@ -20173,6 +19231,8 @@ }, "node_modules/is-unicode-supported": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "devOptional": true, "license": "MIT", "engines": { @@ -20182,17 +19242,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-unsafe": { - "version": "1.0.1", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT" - }, "node_modules/is-weakmap": { "version": "2.0.2", "dev": true, @@ -20235,6 +19284,8 @@ }, "node_modules/is-wsl": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", "devOptional": true, "license": "MIT", "engines": { @@ -20248,11 +19299,11 @@ }, "node_modules/isexe": { "version": "2.0.0", - "devOptional": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=8" @@ -20260,6 +19311,7 @@ }, "node_modules/istanbul-lib-instrument": { "version": "5.2.1", + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", @@ -20526,6 +19578,7 @@ }, "node_modules/jest-environment-node": { "version": "29.7.0", + "devOptional": true, "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", @@ -20548,6 +19601,7 @@ }, "node_modules/jest-haste-map": { "version": "29.7.0", + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -20597,6 +19651,7 @@ }, "node_modules/jest-message-util": { "version": "29.7.0", + "devOptional": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", @@ -20615,6 +19670,7 @@ }, "node_modules/jest-mock": { "version": "29.7.0", + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -20643,6 +19699,7 @@ }, "node_modules/jest-regex-util": { "version": "29.6.3", + "devOptional": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -20869,6 +19926,8 @@ }, "node_modules/joi": { "version": "17.13.4", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.4.tgz", + "integrity": "sha512-1RuuER6kmt8K8I3nIWvPZKi5RQCb568ZPyY4Pwjlua+yo+63ZTmIwxLZH0heBmiKN4uxjvCiarDrjaeH84xicQ==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -20885,6 +19944,7 @@ }, "node_modules/js-yaml": { "version": "3.14.2", + "devOptional": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -20896,6 +19956,8 @@ }, "node_modules/jsc-safe-url": { "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", "license": "0BSD" }, "node_modules/jsesc": { @@ -20913,10 +19975,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "license": "MIT" - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "devOptional": true, @@ -20982,6 +20040,8 @@ }, "node_modules/launch-editor": { "version": "2.14.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz", + "integrity": "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -21010,6 +20070,8 @@ }, "node_modules/lighthouse-logger": { "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", "license": "Apache-2.0", "dependencies": { "debug": "^2.6.9", @@ -21018,6 +20080,8 @@ }, "node_modules/lighthouse-logger/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -21025,6 +20089,8 @@ }, "node_modules/lighthouse-logger/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/lines-and-columns": { @@ -21053,6 +20119,7 @@ }, "node_modules/lodash.debounce": { "version": "4.0.8", + "devOptional": true, "license": "MIT" }, "node_modules/lodash.merge": { @@ -21062,10 +20129,14 @@ }, "node_modules/lodash.throttle": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -21081,6 +20152,8 @@ }, "node_modules/logkitty": { "version": "0.7.1", + "resolved": "https://registry.npmjs.org/logkitty/-/logkitty-0.7.1.tgz", + "integrity": "sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -21094,6 +20167,8 @@ }, "node_modules/logkitty/node_modules/cliui": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -21104,6 +20179,8 @@ }, "node_modules/logkitty/node_modules/find-up": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -21116,6 +20193,8 @@ }, "node_modules/logkitty/node_modules/locate-path": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -21127,6 +20206,8 @@ }, "node_modules/logkitty/node_modules/p-limit": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -21141,6 +20222,8 @@ }, "node_modules/logkitty/node_modules/p-locate": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -21152,6 +20235,8 @@ }, "node_modules/logkitty/node_modules/wrap-ansi": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -21165,11 +20250,15 @@ }, "node_modules/logkitty/node_modules/y18n": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "devOptional": true, "license": "ISC" }, "node_modules/logkitty/node_modules/yargs": { "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -21191,6 +20280,8 @@ }, "node_modules/logkitty/node_modules/yargs-parser": { "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -21252,6 +20343,8 @@ }, "node_modules/marky": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", "license": "Apache-2.0" }, "node_modules/math-intrinsics": { @@ -21263,11 +20356,13 @@ } }, "node_modules/media-typer": { - "version": "1.1.0", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "devOptional": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, "node_modules/memoize-one": { @@ -21287,469 +20382,369 @@ } }, "node_modules/metro": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.4.tgz", + "integrity": "sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/core": "^7.20.0", - "@babel/generator": "^7.20.0", - "@babel/parser": "^7.20.0", - "@babel/template": "^7.0.0", - "@babel/traverse": "^7.20.0", - "@babel/types": "^7.20.0", - "accepts": "^1.3.7", - "chalk": "^4.0.0", + "@babel/code-frame": "^7.29.0", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "accepts": "^2.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", - "debug": "^2.2.0", - "denodeify": "^1.2.1", + "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", - "hermes-parser": "0.23.1", + "hermes-parser": "0.35.0", "image-size": "^1.0.2", "invariant": "^2.2.4", - "jest-worker": "^29.6.3", + "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.80.12", - "metro-cache": "0.80.12", - "metro-cache-key": "0.80.12", - "metro-config": "0.80.12", - "metro-core": "0.80.12", - "metro-file-map": "0.80.12", - "metro-resolver": "0.80.12", - "metro-runtime": "0.80.12", - "metro-source-map": "0.80.12", - "metro-symbolicate": "0.80.12", - "metro-transform-plugins": "0.80.12", - "metro-transform-worker": "0.80.12", - "mime-types": "^2.1.27", + "metro-babel-transformer": "0.84.4", + "metro-cache": "0.84.4", + "metro-cache-key": "0.84.4", + "metro-config": "0.84.4", + "metro-core": "0.84.4", + "metro-file-map": "0.84.4", + "metro-resolver": "0.84.4", + "metro-runtime": "0.84.4", + "metro-source-map": "0.84.4", + "metro-symbolicate": "0.84.4", + "metro-transform-plugins": "0.84.4", + "metro-transform-worker": "0.84.4", + "mime-types": "^3.0.1", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", - "strip-ansi": "^6.0.0", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, - "bin": { - "metro": "src/cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/metro-babel-transformer": { - "version": "0.80.12", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.20.0", - "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.23.1", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/metro-babel-transformer/node_modules/hermes-estree": { - "version": "0.23.1", - "dev": true, - "license": "MIT" - }, - "node_modules/metro-babel-transformer/node_modules/hermes-parser": { - "version": "0.23.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hermes-estree": "0.23.1" - } - }, - "node_modules/metro-cache": { - "version": "0.80.12", - "dev": true, - "license": "MIT", - "dependencies": { - "exponential-backoff": "^3.1.1", - "flow-enums-runtime": "^0.0.6", - "metro-core": "0.80.12" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/metro-cache-key": { - "version": "0.80.12", - "dev": true, - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" + "bin": { + "metro": "src/cli.js" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro-config": { - "version": "0.80.12", - "dev": true, + "node_modules/metro-babel-transformer": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.4.tgz", + "integrity": "sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==", "license": "MIT", "dependencies": { - "connect": "^3.6.5", - "cosmiconfig": "^5.0.5", + "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", - "jest-validate": "^29.6.3", - "metro": "0.80.12", - "metro-cache": "0.80.12", - "metro-core": "0.80.12", - "metro-runtime": "0.80.12" + "hermes-parser": "0.35.0", + "metro-cache-key": "0.84.4", + "nullthrows": "^1.1.1" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro-config/node_modules/cosmiconfig": { - "version": "5.2.1", - "dev": true, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", + "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", + "license": "MIT" + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", + "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", "license": "MIT", "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "engines": { - "node": ">=4" + "hermes-estree": "0.35.0" } }, - "node_modules/metro-config/node_modules/import-fresh": { - "version": "2.0.0", - "dev": true, + "node_modules/metro-cache": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.4.tgz", + "integrity": "sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==", "license": "MIT", "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.84.4" }, "engines": { - "node": ">=4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro-config/node_modules/metro-runtime": { - "version": "0.80.12", - "dev": true, + "node_modules/metro-cache-key": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.4.tgz", + "integrity": "sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro-config/node_modules/parse-json": { - "version": "4.0.0", - "dev": true, + "node_modules/metro-config": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.4.tgz", + "integrity": "sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==", "license": "MIT", "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.84.4", + "metro-cache": "0.84.4", + "metro-core": "0.84.4", + "metro-runtime": "0.84.4", + "yaml": "^2.6.1" }, "engines": { - "node": ">=4" - } - }, - "node_modules/metro-config/node_modules/resolve-from": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-core": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.4.tgz", + "integrity": "sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", - "metro-resolver": "0.80.12" + "metro-resolver": "0.84.4" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-file-map": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.4.tgz", + "integrity": "sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==", "license": "MIT", "dependencies": { - "anymatch": "^3.0.3", - "debug": "^2.2.0", + "debug": "^4.4.0", "fb-watchman": "^2.0.0", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", - "jest-worker": "^29.6.3", + "jest-worker": "^29.7.0", "micromatch": "^4.0.4", - "node-abort-controller": "^3.1.1", "nullthrows": "^1.1.1", "walker": "^1.0.7" }, "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/metro-file-map/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro-file-map/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/metro-minify-terser": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.4.tgz", + "integrity": "sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" }, "engines": { - "node": ">=18" - } - }, - "node_modules/metro-react-native-babel-preset": { - "version": "0.76.8", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.20.0", - "@babel/plugin-proposal-async-generator-functions": "^7.0.0", - "@babel/plugin-proposal-class-properties": "^7.18.0", - "@babel/plugin-proposal-export-default-from": "^7.0.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0", - "@babel/plugin-proposal-numeric-separator": "^7.0.0", - "@babel/plugin-proposal-object-rest-spread": "^7.20.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", - "@babel/plugin-proposal-optional-chaining": "^7.20.0", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", - "@babel/plugin-syntax-export-default-from": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.18.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", - "@babel/plugin-syntax-optional-chaining": "^7.0.0", - "@babel/plugin-transform-arrow-functions": "^7.0.0", - "@babel/plugin-transform-async-to-generator": "^7.20.0", - "@babel/plugin-transform-block-scoping": "^7.0.0", - "@babel/plugin-transform-classes": "^7.0.0", - "@babel/plugin-transform-computed-properties": "^7.0.0", - "@babel/plugin-transform-destructuring": "^7.20.0", - "@babel/plugin-transform-flow-strip-types": "^7.20.0", - "@babel/plugin-transform-function-name": "^7.0.0", - "@babel/plugin-transform-literals": "^7.0.0", - "@babel/plugin-transform-modules-commonjs": "^7.0.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", - "@babel/plugin-transform-parameters": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-react-jsx-self": "^7.0.0", - "@babel/plugin-transform-react-jsx-source": "^7.0.0", - "@babel/plugin-transform-runtime": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0", - "@babel/plugin-transform-spread": "^7.0.0", - "@babel/plugin-transform-sticky-regex": "^7.0.0", - "@babel/plugin-transform-typescript": "^7.5.0", - "@babel/plugin-transform-unicode-regex": "^7.0.0", - "@babel/template": "^7.0.0", - "babel-plugin-transform-flow-enums": "^0.0.2", - "react-refresh": "^0.4.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/metro-react-native-babel-preset/node_modules/react-refresh": { - "version": "0.4.3", - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-resolver": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.4.tgz", + "integrity": "sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-runtime": { - "version": "0.82.5", + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.4.tgz", + "integrity": "sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": ">=18.18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-source-map": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.4.tgz", + "integrity": "sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.20.0", - "@babel/types": "^7.20.0", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-symbolicate": "0.80.12", + "metro-symbolicate": "0.84.4", "nullthrows": "^1.1.1", - "ob1": "0.80.12", + "ob1": "0.84.4", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-source-map/node_modules/source-map": { "version": "0.5.7", - "dev": true, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/metro-symbolicate": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.4.tgz", + "integrity": "sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-source-map": "0.80.12", + "metro-source-map": "0.84.4", "nullthrows": "^1.1.1", "source-map": "^0.5.6", - "through2": "^2.0.1", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-symbolicate/node_modules/source-map": { "version": "0.5.7", - "dev": true, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/metro-transform-plugins": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.4.tgz", + "integrity": "sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==", "license": "MIT", "dependencies": { - "@babel/core": "^7.20.0", - "@babel/generator": "^7.20.0", - "@babel/template": "^7.0.0", - "@babel/traverse": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-transform-worker": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.4.tgz", + "integrity": "sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==", "license": "MIT", "dependencies": { - "@babel/core": "^7.20.0", - "@babel/generator": "^7.20.0", - "@babel/parser": "^7.20.0", - "@babel/types": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "flow-enums-runtime": "^0.0.6", - "metro": "0.80.12", - "metro-babel-transformer": "0.80.12", - "metro-cache": "0.80.12", - "metro-cache-key": "0.80.12", - "metro-minify-terser": "0.80.12", - "metro-source-map": "0.80.12", - "metro-transform-plugins": "0.80.12", + "metro": "0.84.4", + "metro-babel-transformer": "0.84.4", + "metro-cache": "0.84.4", + "metro-cache-key": "0.84.4", + "metro-minify-terser": "0.84.4", + "metro-source-map": "0.84.4", + "metro-transform-plugins": "0.84.4", "nullthrows": "^1.1.1" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro/node_modules/ci-info": { + "node_modules/metro/node_modules/accepts": { "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/metro/node_modules/debug": { - "version": "2.6.9", - "dev": true, + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" } }, + "node_modules/metro/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, "node_modules/metro/node_modules/hermes-estree": { - "version": "0.23.1", - "dev": true, + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", + "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", "license": "MIT" }, "node_modules/metro/node_modules/hermes-parser": { - "version": "0.23.1", - "dev": true, + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", + "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", "license": "MIT", "dependencies": { - "hermes-estree": "0.23.1" + "hermes-estree": "0.35.0" } }, - "node_modules/metro/node_modules/metro-runtime": { - "version": "0.80.12", - "dev": true, + "node_modules/metro/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.25.0", - "flow-enums-runtime": "^0.0.6" + "mime-db": "^1.54.0" }, "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/metro/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" + "node_modules/metro/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, "node_modules/metro/node_modules/source-map": { "version": "0.5.7", - "dev": true, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -21757,7 +20752,8 @@ }, "node_modules/metro/node_modules/ws": { "version": "7.5.11", - "dev": true, + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", "license": "MIT", "engines": { "node": ">=8.3.0" @@ -21788,6 +20784,8 @@ }, "node_modules/mime": { "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "devOptional": true, "license": "MIT", "bin": { @@ -21799,7 +20797,8 @@ }, "node_modules/mime-db": { "version": "1.54.0", - "devOptional": true, + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -21807,6 +20806,7 @@ }, "node_modules/mime-types": { "version": "2.1.35", + "devOptional": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -21817,6 +20817,7 @@ }, "node_modules/mime-types/node_modules/mime-db": { "version": "1.52.0", + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -21832,6 +20833,7 @@ }, "node_modules/minimatch": { "version": "3.1.5", + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -21840,13 +20842,6 @@ "node": "*" } }, - "node_modules/minipass": { - "version": "4.2.8", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, "node_modules/mkdirp": { "version": "1.0.4", "license": "MIT", @@ -21866,13 +20861,10 @@ "dev": true, "license": "MIT" }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, "node_modules/negotiator": { "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "devOptional": true, "license": "MIT", "engines": { @@ -21881,17 +20873,14 @@ }, "node_modules/nocache": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-3.0.4.tgz", + "integrity": "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==", "devOptional": true, "license": "MIT", "engines": { "node": ">=12.0.0" } }, - "node_modules/node-abort-controller": { - "version": "3.1.1", - "dev": true, - "license": "MIT" - }, "node_modules/node-exports-info": { "version": "1.6.0", "dev": true, @@ -21919,6 +20908,8 @@ }, "node_modules/node-stream-zip": { "version": "1.15.0", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", + "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", "devOptional": true, "license": "MIT", "engines": { @@ -21940,6 +20931,7 @@ }, "node_modules/normalize-path": { "version": "3.0.0", + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -21961,14 +20953,15 @@ "license": "MIT" }, "node_modules/ob1": { - "version": "0.80.12", - "dev": true, + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.4.tgz", + "integrity": "sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/object-assign": { @@ -22077,6 +21070,8 @@ }, "node_modules/on-headers": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "devOptional": true, "license": "MIT", "engines": { @@ -22085,6 +21080,7 @@ }, "node_modules/once": { "version": "1.4.0", + "devOptional": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -22106,6 +21102,8 @@ }, "node_modules/open": { "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -22133,6 +21131,8 @@ }, "node_modules/ora": { "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -22199,6 +21199,7 @@ }, "node_modules/p-try": { "version": "2.2.0", + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -22246,27 +21247,15 @@ }, "node_modules/path-exists": { "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-expression-matcher": { - "version": "1.6.1", "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=8" } }, "node_modules/path-is-absolute": { "version": "1.0.1", + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -22274,7 +21263,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -22282,10 +21270,12 @@ }, "node_modules/path-parse": { "version": "1.0.7", + "devOptional": true, "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -22300,23 +21290,17 @@ }, "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.4.3", + "dev": true, "license": "ISC" }, "node_modules/path-scurry/node_modules/minipass": { "version": "7.1.3", + "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, - "node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/picocolors": { "version": "1.1.1", "license": "ISC" @@ -22333,6 +21317,7 @@ }, "node_modules/pirates": { "version": "4.0.7", + "devOptional": true, "license": "MIT", "engines": { "node": ">= 6" @@ -22372,64 +21357,9 @@ "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up": { - "version": "3.1.0", - "license": "MIT", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up/node_modules/find-up": { - "version": "3.0.0", - "license": "MIT", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "license": "MIT", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/p-limit": { + "node_modules/pkg-dir/node_modules/p-limit": { "version": "2.3.0", + "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -22441,21 +21371,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.0.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/possible-typed-array-names": { @@ -22488,17 +21412,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/pretty-format": { "version": "29.7.0", "license": "MIT", @@ -22585,6 +21498,8 @@ }, "node_modules/qs": { "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -22600,6 +21515,8 @@ }, "node_modules/queue": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", "license": "MIT", "dependencies": { "inherits": "~2.0.3" @@ -22632,21 +21549,25 @@ } }, "node_modules/raw-body": { - "version": "3.0.2", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "devOptional": true, "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", + "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 0.8" } }, "node_modules/react": { - "version": "19.2.4", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -22684,57 +21605,59 @@ "license": "MIT" }, "node_modules/react-native": { - "version": "0.79.7", - "license": "MIT", - "dependencies": { - "@jest/create-cache-key-function": "^29.7.0", - "@react-native/assets-registry": "0.79.7", - "@react-native/codegen": "0.79.7", - "@react-native/community-cli-plugin": "0.79.7", - "@react-native/gradle-plugin": "0.79.7", - "@react-native/js-polyfills": "0.79.7", - "@react-native/normalize-colors": "0.79.7", - "@react-native/virtualized-lists": "0.79.7", + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.85.1.tgz", + "integrity": "sha512-1K2TIvu2M1C8gqkPevi/MuLan16mQvEdURiTlwHgrb6S2vvkDyik6TrkkXMlMMhz9hF5RT8wFyDUdlpGFlkpXg==", + "license": "MIT", + "dependencies": { + "@react-native/assets-registry": "0.85.1", + "@react-native/codegen": "0.85.1", + "@react-native/community-cli-plugin": "0.85.1", + "@react-native/gradle-plugin": "0.85.1", + "@react-native/js-polyfills": "0.85.1", + "@react-native/normalize-colors": "0.85.1", + "@react-native/virtualized-lists": "0.85.1", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", - "babel-jest": "^29.7.0", - "babel-plugin-syntax-hermes-parser": "0.25.1", + "babel-plugin-syntax-hermes-parser": "0.33.3", "base64-js": "^1.5.1", - "chalk": "^4.0.0", "commander": "^12.0.0", - "event-target-shim": "^5.0.1", "flow-enums-runtime": "^0.0.6", - "glob": "^7.1.1", + "hermes-compiler": "250829098.0.10", "invariant": "^2.2.4", - "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", - "metro-runtime": "^0.82.0", - "metro-source-map": "^0.82.0", + "metro-runtime": "^0.84.0", + "metro-source-map": "^0.84.0", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", - "react-devtools-core": "^6.1.1", + "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", - "scheduler": "0.25.0", + "scheduler": "0.27.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.15", "whatwg-fetch": "^3.0.0", - "ws": "^6.2.3", + "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "react-native": "cli.js" }, "engines": { - "node": ">=18" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, "peerDependencies": { - "@types/react": "^19.0.0", - "react": "^19.0.0" + "@react-native/jest-preset": "0.85.1", + "@types/react": "^19.1.1", + "react": "^19.2.3" }, "peerDependenciesMeta": { + "@react-native/jest-preset": { + "optional": true + }, "@types/react": { "optional": true } @@ -22748,32 +21671,6 @@ "react-native": "*" } }, - "node_modules/react-native/node_modules/@react-native/codegen": { - "version": "0.79.7", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/parser": "^7.25.3", - "glob": "^7.1.1", - "hermes-parser": "0.25.1", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "yargs": "^17.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/react-native/node_modules/@react-native/js-polyfills": { - "version": "0.79.7", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/react-native/node_modules/commander": { "version": "12.1.0", "license": "MIT", @@ -22781,53 +21678,6 @@ "node": ">=18" } }, - "node_modules/react-native/node_modules/metro-source-map": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.3", - "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", - "@babel/types": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-symbolicate": "0.82.5", - "nullthrows": "^1.1.1", - "ob1": "0.82.5", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/react-native/node_modules/metro-symbolicate": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-source-map": "0.82.5", - "nullthrows": "^1.1.1", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "bin": { - "metro-symbolicate": "src/index.js" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/react-native/node_modules/ob1": { - "version": "0.82.5", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": ">=18.18" - } - }, "node_modules/react-native/node_modules/semver": { "version": "7.7.4", "license": "ISC", @@ -22838,11 +21688,25 @@ "node": ">=10" } }, - "node_modules/react-native/node_modules/source-map": { - "version": "0.5.7", - "license": "BSD-3-Clause", + "node_modules/react-native/node_modules/ws": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/react-refresh": { @@ -22853,15 +21717,17 @@ } }, "node_modules/react-test-renderer": { - "version": "19.0.0", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-19.2.3.tgz", + "integrity": "sha512-TMR1LnSFiWZMJkCgNf5ATSvAheTT2NvKIwiVwdBPHxjBI7n/JbWd4gaZ16DVd9foAXdvDz+sB5yxZTwMjPRxpw==", "dev": true, "license": "MIT", "dependencies": { - "react-is": "^19.0.0", - "scheduler": "^0.25.0" + "react-is": "^19.2.3", + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.0.0" + "react": "^19.2.3" } }, "node_modules/react-test-renderer/node_modules/react-is": { @@ -22903,10 +21769,12 @@ }, "node_modules/regenerate": { "version": "1.4.2", + "devOptional": true, "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.2.2", + "devOptional": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -22940,6 +21808,7 @@ }, "node_modules/regexpu-core": { "version": "6.4.0", + "devOptional": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2", @@ -22955,10 +21824,12 @@ }, "node_modules/regjsgen": { "version": "0.8.0", + "devOptional": true, "license": "MIT" }, "node_modules/regjsparser": { "version": "0.13.0", + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.1.0" @@ -22976,15 +21847,14 @@ }, "node_modules/require-main-filename": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "devOptional": true, "license": "ISC" }, - "node_modules/reselect": { - "version": "4.1.8", - "license": "MIT" - }, "node_modules/resolve": { "version": "1.22.11", + "devOptional": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", @@ -23014,6 +21884,7 @@ }, "node_modules/resolve-from": { "version": "5.0.0", + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -23029,6 +21900,8 @@ }, "node_modules/restore-cursor": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -23158,6 +22031,8 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "devOptional": true, "funding": [ { @@ -23213,11 +22088,15 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "devOptional": true, "license": "MIT" }, "node_modules/scheduler": { - "version": "0.25.0", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, "node_modules/semver": { @@ -23286,6 +22165,8 @@ }, "node_modules/serialize-error": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -23313,6 +22194,8 @@ }, "node_modules/set-blocking": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "devOptional": true, "license": "ISC" }, @@ -23365,7 +22248,6 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "devOptional": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -23376,7 +22258,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -23462,6 +22343,7 @@ }, "node_modules/signal-exit": { "version": "3.0.7", + "devOptional": true, "license": "ISC" }, "node_modules/sisteransi": { @@ -23471,6 +22353,7 @@ }, "node_modules/slash": { "version": "3.0.0", + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -23478,6 +22361,8 @@ }, "node_modules/slice-ansi": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -23491,6 +22376,8 @@ }, "node_modules/slice-ansi/node_modules/ansi-styles": { "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -23502,6 +22389,8 @@ }, "node_modules/slice-ansi/node_modules/color-convert": { "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -23510,6 +22399,8 @@ }, "node_modules/slice-ansi/node_modules/color-name": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "devOptional": true, "license": "MIT" }, @@ -23531,10 +22422,12 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", + "devOptional": true, "license": "BSD-3-Clause" }, "node_modules/stack-utils": { "version": "2.0.6", + "devOptional": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" @@ -23545,6 +22438,7 @@ }, "node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -23552,6 +22446,8 @@ }, "node_modules/stackframe": { "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", "license": "MIT" }, "node_modules/stacktrace-parser": { @@ -23590,11 +22486,6 @@ "node": ">= 0.4" } }, - "node_modules/strict-url-sanitise": { - "version": "0.0.1", - "devOptional": true, - "license": "MIT" - }, "node_modules/string_decoder": { "version": "0.10.31", "dev": true, @@ -23796,7 +22687,9 @@ } }, "node_modules/strnum": { - "version": "2.4.1", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", "devOptional": true, "funding": [ { @@ -23804,10 +22697,7 @@ "url": "https://github.com/sponsors/NaturalIntelligence" } ], - "license": "MIT", - "dependencies": { - "anynum": "^1.0.1" - } + "license": "MIT" }, "node_modules/supports-color": { "version": "7.2.0", @@ -23821,6 +22711,7 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -23830,7 +22721,9 @@ } }, "node_modules/terser": { - "version": "5.46.1", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -23847,10 +22740,14 @@ }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, "node_modules/terser/node_modules/source-map-support": { "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -23859,6 +22756,7 @@ }, "node_modules/test-exclude": { "version": "6.0.0", + "devOptional": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -23876,6 +22774,8 @@ }, "node_modules/throat": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", "license": "MIT" }, "node_modules/through2": { @@ -23919,6 +22819,51 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmpl": { "version": "1.0.5", "license": "BSD-3-Clause" @@ -23941,33 +22886,16 @@ } }, "node_modules/ts-api-utils": { - "version": "1.4.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsutils": { - "version": "3.21.0", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", - "dependencies": { - "tslib": "^1.8.1" - }, "engines": { - "node": ">= 6" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + "typescript": ">=4.8.4" } }, "node_modules/type-check": { @@ -23983,6 +22911,7 @@ }, "node_modules/type-detect": { "version": "4.0.8", + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -24000,33 +22929,19 @@ } }, "node_modules/type-is": { - "version": "2.0.1", + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "devOptional": true, "license": "MIT", "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" + "media-typer": "0.3.0", + "mime-types": "~2.1.24" }, "engines": { "node": ">= 0.6" } }, - "node_modules/type-is/node_modules/mime-types": { - "version": "3.0.2", - "devOptional": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.3", "dev": true, @@ -24098,7 +23013,9 @@ } }, "node_modules/typescript": { - "version": "5.0.4", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -24106,7 +23023,7 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { @@ -24132,6 +23049,7 @@ }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -24139,6 +23057,7 @@ }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", + "devOptional": true, "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", @@ -24150,6 +23069,7 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.2.1", + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -24157,6 +23077,7 @@ }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.2.0", + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -24248,6 +23169,8 @@ }, "node_modules/vary": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "devOptional": true, "license": "MIT", "engines": { @@ -24256,6 +23179,8 @@ }, "node_modules/vlq": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", "license": "MIT" }, "node_modules/walker": { @@ -24267,6 +23192,8 @@ }, "node_modules/wcwidth": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -24279,7 +23206,6 @@ }, "node_modules/which": { "version": "2.0.2", - "devOptional": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -24359,6 +23285,8 @@ }, "node_modules/which-module": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "devOptional": true, "license": "ISC" }, @@ -24424,10 +23352,12 @@ }, "node_modules/wrappy": { "version": "1.0.2", + "devOptional": true, "license": "ISC" }, "node_modules/write-file-atomic": { "version": "4.0.2", + "devOptional": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -24439,25 +23369,14 @@ }, "node_modules/ws": { "version": "6.2.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.4.tgz", + "integrity": "sha512-PNIUUyLI5YpkJZj60YBzX1o0ByQ4ovvfmq9N/Kig/PAYbVlGyz4R6G0SEWrD0O9acc0sT2+IdMBVLFv8FSi0Nw==", + "devOptional": true, "license": "MIT", "dependencies": { "async-limiter": "~1.0.0" } }, - "node_modules/xml-naming": { - "version": "0.1.0", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/xtend": { "version": "4.0.2", "dev": true, @@ -24478,8 +23397,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.3", - "devOptional": true, + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -24524,6 +23444,29 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } } } } diff --git a/package/__tests__/Slider.test.tsx b/package/__tests__/Slider.test.tsx new file mode 100644 index 00000000..77d6a76c --- /dev/null +++ b/package/__tests__/Slider.test.tsx @@ -0,0 +1,135 @@ +import React from 'react'; +import {fireEvent, render} from '@testing-library/react-native'; +import {Text} from 'react-native'; + +import Slider, {type MarkerProps} from '../src/Slider'; + +describe('Slider', () => { + it('maps public value props to native prop names', () => { + const {getByTestId} = render( + , + ); + + expect(getByTestId('slider')).toHaveProp('minValue', 2); + expect(getByTestId('slider')).toHaveProp('maxValue', 10); + expect(getByTestId('slider')).toHaveProp('lowerLimit', 3); + expect(getByTestId('slider')).toHaveProp('upperLimit', 9); + expect(getByTestId('slider')).toHaveProp('value', 4); + expect(getByTestId('slider')).toHaveProp('step', 2); + expect(getByTestId('slider')).toHaveProp('disabled', true); + expect(getByTestId('slider')).toHaveProp('inverted', true); + expect(getByTestId('slider')).toHaveProp('tapToSeek', true); + expect(getByTestId('slider')).toHaveProp('thumbTintColor', 'red'); + }); + + it('keeps minValue and maxValue as compatibility aliases', () => { + const {getByTestId} = render( + , + ); + + expect(getByTestId('slider')).toHaveProp('minValue', 5); + expect(getByTestId('slider')).toHaveProp('maxValue', 15); + }); + + it('forwards native value events with numeric values', () => { + const onValueChange = jest.fn(); + const onSlidingStart = jest.fn(); + const onSlidingComplete = jest.fn(); + const {getByTestId} = render( + , + ); + + fireEvent(getByTestId('slider'), 'onValueChange', { + nativeEvent: {value: 0.25}, + }); + fireEvent(getByTestId('slider'), 'onSlidingStart', { + nativeEvent: {value: 0.5}, + }); + fireEvent(getByTestId('slider'), 'onSlidingComplete', { + nativeEvent: {value: 0.75}, + }); + + expect(onValueChange).toHaveBeenCalledWith(0.25); + expect(onSlidingStart).toHaveBeenCalledWith(0.5); + expect(onSlidingComplete).toHaveBeenCalledWith(0.75); + }); + + it('passes accessibility actions through unchanged', () => { + const onAccessibilityAction = jest.fn(); + const event = {nativeEvent: {actionName: 'increment'}}; + const {getByTestId} = render( + , + ); + + fireEvent(getByTestId('slider'), 'onAccessibilityAction', event); + + expect(onAccessibilityAction).toHaveBeenCalledWith(event); + }); + + it('warns when lowerLimit is greater than upperLimit', () => { + const warn = jest.spyOn(console, 'warn').mockImplementation(() => {}); + + render(); + + expect(warn).toHaveBeenCalledWith( + 'Invalid configuration: lower limit is supposed to be smaller than upper limit', + ); + + warn.mockRestore(); + }); + + it('renders step numbers and custom markers', () => { + const StepMarker = jest.fn(({index, stepMarked}: MarkerProps) => ( + {stepMarked ? 'selected' : 'idle'} + )); + + const {getByTestId} = render( + , + ); + + expect(getByTestId('StepsIndicator-Container')).toBeTruthy(); + expect(getByTestId('0th-step')).toHaveTextContent('0'); + expect(getByTestId('1th-step')).toHaveTextContent('1'); + expect(getByTestId('2th-step')).toHaveTextContent('2'); + expect(getByTestId('marker-1')).toHaveTextContent('selected'); + expect(getByTestId('slider')).toHaveProp('thumbTintColor', 'transparent'); + expect(StepMarker).toHaveBeenCalledWith( + expect.objectContaining({ + currentValue: 1, + index: 1, + max: 2, + min: 0, + stepMarked: true, + }), + undefined, + ); + }); +}); diff --git a/package/package.json b/package/package.json index ca3fe4eb..87985b69 100644 --- a/package/package.json +++ b/package/package.json @@ -60,6 +60,7 @@ "jest": { "preset": "react-native", "verbose": true, + "watchman": false, "modulePathIgnorePatterns": [ "/e2e/" ]