@onekeyfe/react-native-segment-slider 3.0.53 → 3.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -3
- package/SegmentSlider.podspec +1 -1
- package/android/src/main/java/com/margelo/nitro/segmentslider/HybridSegmentSlider.kt +39 -11
- package/android/src/main/java/com/margelo/nitro/segmentslider/SegmentSliderColorParser.kt +19 -3
- package/ios/HybridSegmentSlider.swift +38 -13
- package/ios/SegmentSliderColorParser.swift +40 -9
- package/lib/module/index.js +7 -4
- package/lib/module/index.js.map +1 -1
- package/lib/nitrogen/generated/android/c++/JHybridSegmentSliderSpec.cpp +9 -15
- package/lib/nitrogen/generated/android/c++/JHybridSegmentSliderSpec.hpp +3 -5
- package/lib/nitrogen/generated/android/c++/views/JHybridSegmentSliderStateUpdater.cpp +2 -6
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/segmentslider/HybridSegmentSliderSpec.kt +4 -8
- package/lib/nitrogen/generated/ios/SegmentSlider-Swift-Cxx-Bridge.hpp +11 -0
- package/lib/nitrogen/generated/ios/SegmentSlider-Swift-Cxx-Umbrella.hpp +2 -0
- package/lib/nitrogen/generated/ios/c++/HybridSegmentSliderSpecSwift.hpp +10 -11
- package/lib/nitrogen/generated/ios/c++/views/HybridSegmentSliderComponent.mm +4 -9
- package/lib/nitrogen/generated/ios/swift/HybridSegmentSliderSpec.swift +2 -3
- package/lib/nitrogen/generated/ios/swift/HybridSegmentSliderSpec_cxx.swift +14 -14
- package/lib/nitrogen/generated/shared/c++/HybridSegmentSliderSpec.cpp +3 -4
- package/lib/nitrogen/generated/shared/c++/HybridSegmentSliderSpec.hpp +3 -5
- package/lib/nitrogen/generated/shared/c++/views/HybridSegmentSliderComponent.cpp +7 -19
- package/lib/nitrogen/generated/shared/c++/views/HybridSegmentSliderComponent.hpp +1 -2
- package/lib/nitrogen/generated/shared/json/SegmentSliderConfig.json +1 -2
- package/lib/typescript/src/SegmentSlider.nitro.d.ts +18 -8
- package/lib/typescript/src/SegmentSlider.nitro.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JHybridSegmentSliderSpec.cpp +9 -15
- package/nitrogen/generated/android/c++/JHybridSegmentSliderSpec.hpp +3 -5
- package/nitrogen/generated/android/c++/views/JHybridSegmentSliderStateUpdater.cpp +2 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/segmentslider/HybridSegmentSliderSpec.kt +4 -8
- package/nitrogen/generated/ios/SegmentSlider-Swift-Cxx-Bridge.hpp +11 -0
- package/nitrogen/generated/ios/SegmentSlider-Swift-Cxx-Umbrella.hpp +2 -0
- package/nitrogen/generated/ios/c++/HybridSegmentSliderSpecSwift.hpp +10 -11
- package/nitrogen/generated/ios/c++/views/HybridSegmentSliderComponent.mm +4 -9
- package/nitrogen/generated/ios/swift/HybridSegmentSliderSpec.swift +2 -3
- package/nitrogen/generated/ios/swift/HybridSegmentSliderSpec_cxx.swift +14 -14
- package/nitrogen/generated/shared/c++/HybridSegmentSliderSpec.cpp +3 -4
- package/nitrogen/generated/shared/c++/HybridSegmentSliderSpec.hpp +3 -5
- package/nitrogen/generated/shared/c++/views/HybridSegmentSliderComponent.cpp +7 -19
- package/nitrogen/generated/shared/c++/views/HybridSegmentSliderComponent.hpp +1 -2
- package/nitrogen/generated/shared/json/SegmentSliderConfig.json +1 -2
- package/package.json +1 -1
- package/src/SegmentSlider.nitro.ts +20 -9
- package/src/index.tsx +16 -6
package/README.md
CHANGED
|
@@ -10,12 +10,56 @@ yarn add @onekeyfe/react-native-segment-slider
|
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
The slider is **uncontrolled**: pass the initial value via `defaultValue` (applied
|
|
14
|
+
once on mount), read live changes through `onChange`, and set the value
|
|
15
|
+
imperatively via the `setValue` method on the hybrid ref. This keeps reset/programmatic
|
|
16
|
+
updates off the Fabric prop-commit path and avoids any controlled-value-vs-drag conflict.
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { useMemo, useRef } from 'react';
|
|
20
|
+
import {
|
|
21
|
+
type SegmentSliderMethods,
|
|
22
|
+
type SegmentSliderProps,
|
|
23
|
+
SegmentSliderView,
|
|
24
|
+
} from '@onekeyfe/react-native-segment-slider';
|
|
25
|
+
import { type HybridView, callback } from 'react-native-nitro-modules';
|
|
26
|
+
|
|
27
|
+
type ISegmentSliderRef = HybridView<SegmentSliderProps, SegmentSliderMethods>;
|
|
15
28
|
|
|
16
29
|
// ...
|
|
17
30
|
|
|
18
|
-
|
|
31
|
+
const sliderRef = useRef<ISegmentSliderRef | null>(null);
|
|
32
|
+
const hybridRef = useMemo(
|
|
33
|
+
() => callback((node: ISegmentSliderRef) => { sliderRef.current = node; }),
|
|
34
|
+
[],
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Programmatically move the thumb (does NOT fire onChange):
|
|
38
|
+
// sliderRef.current?.setValue(50);
|
|
39
|
+
|
|
40
|
+
<SegmentSliderView
|
|
41
|
+
style={{ width: 240, height: 24 }}
|
|
42
|
+
hybridRef={hybridRef}
|
|
43
|
+
defaultValue={50}
|
|
44
|
+
min={0}
|
|
45
|
+
max={100}
|
|
46
|
+
segments={4}
|
|
47
|
+
sliderHeight={4}
|
|
48
|
+
disabled={false}
|
|
49
|
+
showBubble={true}
|
|
50
|
+
centerOrigin={false}
|
|
51
|
+
snapTapToSegment={true}
|
|
52
|
+
fillColor="#000000df"
|
|
53
|
+
trackColor="#0000001f"
|
|
54
|
+
thumbColor="#ffffff"
|
|
55
|
+
thumbBorderColor="#00000031"
|
|
56
|
+
markActiveColor="#000000df"
|
|
57
|
+
markInactiveColor="#ffffff"
|
|
58
|
+
markBorderColor="#0000001f"
|
|
59
|
+
bubbleColor="#000000df"
|
|
60
|
+
bubbleTextColor="#ffffff"
|
|
61
|
+
onChange={(nextValue) => console.log(nextValue)}
|
|
62
|
+
/>
|
|
19
63
|
```
|
|
20
64
|
|
|
21
65
|
## Contributing
|
package/SegmentSlider.podspec
CHANGED
|
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
|
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
|
|
13
13
|
s.platforms = { :ios => min_ios_version_supported }
|
|
14
|
-
s.source = { :git => "https://github.com/OneKeyHQ/
|
|
14
|
+
s.source = { :git => "https://github.com/OneKeyHQ/native-views/react-native-segment-slider.git", :tag => "#{s.version}" }
|
|
15
15
|
|
|
16
16
|
s.source_files = [
|
|
17
17
|
"ios/**/*.{swift}",
|
|
@@ -85,7 +85,10 @@ class HybridSegmentSlider(val context: ThemedReactContext) : HybridSegmentSlider
|
|
|
85
85
|
|
|
86
86
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
87
87
|
if (disabled || isDisposed) return false
|
|
88
|
-
|
|
88
|
+
// Use actionMasked so multi-touch pointer events (ACTION_POINTER_UP /
|
|
89
|
+
// pointer-index > 0) still resolve to the right action and never strand
|
|
90
|
+
// the drag state or the disallow-intercept flag.
|
|
91
|
+
when (event.actionMasked) {
|
|
89
92
|
MotionEvent.ACTION_DOWN -> {
|
|
90
93
|
isDragging = true
|
|
91
94
|
hasDragged = false
|
|
@@ -140,15 +143,18 @@ class HybridSegmentSlider(val context: ThemedReactContext) : HybridSegmentSlider
|
|
|
140
143
|
}
|
|
141
144
|
|
|
142
145
|
// MARK: - Props
|
|
143
|
-
|
|
146
|
+
// Guards the apply-once semantics of [defaultValue]: only the first prop
|
|
147
|
+
// commit seeds the initial value. After that the view is uncontrolled and JS
|
|
148
|
+
// drives it via the imperative [setValue] method.
|
|
149
|
+
private var didApplyDefault = false
|
|
150
|
+
|
|
151
|
+
override var defaultValue: Double = 0.0
|
|
144
152
|
get() = field
|
|
145
153
|
set(v) {
|
|
146
154
|
field = v
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
lastEmitted = v
|
|
151
|
-
view.invalidate()
|
|
155
|
+
if (!didApplyDefault) {
|
|
156
|
+
didApplyDefault = true
|
|
157
|
+
syncToValue(v)
|
|
152
158
|
}
|
|
153
159
|
}
|
|
154
160
|
|
|
@@ -189,10 +195,6 @@ class HybridSegmentSlider(val context: ThemedReactContext) : HybridSegmentSlider
|
|
|
189
195
|
get() = field
|
|
190
196
|
set(v) { field = v }
|
|
191
197
|
|
|
192
|
-
override var epoch: Double = 0.0
|
|
193
|
-
get() = field
|
|
194
|
-
set(v) { field = v }
|
|
195
|
-
|
|
196
198
|
override var fillColor: String = ""
|
|
197
199
|
get() = field
|
|
198
200
|
set(v) { field = v; cFill = parse(v); fillPaint.color = cFill; invalidateIfAlive() }
|
|
@@ -234,6 +236,18 @@ class HybridSegmentSlider(val context: ThemedReactContext) : HybridSegmentSlider
|
|
|
234
236
|
override var onSlideStart: (() -> Unit)? = null
|
|
235
237
|
override var onSlideComplete: (() -> Unit)? = null
|
|
236
238
|
|
|
239
|
+
// MARK: - Imperative methods
|
|
240
|
+
// Set the value from JS without a Fabric prop commit. Called on the JS
|
|
241
|
+
// thread, so hop to the UI thread before touching the view / drawing state
|
|
242
|
+
// (mirrors react-native-perp-depth-bar's imperative methods). Does NOT fire
|
|
243
|
+
// onChange — syncToValue updates lastEmitted so the caller's own value never
|
|
244
|
+
// echoes back.
|
|
245
|
+
override fun setValue(value: Double) {
|
|
246
|
+
view.post {
|
|
247
|
+
if (!isDisposed) syncToValue(value)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
237
251
|
private fun parse(v: String) = SegmentSliderColorParser.parse(v)
|
|
238
252
|
|
|
239
253
|
private fun invalidateIfAlive() {
|
|
@@ -269,6 +283,20 @@ class HybridSegmentSlider(val context: ThemedReactContext) : HybridSegmentSlider
|
|
|
269
283
|
return min + snappedFrac * (max - min)
|
|
270
284
|
}
|
|
271
285
|
|
|
286
|
+
/** Hard re-sync: snap the thumb to [v], overriding any in-flight drag. */
|
|
287
|
+
private fun syncToValue(v: Double) {
|
|
288
|
+
if (isDisposed) return
|
|
289
|
+
// An imperative setValue (or the initial defaultValue) wins over the
|
|
290
|
+
// current gesture: drop the drag so a queued ACTION_MOVE can't immediately
|
|
291
|
+
// re-overwrite the thumb, and clear the transient hover/halo so the snapped
|
|
292
|
+
// position renders clean.
|
|
293
|
+
isDragging = false
|
|
294
|
+
hoverMarkIndex = -1
|
|
295
|
+
currentValue = v
|
|
296
|
+
lastEmitted = v
|
|
297
|
+
view.invalidate()
|
|
298
|
+
}
|
|
299
|
+
|
|
272
300
|
private fun commitDragValue(raw: Double) {
|
|
273
301
|
val rounded = raw.coerceIn(min, max).let { Math.round(it).toDouble() }
|
|
274
302
|
currentValue = rounded
|
|
@@ -47,10 +47,26 @@ object SegmentSliderColorParser {
|
|
|
47
47
|
if (open < 0 || close < 0 || close <= open) return null
|
|
48
48
|
val parts = value.substring(open + 1, close).split(",").map { it.trim() }
|
|
49
49
|
if (parts.size < 3) return null
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
// A malformed channel degrades to gray rather than the invisible TRANSPARENT
|
|
51
|
+
// fallback: a wrong-but-visible element is far easier to notice and debug
|
|
52
|
+
// than one that silently disappears. Percentage forms (`rgb(50%, ...)`) are
|
|
53
|
+
// accepted and scaled to 0..255.
|
|
54
|
+
val r = parseRgbChannel(parts[0]) ?: return DEFAULT_VISIBLE
|
|
55
|
+
val g = parseRgbChannel(parts[1]) ?: return DEFAULT_VISIBLE
|
|
56
|
+
val b = parseRgbChannel(parts[2]) ?: return DEFAULT_VISIBLE
|
|
53
57
|
val a = if (parts.size >= 4) ((parts[3].toFloatOrNull() ?: 1f) * 255f).toInt() else 255
|
|
54
58
|
return Color.argb(a.coerceIn(0, 255), r.coerceIn(0, 255), g.coerceIn(0, 255), b.coerceIn(0, 255))
|
|
55
59
|
}
|
|
60
|
+
|
|
61
|
+
/** Parses an rgb() channel, supporting both `0..255` and `0%..100%` forms. */
|
|
62
|
+
private fun parseRgbChannel(part: String): Int? {
|
|
63
|
+
if (part.endsWith("%")) {
|
|
64
|
+
val pct = part.dropLast(1).trim().toFloatOrNull() ?: return null
|
|
65
|
+
return Math.round(pct / 100f * 255f)
|
|
66
|
+
}
|
|
67
|
+
return part.toFloatOrNull()?.toInt()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Opaque mid-gray: a conservative, always-visible stand-in for a bad rgb(). */
|
|
71
|
+
private val DEFAULT_VISIBLE = Color.argb(255, 128, 128, 128)
|
|
56
72
|
}
|
|
@@ -61,15 +61,15 @@ final class HybridSegmentSlider: HybridSegmentSliderSpec {
|
|
|
61
61
|
private lazy var haptic = UIImpactFeedbackGenerator(style: .light)
|
|
62
62
|
|
|
63
63
|
// MARK: - Props (required props are non-optional in the generated spec)
|
|
64
|
-
|
|
64
|
+
// Guards the apply-once semantics of `defaultValue`: only the first prop
|
|
65
|
+
// commit seeds the initial value. After that the view is uncontrolled and JS
|
|
66
|
+
// drives it via the imperative `setValue` method.
|
|
67
|
+
private var didApplyDefault = false
|
|
68
|
+
var defaultValue: Double = 0 {
|
|
65
69
|
didSet {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
currentValue = value
|
|
70
|
-
lastEmitted = value
|
|
71
|
-
applyVisual(value)
|
|
72
|
-
}
|
|
70
|
+
guard !didApplyDefault else { return }
|
|
71
|
+
didApplyDefault = true
|
|
72
|
+
syncToValue(defaultValue)
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
var min: Double = 0 { didSet { scheduleLayout() } }
|
|
@@ -86,7 +86,6 @@ final class HybridSegmentSlider: HybridSegmentSliderSpec {
|
|
|
86
86
|
var centerOrigin: Bool = false { didSet { scheduleLayout() } }
|
|
87
87
|
// Gates tap snapping only; no visual change on its own, so no didSet.
|
|
88
88
|
var snapTapToSegment: Bool = false
|
|
89
|
-
var epoch: Double = 0 { didSet { scheduleLayout() } }
|
|
90
89
|
|
|
91
90
|
var fillColor: String = "" {
|
|
92
91
|
didSet { cFill = parse(fillColor); fillLayer.backgroundColor = cFill; scheduleLayout() }
|
|
@@ -391,7 +390,7 @@ final class HybridSegmentSlider: HybridSegmentSliderSpec {
|
|
|
391
390
|
// Tap-snap mode: defer any value change until we know this is a tap or a
|
|
392
391
|
// drag, so a tap never jumps to the raw touch point first.
|
|
393
392
|
if !snapTapsActive {
|
|
394
|
-
|
|
393
|
+
commitDragValue(valueFromX(x))
|
|
395
394
|
}
|
|
396
395
|
}
|
|
397
396
|
|
|
@@ -403,7 +402,7 @@ final class HybridSegmentSlider: HybridSegmentSliderSpec {
|
|
|
403
402
|
}
|
|
404
403
|
// Still a tap candidate in snap mode → keep the thumb put.
|
|
405
404
|
if snapTapsActive, !hasDragged { return }
|
|
406
|
-
|
|
405
|
+
commitDragValue(valueFromX(x))
|
|
407
406
|
}
|
|
408
407
|
|
|
409
408
|
private func handleTouchEnded() {
|
|
@@ -416,7 +415,7 @@ final class HybridSegmentSlider: HybridSegmentSliderSpec {
|
|
|
416
415
|
if snapTapsActive, !hasDragged {
|
|
417
416
|
let pressDuration = CACurrentMediaTime() - touchStartTime
|
|
418
417
|
if pressDuration <= tapMaxDuration {
|
|
419
|
-
|
|
418
|
+
commitDragValue(snapValueToNearestMark(valueFromX(lastTouchX)))
|
|
420
419
|
}
|
|
421
420
|
}
|
|
422
421
|
hoverMarkIndex = -1
|
|
@@ -435,7 +434,22 @@ final class HybridSegmentSlider: HybridSegmentSliderSpec {
|
|
|
435
434
|
return min + snappedFrac * (max - min)
|
|
436
435
|
}
|
|
437
436
|
|
|
438
|
-
|
|
437
|
+
/// Hard re-sync: snap the thumb to `v`, overriding any in-flight drag. An
|
|
438
|
+
/// imperative `setValue` (or the initial `defaultValue`) wins over the current
|
|
439
|
+
/// gesture, so drop the drag (a queued touchesMoved can't then re-overwrite
|
|
440
|
+
/// the thumb) and clear the transient hover/halo before re-rendering.
|
|
441
|
+
private func syncToValue(_ v: Double) {
|
|
442
|
+
isDragging = false
|
|
443
|
+
if hoverMarkIndex != -1 {
|
|
444
|
+
hoverMarkIndex = -1
|
|
445
|
+
setHalo(visible: false, index: 0)
|
|
446
|
+
}
|
|
447
|
+
currentValue = v
|
|
448
|
+
lastEmitted = v
|
|
449
|
+
applyVisual(v)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
private func commitDragValue(_ raw: Double) {
|
|
439
453
|
let clamped = Swift.max(min, Swift.min(max, raw))
|
|
440
454
|
let rounded = clamped.rounded()
|
|
441
455
|
currentValue = rounded
|
|
@@ -446,6 +460,17 @@ final class HybridSegmentSlider: HybridSegmentSliderSpec {
|
|
|
446
460
|
}
|
|
447
461
|
}
|
|
448
462
|
|
|
463
|
+
// MARK: - Imperative methods
|
|
464
|
+
/// Set the value from JS without a Fabric prop commit. Called on the JS
|
|
465
|
+
/// thread, so hop to the main thread before touching the view / layers. Does
|
|
466
|
+
/// NOT fire `onChange` — `syncToValue` updates `lastEmitted` so the caller's
|
|
467
|
+
/// own value never echoes back.
|
|
468
|
+
func setValue(value: Double) throws {
|
|
469
|
+
DispatchQueue.main.async { [weak self] in
|
|
470
|
+
self?.syncToValue(value)
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
449
474
|
private func animateThumbScale(_ s: CGFloat) {
|
|
450
475
|
CATransaction.begin()
|
|
451
476
|
CATransaction.setAnimationDuration(0.12)
|
|
@@ -49,6 +49,10 @@ enum SegmentSliderColorParser {
|
|
|
49
49
|
return UIColor(red: r, green: g, blue: b, alpha: a)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/// Opaque mid-gray: a conservative, always-visible stand-in for a bad rgb().
|
|
53
|
+
private static let defaultVisible = UIColor(
|
|
54
|
+
red: 128 / 255.0, green: 128 / 255.0, blue: 128 / 255.0, alpha: 1)
|
|
55
|
+
|
|
52
56
|
private static func parseRGB(_ value: String) -> UIColor? {
|
|
53
57
|
guard let open = value.firstIndex(of: "("),
|
|
54
58
|
let close = value.firstIndex(of: ")") else { return nil }
|
|
@@ -56,17 +60,28 @@ enum SegmentSliderColorParser {
|
|
|
56
60
|
let parts = inner.split(separator: ",").map {
|
|
57
61
|
$0.trimmingCharacters(in: .whitespaces)
|
|
58
62
|
}
|
|
59
|
-
guard parts.count >= 3
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
guard parts.count >= 3 else { return nil }
|
|
64
|
+
// A malformed channel degrades to gray rather than the invisible `.clear`
|
|
65
|
+
// fallback: a wrong-but-visible element is far easier to notice and debug
|
|
66
|
+
// than one that silently disappears. Percentage forms (`rgb(50%, ...)`) are
|
|
67
|
+
// accepted and scaled to 0...1.
|
|
68
|
+
guard let r = channel(parts[0]),
|
|
69
|
+
let g = channel(parts[1]),
|
|
70
|
+
let b = channel(parts[2]) else { return defaultVisible }
|
|
63
71
|
let a = parts.count >= 4 ? (Double(parts[3]) ?? 1.0) : 1.0
|
|
64
72
|
return UIColor(
|
|
65
|
-
red: CGFloat(r)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: CGFloat(a))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// Parses an rgb() channel to 0...1, supporting `0...255` and `0%...100%`.
|
|
77
|
+
private static func channel(_ part: String) -> Double? {
|
|
78
|
+
if part.hasSuffix("%") {
|
|
79
|
+
guard let pct = Double(part.dropLast().trimmingCharacters(in: .whitespaces))
|
|
80
|
+
else { return nil }
|
|
81
|
+
return Swift.max(0, Swift.min(1, pct / 100.0))
|
|
82
|
+
}
|
|
83
|
+
guard let v = Double(part) else { return nil }
|
|
84
|
+
return Swift.max(0, Swift.min(1, v / 255.0))
|
|
70
85
|
}
|
|
71
86
|
}
|
|
72
87
|
|
|
@@ -149,4 +164,20 @@ final class SegmentSliderUIView: UIControl {
|
|
|
149
164
|
unlockAncestorGestures()
|
|
150
165
|
onTouchEnded?()
|
|
151
166
|
}
|
|
167
|
+
|
|
168
|
+
// If the view is detached mid-drag (e.g. JS unmounts it during a gesture),
|
|
169
|
+
// touchesEnded/Cancelled may never fire, which would leave the ancestors'
|
|
170
|
+
// pan recognizers permanently disabled — the scroll view and swipe-back would
|
|
171
|
+
// stay dead. Restore them on the way out of the window, and again on deinit
|
|
172
|
+
// as a final safety net.
|
|
173
|
+
override func willMove(toWindow newWindow: UIWindow?) {
|
|
174
|
+
super.willMove(toWindow: newWindow)
|
|
175
|
+
if newWindow == nil {
|
|
176
|
+
unlockAncestorGestures()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
deinit {
|
|
181
|
+
unlockAncestorGestures()
|
|
182
|
+
}
|
|
152
183
|
}
|
package/lib/module/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useRef } from 'react';
|
|
3
|
+
import { useCallback, useMemo, useRef } from 'react';
|
|
4
4
|
import { callback, getHostComponent } from 'react-native-nitro-modules';
|
|
5
5
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
6
|
const SegmentSliderConfig = require('../nitrogen/generated/shared/json/SegmentSliderConfig.json');
|
|
@@ -33,11 +33,14 @@ export function SegmentSliderView({
|
|
|
33
33
|
const stableOnSlideComplete = useCallback(() => {
|
|
34
34
|
onSlideCompleteRef.current?.();
|
|
35
35
|
}, []);
|
|
36
|
+
const onChangeCallback = useMemo(() => callback(stableOnChange), [stableOnChange]);
|
|
37
|
+
const onSlideStartCallback = useMemo(() => callback(stableOnSlideStart), [stableOnSlideStart]);
|
|
38
|
+
const onSlideCompleteCallback = useMemo(() => callback(stableOnSlideComplete), [stableOnSlideComplete]);
|
|
36
39
|
return /*#__PURE__*/_jsx(SegmentSliderHost, {
|
|
37
40
|
...props,
|
|
38
|
-
onChange: onChange ?
|
|
39
|
-
onSlideStart: onSlideStart ?
|
|
40
|
-
onSlideComplete: onSlideComplete ?
|
|
41
|
+
onChange: onChange ? onChangeCallback : undefined,
|
|
42
|
+
onSlideStart: onSlideStart ? onSlideStartCallback : undefined,
|
|
43
|
+
onSlideComplete: onSlideComplete ? onSlideCompleteCallback : undefined
|
|
41
44
|
});
|
|
42
45
|
}
|
|
43
46
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useCallback","useRef","callback","getHostComponent","jsx","_jsx","SegmentSliderConfig","require","SegmentSliderHost","SegmentSliderView","onChange","onSlideStart","onSlideComplete","props","onChangeRef","current","onSlideStartRef","onSlideCompleteRef","stableOnChange","value","stableOnSlideStart","stableOnSlideComplete","undefined"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,WAAW,EAAEC,MAAM,QAAQ,OAAO;
|
|
1
|
+
{"version":3,"names":["useCallback","useMemo","useRef","callback","getHostComponent","jsx","_jsx","SegmentSliderConfig","require","SegmentSliderHost","SegmentSliderView","onChange","onSlideStart","onSlideComplete","props","onChangeRef","current","onSlideStartRef","onSlideCompleteRef","stableOnChange","value","stableOnSlideStart","stableOnSlideComplete","onChangeCallback","onSlideStartCallback","onSlideCompleteCallback","undefined"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,WAAW,EAAEC,OAAO,EAAEC,MAAM,QAAQ,OAAO;AAGpD,SAASC,QAAQ,EAAEC,gBAAgB,QAAQ,4BAA4B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAOxE,MAAMC,mBAAmB,GAAGC,OAAO,CAAC,4DAA4D,CAAC;AAIjG,MAAMC,iBAAiB,GAAGL,gBAAgB,CAGxC,eAAe,EAAE,MAAMG,mBAAmB,CAAC;;AAE7C;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASG,iBAAiBA,CAAC;EAChCC,QAAQ;EACRC,YAAY;EACZC,eAAe;EACf,GAAGC;AAC2B,CAAC,EAAE;EACjC,MAAMC,WAAW,GAAGb,MAAM,CAACS,QAAQ,CAAC;EACpCI,WAAW,CAACC,OAAO,GAAGL,QAAQ;EAC9B,MAAMM,eAAe,GAAGf,MAAM,CAACU,YAAY,CAAC;EAC5CK,eAAe,CAACD,OAAO,GAAGJ,YAAY;EACtC,MAAMM,kBAAkB,GAAGhB,MAAM,CAACW,eAAe,CAAC;EAClDK,kBAAkB,CAACF,OAAO,GAAGH,eAAe;EAE5C,MAAMM,cAAc,GAAGnB,WAAW,CAAEoB,KAAa,IAAK;IACpDL,WAAW,CAACC,OAAO,GAAGI,KAAK,CAAC;EAC9B,CAAC,EAAE,EAAE,CAAC;EACN,MAAMC,kBAAkB,GAAGrB,WAAW,CAAC,MAAM;IAC3CiB,eAAe,CAACD,OAAO,GAAG,CAAC;EAC7B,CAAC,EAAE,EAAE,CAAC;EACN,MAAMM,qBAAqB,GAAGtB,WAAW,CAAC,MAAM;IAC9CkB,kBAAkB,CAACF,OAAO,GAAG,CAAC;EAChC,CAAC,EAAE,EAAE,CAAC;EACN,MAAMO,gBAAgB,GAAGtB,OAAO,CAC9B,MAAME,QAAQ,CAACgB,cAAc,CAAC,EAC9B,CAACA,cAAc,CACjB,CAAC;EACD,MAAMK,oBAAoB,GAAGvB,OAAO,CAClC,MAAME,QAAQ,CAACkB,kBAAkB,CAAC,EAClC,CAACA,kBAAkB,CACrB,CAAC;EACD,MAAMI,uBAAuB,GAAGxB,OAAO,CACrC,MAAME,QAAQ,CAACmB,qBAAqB,CAAC,EACrC,CAACA,qBAAqB,CACxB,CAAC;EAED,oBACEhB,IAAA,CAACG,iBAAiB;IAAA,GACZK,KAAK;IACTH,QAAQ,EAAEA,QAAQ,GAAGY,gBAAgB,GAAGG,SAAU;IAClDd,YAAY,EAAEA,YAAY,GAAGY,oBAAoB,GAAGE,SAAU;IAC9Db,eAAe,EAAEA,eAAe,GAAGY,uBAAuB,GAAGC;EAAU,CACxE,CAAC;AAEN","ignoreList":[]}
|
|
@@ -45,14 +45,14 @@ namespace margelo::nitro::segmentslider {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// Properties
|
|
48
|
-
double JHybridSegmentSliderSpec::
|
|
49
|
-
static const auto method = javaClassStatic()->getMethod<double()>("
|
|
48
|
+
double JHybridSegmentSliderSpec::getDefaultValue() {
|
|
49
|
+
static const auto method = javaClassStatic()->getMethod<double()>("getDefaultValue");
|
|
50
50
|
auto __result = method(_javaPart);
|
|
51
51
|
return __result;
|
|
52
52
|
}
|
|
53
|
-
void JHybridSegmentSliderSpec::
|
|
54
|
-
static const auto method = javaClassStatic()->getMethod<void(double /*
|
|
55
|
-
method(_javaPart,
|
|
53
|
+
void JHybridSegmentSliderSpec::setDefaultValue(double defaultValue) {
|
|
54
|
+
static const auto method = javaClassStatic()->getMethod<void(double /* defaultValue */)>("setDefaultValue");
|
|
55
|
+
method(_javaPart, defaultValue);
|
|
56
56
|
}
|
|
57
57
|
double JHybridSegmentSliderSpec::getMin() {
|
|
58
58
|
static const auto method = javaClassStatic()->getMethod<double()>("getMin");
|
|
@@ -126,15 +126,6 @@ namespace margelo::nitro::segmentslider {
|
|
|
126
126
|
static const auto method = javaClassStatic()->getMethod<void(jboolean /* snapTapToSegment */)>("setSnapTapToSegment");
|
|
127
127
|
method(_javaPart, snapTapToSegment);
|
|
128
128
|
}
|
|
129
|
-
double JHybridSegmentSliderSpec::getEpoch() {
|
|
130
|
-
static const auto method = javaClassStatic()->getMethod<double()>("getEpoch");
|
|
131
|
-
auto __result = method(_javaPart);
|
|
132
|
-
return __result;
|
|
133
|
-
}
|
|
134
|
-
void JHybridSegmentSliderSpec::setEpoch(double epoch) {
|
|
135
|
-
static const auto method = javaClassStatic()->getMethod<void(double /* epoch */)>("setEpoch");
|
|
136
|
-
method(_javaPart, epoch);
|
|
137
|
-
}
|
|
138
129
|
std::string JHybridSegmentSliderSpec::getFillColor() {
|
|
139
130
|
static const auto method = javaClassStatic()->getMethod<jni::local_ref<jni::JString>()>("getFillColor");
|
|
140
131
|
auto __result = method(_javaPart);
|
|
@@ -269,6 +260,9 @@ namespace margelo::nitro::segmentslider {
|
|
|
269
260
|
}
|
|
270
261
|
|
|
271
262
|
// Methods
|
|
272
|
-
|
|
263
|
+
void JHybridSegmentSliderSpec::setValue(double value) {
|
|
264
|
+
static const auto method = javaClassStatic()->getMethod<void(double /* value */)>("setValue");
|
|
265
|
+
method(_javaPart, value);
|
|
266
|
+
}
|
|
273
267
|
|
|
274
268
|
} // namespace margelo::nitro::segmentslider
|
|
@@ -50,8 +50,8 @@ namespace margelo::nitro::segmentslider {
|
|
|
50
50
|
|
|
51
51
|
public:
|
|
52
52
|
// Properties
|
|
53
|
-
double
|
|
54
|
-
void
|
|
53
|
+
double getDefaultValue() override;
|
|
54
|
+
void setDefaultValue(double defaultValue) override;
|
|
55
55
|
double getMin() override;
|
|
56
56
|
void setMin(double min) override;
|
|
57
57
|
double getMax() override;
|
|
@@ -68,8 +68,6 @@ namespace margelo::nitro::segmentslider {
|
|
|
68
68
|
void setCenterOrigin(bool centerOrigin) override;
|
|
69
69
|
bool getSnapTapToSegment() override;
|
|
70
70
|
void setSnapTapToSegment(bool snapTapToSegment) override;
|
|
71
|
-
double getEpoch() override;
|
|
72
|
-
void setEpoch(double epoch) override;
|
|
73
71
|
std::string getFillColor() override;
|
|
74
72
|
void setFillColor(const std::string& fillColor) override;
|
|
75
73
|
std::string getTrackColor() override;
|
|
@@ -97,7 +95,7 @@ namespace margelo::nitro::segmentslider {
|
|
|
97
95
|
|
|
98
96
|
public:
|
|
99
97
|
// Methods
|
|
100
|
-
|
|
98
|
+
void setValue(double value) override;
|
|
101
99
|
|
|
102
100
|
private:
|
|
103
101
|
friend HybridBase;
|
|
@@ -36,8 +36,8 @@ void JHybridSegmentSliderStateUpdater::updateViewProps(jni::alias_ref<jni::JClas
|
|
|
36
36
|
throw std::runtime_error("HybridSegmentSliderState's data doesn't contain any props!");
|
|
37
37
|
}
|
|
38
38
|
const HybridSegmentSliderProps& props = maybeProps.value();
|
|
39
|
-
if (props.
|
|
40
|
-
view->
|
|
39
|
+
if (props.defaultValue.isDirty) {
|
|
40
|
+
view->setDefaultValue(props.defaultValue.value);
|
|
41
41
|
// TODO: Set isDirty = false
|
|
42
42
|
}
|
|
43
43
|
if (props.min.isDirty) {
|
|
@@ -72,10 +72,6 @@ void JHybridSegmentSliderStateUpdater::updateViewProps(jni::alias_ref<jni::JClas
|
|
|
72
72
|
view->setSnapTapToSegment(props.snapTapToSegment.value);
|
|
73
73
|
// TODO: Set isDirty = false
|
|
74
74
|
}
|
|
75
|
-
if (props.epoch.isDirty) {
|
|
76
|
-
view->setEpoch(props.epoch.value);
|
|
77
|
-
// TODO: Set isDirty = false
|
|
78
|
-
}
|
|
79
75
|
if (props.fillColor.isDirty) {
|
|
80
76
|
view->setFillColor(props.fillColor.value);
|
|
81
77
|
// TODO: Set isDirty = false
|
|
@@ -46,7 +46,7 @@ abstract class HybridSegmentSliderSpec: HybridView() {
|
|
|
46
46
|
@get:Keep
|
|
47
47
|
@set:DoNotStrip
|
|
48
48
|
@set:Keep
|
|
49
|
-
abstract var
|
|
49
|
+
abstract var defaultValue: Double
|
|
50
50
|
|
|
51
51
|
@get:DoNotStrip
|
|
52
52
|
@get:Keep
|
|
@@ -96,12 +96,6 @@ abstract class HybridSegmentSliderSpec: HybridView() {
|
|
|
96
96
|
@set:Keep
|
|
97
97
|
abstract var snapTapToSegment: Boolean
|
|
98
98
|
|
|
99
|
-
@get:DoNotStrip
|
|
100
|
-
@get:Keep
|
|
101
|
-
@set:DoNotStrip
|
|
102
|
-
@set:Keep
|
|
103
|
-
abstract var epoch: Double
|
|
104
|
-
|
|
105
99
|
@get:DoNotStrip
|
|
106
100
|
@get:Keep
|
|
107
101
|
@set:DoNotStrip
|
|
@@ -199,7 +193,9 @@ abstract class HybridSegmentSliderSpec: HybridView() {
|
|
|
199
193
|
}
|
|
200
194
|
|
|
201
195
|
// Methods
|
|
202
|
-
|
|
196
|
+
@DoNotStrip
|
|
197
|
+
@Keep
|
|
198
|
+
abstract fun setValue(value: Double): Unit
|
|
203
199
|
|
|
204
200
|
private external fun initHybrid(): HybridData
|
|
205
201
|
|
|
@@ -17,6 +17,8 @@ namespace SegmentSlider { class HybridSegmentSliderSpec_cxx; }
|
|
|
17
17
|
|
|
18
18
|
// Include C++ defined types
|
|
19
19
|
#include "HybridSegmentSliderSpec.hpp"
|
|
20
|
+
#include <NitroModules/Result.hpp>
|
|
21
|
+
#include <exception>
|
|
20
22
|
#include <functional>
|
|
21
23
|
#include <memory>
|
|
22
24
|
#include <optional>
|
|
@@ -112,5 +114,14 @@ namespace margelo::nitro::segmentslider::bridge::swift {
|
|
|
112
114
|
// pragma MARK: std::weak_ptr<HybridSegmentSliderSpec>
|
|
113
115
|
using std__weak_ptr_HybridSegmentSliderSpec_ = std::weak_ptr<HybridSegmentSliderSpec>;
|
|
114
116
|
inline std__weak_ptr_HybridSegmentSliderSpec_ weakify_std__shared_ptr_HybridSegmentSliderSpec_(const std::shared_ptr<HybridSegmentSliderSpec>& strong) noexcept { return strong; }
|
|
117
|
+
|
|
118
|
+
// pragma MARK: Result<void>
|
|
119
|
+
using Result_void_ = Result<void>;
|
|
120
|
+
inline Result_void_ create_Result_void_() noexcept {
|
|
121
|
+
return Result<void>::withValue();
|
|
122
|
+
}
|
|
123
|
+
inline Result_void_ create_Result_void_(const std::exception_ptr& error) noexcept {
|
|
124
|
+
return Result<void>::withError(error);
|
|
125
|
+
}
|
|
115
126
|
|
|
116
127
|
} // namespace margelo::nitro::segmentslider::bridge::swift
|
|
@@ -13,6 +13,8 @@ namespace margelo::nitro::segmentslider { class HybridSegmentSliderSpec; }
|
|
|
13
13
|
|
|
14
14
|
// Include C++ defined types
|
|
15
15
|
#include "HybridSegmentSliderSpec.hpp"
|
|
16
|
+
#include <NitroModules/Result.hpp>
|
|
17
|
+
#include <exception>
|
|
16
18
|
#include <functional>
|
|
17
19
|
#include <memory>
|
|
18
20
|
#include <optional>
|
|
@@ -58,11 +58,11 @@ namespace margelo::nitro::segmentslider {
|
|
|
58
58
|
|
|
59
59
|
public:
|
|
60
60
|
// Properties
|
|
61
|
-
inline double
|
|
62
|
-
return _swiftPart.
|
|
61
|
+
inline double getDefaultValue() noexcept override {
|
|
62
|
+
return _swiftPart.getDefaultValue();
|
|
63
63
|
}
|
|
64
|
-
inline void
|
|
65
|
-
_swiftPart.
|
|
64
|
+
inline void setDefaultValue(double defaultValue) noexcept override {
|
|
65
|
+
_swiftPart.setDefaultValue(std::forward<decltype(defaultValue)>(defaultValue));
|
|
66
66
|
}
|
|
67
67
|
inline double getMin() noexcept override {
|
|
68
68
|
return _swiftPart.getMin();
|
|
@@ -112,12 +112,6 @@ namespace margelo::nitro::segmentslider {
|
|
|
112
112
|
inline void setSnapTapToSegment(bool snapTapToSegment) noexcept override {
|
|
113
113
|
_swiftPart.setSnapTapToSegment(std::forward<decltype(snapTapToSegment)>(snapTapToSegment));
|
|
114
114
|
}
|
|
115
|
-
inline double getEpoch() noexcept override {
|
|
116
|
-
return _swiftPart.getEpoch();
|
|
117
|
-
}
|
|
118
|
-
inline void setEpoch(double epoch) noexcept override {
|
|
119
|
-
_swiftPart.setEpoch(std::forward<decltype(epoch)>(epoch));
|
|
120
|
-
}
|
|
121
115
|
inline std::string getFillColor() noexcept override {
|
|
122
116
|
auto __result = _swiftPart.getFillColor();
|
|
123
117
|
return __result;
|
|
@@ -205,7 +199,12 @@ namespace margelo::nitro::segmentslider {
|
|
|
205
199
|
|
|
206
200
|
public:
|
|
207
201
|
// Methods
|
|
208
|
-
|
|
202
|
+
inline void setValue(double value) override {
|
|
203
|
+
auto __result = _swiftPart.setValue(std::forward<decltype(value)>(value));
|
|
204
|
+
if (__result.hasError()) [[unlikely]] {
|
|
205
|
+
std::rethrow_exception(__result.error());
|
|
206
|
+
}
|
|
207
|
+
}
|
|
209
208
|
|
|
210
209
|
private:
|
|
211
210
|
SegmentSlider::HybridSegmentSliderSpec_cxx _swiftPart;
|
|
@@ -71,10 +71,10 @@ using namespace margelo::nitro::segmentslider::views;
|
|
|
71
71
|
// 2. Update each prop individually
|
|
72
72
|
swiftPart.beforeUpdate();
|
|
73
73
|
|
|
74
|
-
//
|
|
75
|
-
if (newViewProps.
|
|
76
|
-
swiftPart.
|
|
77
|
-
newViewProps.
|
|
74
|
+
// defaultValue: number
|
|
75
|
+
if (newViewProps.defaultValue.isDirty) {
|
|
76
|
+
swiftPart.setDefaultValue(newViewProps.defaultValue.value);
|
|
77
|
+
newViewProps.defaultValue.isDirty = false;
|
|
78
78
|
}
|
|
79
79
|
// min: number
|
|
80
80
|
if (newViewProps.min.isDirty) {
|
|
@@ -116,11 +116,6 @@ using namespace margelo::nitro::segmentslider::views;
|
|
|
116
116
|
swiftPart.setSnapTapToSegment(newViewProps.snapTapToSegment.value);
|
|
117
117
|
newViewProps.snapTapToSegment.isDirty = false;
|
|
118
118
|
}
|
|
119
|
-
// epoch: number
|
|
120
|
-
if (newViewProps.epoch.isDirty) {
|
|
121
|
-
swiftPart.setEpoch(newViewProps.epoch.value);
|
|
122
|
-
newViewProps.epoch.isDirty = false;
|
|
123
|
-
}
|
|
124
119
|
// fillColor: string
|
|
125
120
|
if (newViewProps.fillColor.isDirty) {
|
|
126
121
|
swiftPart.setFillColor(newViewProps.fillColor.value);
|
|
@@ -11,7 +11,7 @@ import NitroModules
|
|
|
11
11
|
/// See ``HybridSegmentSliderSpec``
|
|
12
12
|
public protocol HybridSegmentSliderSpec_protocol: HybridObject, HybridView {
|
|
13
13
|
// Properties
|
|
14
|
-
var
|
|
14
|
+
var defaultValue: Double { get set }
|
|
15
15
|
var min: Double { get set }
|
|
16
16
|
var max: Double { get set }
|
|
17
17
|
var segments: Double { get set }
|
|
@@ -20,7 +20,6 @@ public protocol HybridSegmentSliderSpec_protocol: HybridObject, HybridView {
|
|
|
20
20
|
var showBubble: Bool { get set }
|
|
21
21
|
var centerOrigin: Bool { get set }
|
|
22
22
|
var snapTapToSegment: Bool { get set }
|
|
23
|
-
var epoch: Double { get set }
|
|
24
23
|
var fillColor: String { get set }
|
|
25
24
|
var trackColor: String { get set }
|
|
26
25
|
var thumbColor: String { get set }
|
|
@@ -35,7 +34,7 @@ public protocol HybridSegmentSliderSpec_protocol: HybridObject, HybridView {
|
|
|
35
34
|
var onSlideComplete: (() -> Void)? { get set }
|
|
36
35
|
|
|
37
36
|
// Methods
|
|
38
|
-
|
|
37
|
+
func setValue(value: Double) throws -> Void
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
public extension HybridSegmentSliderSpec_protocol {
|