@lodev09/react-native-true-sheet 4.0.0-beta.10 → 4.0.0-beta.12
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/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +10 -13
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +79 -24
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +24 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +4 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +3 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +2 -3
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +3 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +4 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +2 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +2 -2
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +3 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +3 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +4 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +3 -7
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +3 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +4 -5
- package/ios/TrueSheetContentView.mm +27 -21
- package/package.json +2 -2
|
@@ -14,6 +14,7 @@ import com.facebook.react.uimanager.ThemedReactContext
|
|
|
14
14
|
import com.facebook.react.views.view.ReactViewGroup
|
|
15
15
|
import com.lodev09.truesheet.core.TrueSheetKeyboardObserver
|
|
16
16
|
import com.lodev09.truesheet.core.TrueSheetKeyboardObserverDelegate
|
|
17
|
+
import com.lodev09.truesheet.utils.ScreenUtils
|
|
17
18
|
import com.lodev09.truesheet.utils.isDescendantOf
|
|
18
19
|
import com.lodev09.truesheet.utils.smoothScrollTo
|
|
19
20
|
|
|
@@ -123,7 +124,6 @@ class TrueSheetContentView(private val reactContext: ThemedReactContext) : React
|
|
|
123
124
|
|
|
124
125
|
private val scrollableLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
|
|
125
126
|
updateContentInset()
|
|
126
|
-
clampScrollPosition()
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
private val scrollContentLayoutListener = View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
|
@@ -198,12 +198,6 @@ class TrueSheetContentView(private val reactContext: ThemedReactContext) : React
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
updateContentInset()
|
|
201
|
-
|
|
202
|
-
// If keyboard is currently showing, re-apply the keyboard inset to the new ScrollView
|
|
203
|
-
val keyboardHeight = keyboardObserver?.currentHeight ?: 0
|
|
204
|
-
if (keyboardHeight > 0) {
|
|
205
|
-
updateScrollViewInsetForKeyboard(keyboardHeight)
|
|
206
|
-
}
|
|
207
201
|
}
|
|
208
202
|
|
|
209
203
|
/**
|
|
@@ -221,7 +215,7 @@ class TrueSheetContentView(private val reactContext: ThemedReactContext) : React
|
|
|
221
215
|
0
|
|
222
216
|
}
|
|
223
217
|
|
|
224
|
-
|
|
218
|
+
updateScrollViewInsetForKeyboard(keyboardObserver?.currentHeight ?: 0)
|
|
225
219
|
}
|
|
226
220
|
|
|
227
221
|
// Fabric's measured height excludes the native inset, avoiding feedback.
|
|
@@ -339,12 +333,15 @@ class TrueSheetContentView(private val reactContext: ThemedReactContext) : React
|
|
|
339
333
|
}
|
|
340
334
|
|
|
341
335
|
private fun updateScrollViewInsetForKeyboard(keyboardHeight: Int) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
//
|
|
345
|
-
//
|
|
336
|
+
val scrollView = detectedScrollView ?: return
|
|
337
|
+
|
|
338
|
+
// Short or nested scroll views can end above the sheet's bottom edge.
|
|
339
|
+
// Their position also accounts for space occupied by a relative footer.
|
|
346
340
|
keyboardBottomInset = if (keyboardHeight > 0) {
|
|
347
|
-
val
|
|
341
|
+
val location = IntArray(2)
|
|
342
|
+
scrollView.getLocationInWindow(location)
|
|
343
|
+
val keyboardTop = ScreenUtils.getRealScreenHeight(reactContext) - keyboardHeight
|
|
344
|
+
val baseInset = maxOf(0, location[1] + scrollView.height - keyboardTop)
|
|
348
345
|
val adjustedInset = maxOf(0, baseInset + keyboardOffset.toInt())
|
|
349
346
|
appliedKeyboardOffset = adjustedInset - baseInset
|
|
350
347
|
adjustedInset
|
package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp
CHANGED
|
@@ -1,35 +1,70 @@
|
|
|
1
1
|
#include "TrueSheetContentViewShadowNode.h"
|
|
2
2
|
|
|
3
|
-
#include <
|
|
4
|
-
|
|
3
|
+
#include <folly/ScopeGuard.h>
|
|
5
4
|
#include <react/renderer/components/view/conversions.h>
|
|
5
|
+
#include <react/renderer/core/ComponentDescriptor.h>
|
|
6
6
|
#include <react/renderer/core/LayoutConstraints.h>
|
|
7
7
|
#include <react/renderer/core/LayoutContext.h>
|
|
8
8
|
|
|
9
|
+
#include <limits>
|
|
10
|
+
|
|
9
11
|
namespace facebook::react {
|
|
10
12
|
|
|
11
13
|
using namespace yoga;
|
|
12
14
|
|
|
13
15
|
extern const char TrueSheetContentViewComponentName[] = "TrueSheetContentView";
|
|
14
16
|
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
+
// The measurement pass re-enters layout() on a clone — guard so it doesn't
|
|
18
|
+
// measure again recursively.
|
|
17
19
|
static thread_local bool gIsMeasuringNaturalHeight = false;
|
|
18
20
|
|
|
21
|
+
TrueSheetContentViewShadowNode::TrueSheetContentViewShadowNode(
|
|
22
|
+
const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment)
|
|
23
|
+
: ConcreteViewShadowNode(sourceShadowNode, fragment),
|
|
24
|
+
measurement_(static_cast<const TrueSheetContentViewShadowNode &>(sourceShadowNode).measurement_),
|
|
25
|
+
measurementSourceChildren_(
|
|
26
|
+
static_cast<const TrueSheetContentViewShadowNode &>(sourceShadowNode).measurementSourceChildren_),
|
|
27
|
+
contentChanged_(static_cast<const TrueSheetContentViewShadowNode &>(sourceShadowNode).contentChanged_ ||
|
|
28
|
+
fragment.props || fragment.children) {
|
|
29
|
+
}
|
|
30
|
+
|
|
19
31
|
void TrueSheetContentViewShadowNode::layout(LayoutContext layoutContext) {
|
|
32
|
+
// The sizing tree needs Yoga's result, not Fabric state updates or events.
|
|
33
|
+
if (gIsMeasuringNaturalHeight) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
20
36
|
ConcreteViewShadowNode::layout(layoutContext);
|
|
21
37
|
updateNaturalHeightIfNeeded(layoutContext);
|
|
22
38
|
}
|
|
23
39
|
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
// Every descendant must be detached from React's runtime references before
|
|
41
|
+
// Yoga clones it during measurement. Disabling transfer only on the root
|
|
42
|
+
// still lets descendant clones replace React's live nodes. Reuse unchanged
|
|
43
|
+
// measurement subtrees; Yoga owns copy-on-write when their layout changes.
|
|
44
|
+
std::shared_ptr<ShadowNode> TrueSheetContentViewShadowNode::cloneForMeasurement(
|
|
45
|
+
const ShadowNode &node, const Children &previousSourceChildren, const Children &previousMeasurementChildren) {
|
|
46
|
+
auto children = std::make_shared<Children>();
|
|
47
|
+
children->reserve(node.getChildren().size());
|
|
48
|
+
for (size_t index = 0; index < node.getChildren().size(); index++) {
|
|
49
|
+
const auto &child = node.getChildren()[index];
|
|
50
|
+
if (index < previousSourceChildren.size() && ShadowNode::sameFamily(*child, *previousSourceChildren[index])) {
|
|
51
|
+
const auto &previousSource = previousSourceChildren[index];
|
|
52
|
+
const auto &previousMeasurement = previousMeasurementChildren[index];
|
|
53
|
+
children->push_back(child == previousSource ? previousMeasurement
|
|
54
|
+
: cloneForMeasurement(*child, previousSource->getChildren(),
|
|
55
|
+
previousMeasurement->getChildren()));
|
|
56
|
+
} else {
|
|
57
|
+
children->push_back(cloneForMeasurement(*child, {}, {}));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
auto clone = node.getComponentDescriptor().cloneShadowNode(
|
|
62
|
+
node, {.children = children, .state = node.getState(), .runtimeShadowNodeReference = false});
|
|
63
|
+
if (auto content = dynamic_cast<TrueSheetContentViewShadowNode *>(clone.get())) {
|
|
64
|
+
content->measurement_.reset();
|
|
65
|
+
content->measurementSourceChildren_.reset();
|
|
66
|
+
}
|
|
67
|
+
return clone;
|
|
33
68
|
}
|
|
34
69
|
|
|
35
70
|
// The natural height is the height the content wants when unbounded — the
|
|
@@ -38,26 +73,46 @@ static bool isHeightContainerDerived(const yoga::Style &style) {
|
|
|
38
73
|
// subtree with an unconstrained height instead. Yoga respects the user's
|
|
39
74
|
// styles: an explicit-height ScrollView keeps its height while a flexible one
|
|
40
75
|
// expands to its content — no ScrollView discovery involved.
|
|
41
|
-
void TrueSheetContentViewShadowNode::updateNaturalHeightIfNeeded(
|
|
42
|
-
const LayoutContext &layoutContext) {
|
|
43
|
-
if (gIsMeasuringNaturalHeight) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
76
|
+
void TrueSheetContentViewShadowNode::updateNaturalHeightIfNeeded(const LayoutContext &layoutContext) {
|
|
47
77
|
auto stateData = getStateData();
|
|
48
78
|
auto size = getLayoutMetrics().frame.size;
|
|
49
79
|
|
|
50
80
|
Float naturalHeight = size.height;
|
|
51
|
-
|
|
81
|
+
// Auto-height content can also be capped by a shrinking ScrollView. Only
|
|
82
|
+
// a fixed, non-flexible height can be taken from the viewport layout.
|
|
83
|
+
if (yogaNode_.isNodeFlexible() || !getConcreteProps().yogaStyle.dimension(Dimension::Height).isPoints()) {
|
|
52
84
|
auto constraints = LayoutConstraints{};
|
|
53
85
|
constraints.minimumSize = {size.width, 0};
|
|
54
86
|
constraints.maximumSize = {size.width, std::numeric_limits<Float>::infinity()};
|
|
55
87
|
constraints.layoutDirection = getLayoutMetrics().layoutDirection;
|
|
56
88
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
89
|
+
auto measurementContext = layoutContext;
|
|
90
|
+
measurementContext.affectedNodes = nullptr;
|
|
91
|
+
auto errata = YGConfigGetErrata(&yogaConfig_);
|
|
92
|
+
|
|
93
|
+
// Yoga's viewport-only clones carry no new props or children. Reuse the
|
|
94
|
+
// intrinsic height across those layouts instead of measuring each drag frame.
|
|
95
|
+
if (contentChanged_ || !measurement_ || !(measurement_->constraints == constraints) ||
|
|
96
|
+
!(measurement_->context == measurementContext) || measurement_->errata != errata) {
|
|
97
|
+
gIsMeasuringNaturalHeight = true;
|
|
98
|
+
auto restoreMeasurement = folly::makeGuard([] { gIsMeasuringNaturalHeight = false; });
|
|
99
|
+
auto measurementNode =
|
|
100
|
+
measurement_ ? cloneForMeasurement(*this, *measurementSourceChildren_, measurement_->root->getChildren())
|
|
101
|
+
: cloneForMeasurement(*this, {}, {});
|
|
102
|
+
auto &measurement = static_cast<LayoutableShadowNode &>(*measurementNode);
|
|
103
|
+
measurement.layoutTree(measurementContext, constraints);
|
|
104
|
+
measurement_ = std::make_shared<const Measurement>(Measurement{.root = measurementNode,
|
|
105
|
+
.constraints = constraints,
|
|
106
|
+
.context = measurementContext,
|
|
107
|
+
.errata = errata,
|
|
108
|
+
.height = measurement.getLayoutMetrics().frame.size.height});
|
|
109
|
+
}
|
|
110
|
+
naturalHeight = measurement_->height;
|
|
111
|
+
} else {
|
|
112
|
+
measurement_.reset();
|
|
60
113
|
}
|
|
114
|
+
measurementSourceChildren_ = children_;
|
|
115
|
+
contentChanged_ = false;
|
|
61
116
|
|
|
62
117
|
if (stateData.naturalHeight != naturalHeight) {
|
|
63
118
|
stateData.naturalHeight = naturalHeight;
|
|
@@ -65,4 +120,4 @@ void TrueSheetContentViewShadowNode::updateNaturalHeightIfNeeded(
|
|
|
65
120
|
}
|
|
66
121
|
}
|
|
67
122
|
|
|
68
|
-
}
|
|
123
|
+
} // namespace facebook::react
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
#include <react/renderer/components/TrueSheetSpec/Props.h>
|
|
6
6
|
#include <react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h>
|
|
7
7
|
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
8
|
+
#include <react/renderer/core/LayoutConstraints.h>
|
|
9
|
+
#include <react/renderer/core/LayoutContext.h>
|
|
8
10
|
|
|
9
11
|
namespace facebook::react {
|
|
10
12
|
|
|
@@ -14,20 +16,36 @@ JSI_EXPORT extern const char TrueSheetContentViewComponentName[];
|
|
|
14
16
|
* `ShadowNode` for <TrueSheetContentView> component.
|
|
15
17
|
*/
|
|
16
18
|
class JSI_EXPORT TrueSheetContentViewShadowNode final
|
|
17
|
-
: public ConcreteViewShadowNode<
|
|
18
|
-
|
|
19
|
-
TrueSheetContentViewProps,
|
|
20
|
-
TrueSheetContentViewEventEmitter,
|
|
21
|
-
TrueSheetContentViewState> {
|
|
19
|
+
: public ConcreteViewShadowNode<TrueSheetContentViewComponentName, TrueSheetContentViewProps,
|
|
20
|
+
TrueSheetContentViewEventEmitter, TrueSheetContentViewState> {
|
|
22
21
|
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
|
23
22
|
|
|
24
23
|
public:
|
|
24
|
+
TrueSheetContentViewShadowNode(const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment);
|
|
25
|
+
|
|
25
26
|
#pragma mark - LayoutableShadowNode
|
|
26
27
|
|
|
27
28
|
void layout(LayoutContext layoutContext) override;
|
|
28
29
|
|
|
29
30
|
private:
|
|
31
|
+
using Children = std::vector<std::shared_ptr<const ShadowNode>>;
|
|
32
|
+
|
|
33
|
+
struct Measurement {
|
|
34
|
+
std::shared_ptr<const ShadowNode> root;
|
|
35
|
+
LayoutConstraints constraints;
|
|
36
|
+
LayoutContext context;
|
|
37
|
+
YGErrata errata;
|
|
38
|
+
Float height;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
std::shared_ptr<const Measurement> measurement_;
|
|
42
|
+
std::shared_ptr<const Children> measurementSourceChildren_;
|
|
43
|
+
bool contentChanged_{true};
|
|
44
|
+
|
|
45
|
+
static std::shared_ptr<ShadowNode> cloneForMeasurement(
|
|
46
|
+
const ShadowNode &node, const Children &previousSourceChildren, const Children &previousMeasurementChildren);
|
|
47
|
+
|
|
30
48
|
void updateNaturalHeightIfNeeded(const LayoutContext &layoutContext);
|
|
31
49
|
};
|
|
32
50
|
|
|
33
|
-
}
|
|
51
|
+
} // namespace facebook::react
|
|
@@ -20,10 +20,9 @@ class TrueSheetContentViewState final {
|
|
|
20
20
|
TrueSheetContentViewState() = default;
|
|
21
21
|
|
|
22
22
|
#ifdef ANDROID
|
|
23
|
-
TrueSheetContentViewState(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
: naturalHeight(previousState.naturalHeight) {}
|
|
23
|
+
TrueSheetContentViewState(TrueSheetContentViewState const &previousState, folly::dynamic data)
|
|
24
|
+
: naturalHeight(previousState.naturalHeight) {
|
|
25
|
+
}
|
|
27
26
|
#endif
|
|
28
27
|
|
|
29
28
|
Float naturalHeight{0};
|
|
@@ -36,4 +35,4 @@ class TrueSheetContentViewState final {
|
|
|
36
35
|
#endif
|
|
37
36
|
};
|
|
38
37
|
|
|
39
|
-
}
|
|
38
|
+
} // namespace facebook::react
|
package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h
CHANGED
|
@@ -8,17 +8,15 @@ namespace facebook::react {
|
|
|
8
8
|
/*
|
|
9
9
|
* Descriptor for <TrueSheetFooterView> component.
|
|
10
10
|
*/
|
|
11
|
-
class TrueSheetFooterViewComponentDescriptor final
|
|
12
|
-
: public ConcreteComponentDescriptor<TrueSheetFooterViewShadowNode> {
|
|
11
|
+
class TrueSheetFooterViewComponentDescriptor final : public ConcreteComponentDescriptor<TrueSheetFooterViewShadowNode> {
|
|
13
12
|
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
|
|
14
13
|
|
|
15
14
|
void adopt(ShadowNode &shadowNode) const override {
|
|
16
|
-
auto &concreteShadowNode =
|
|
17
|
-
static_cast<TrueSheetFooterViewShadowNode &>(shadowNode);
|
|
15
|
+
auto &concreteShadowNode = static_cast<TrueSheetFooterViewShadowNode &>(shadowNode);
|
|
18
16
|
concreteShadowNode.adjustLayoutWithState();
|
|
19
17
|
|
|
20
18
|
ConcreteComponentDescriptor::adopt(shadowNode);
|
|
21
19
|
}
|
|
22
20
|
};
|
|
23
21
|
|
|
24
|
-
}
|
|
22
|
+
} // namespace facebook::react
|
package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp
CHANGED
|
@@ -13,8 +13,7 @@ extern const char TrueSheetFooterViewComponentName[] = "TrueSheetFooterView";
|
|
|
13
13
|
void TrueSheetFooterViewShadowNode::adjustLayoutWithState() {
|
|
14
14
|
ensureUnsealed();
|
|
15
15
|
|
|
16
|
-
auto state = std::static_pointer_cast<
|
|
17
|
-
const TrueSheetFooterViewShadowNode::ConcreteState>(getState());
|
|
16
|
+
auto state = std::static_pointer_cast<const TrueSheetFooterViewShadowNode::ConcreteState>(getState());
|
|
18
17
|
auto stateData = state->getData();
|
|
19
18
|
|
|
20
19
|
auto &props = getConcreteProps();
|
|
@@ -60,4 +59,4 @@ void TrueSheetFooterViewShadowNode::adjustLayoutWithState() {
|
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
}
|
|
62
|
+
} // namespace facebook::react
|
|
@@ -14,15 +14,12 @@ JSI_EXPORT extern const char TrueSheetFooterViewComponentName[];
|
|
|
14
14
|
* `ShadowNode` for <TrueSheetFooterView> component.
|
|
15
15
|
*/
|
|
16
16
|
class JSI_EXPORT TrueSheetFooterViewShadowNode final
|
|
17
|
-
: public ConcreteViewShadowNode<
|
|
18
|
-
|
|
19
|
-
TrueSheetFooterViewProps,
|
|
20
|
-
TrueSheetFooterViewEventEmitter,
|
|
21
|
-
TrueSheetFooterViewState> {
|
|
17
|
+
: public ConcreteViewShadowNode<TrueSheetFooterViewComponentName, TrueSheetFooterViewProps,
|
|
18
|
+
TrueSheetFooterViewEventEmitter, TrueSheetFooterViewState> {
|
|
22
19
|
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
|
23
20
|
|
|
24
21
|
public:
|
|
25
22
|
void adjustLayoutWithState();
|
|
26
23
|
};
|
|
27
24
|
|
|
28
|
-
}
|
|
25
|
+
} // namespace facebook::react
|
|
@@ -18,11 +18,9 @@ class TrueSheetFooterViewState final {
|
|
|
18
18
|
TrueSheetFooterViewState() = default;
|
|
19
19
|
|
|
20
20
|
#ifdef ANDROID
|
|
21
|
-
TrueSheetFooterViewState(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
: bottomInset(static_cast<float>(data["bottomInset"].getDouble())),
|
|
25
|
-
initialized(true) {}
|
|
21
|
+
TrueSheetFooterViewState(TrueSheetFooterViewState const &previousState, folly::dynamic data)
|
|
22
|
+
: bottomInset(static_cast<float>(data["bottomInset"].getDouble())), initialized(true) {
|
|
23
|
+
}
|
|
26
24
|
#endif
|
|
27
25
|
|
|
28
26
|
float bottomInset{0};
|
|
@@ -38,4 +36,4 @@ class TrueSheetFooterViewState final {
|
|
|
38
36
|
#endif
|
|
39
37
|
};
|
|
40
38
|
|
|
41
|
-
}
|
|
39
|
+
} // namespace facebook::react
|
|
@@ -11,10 +11,7 @@ namespace facebook::react {
|
|
|
11
11
|
* native. A zero dimension leaves that axis to Yoga.
|
|
12
12
|
*/
|
|
13
13
|
inline void applyContainerSizeToYogaNode(
|
|
14
|
-
|
|
15
|
-
const yoga::Style &baseStyle,
|
|
16
|
-
float containerWidth,
|
|
17
|
-
float containerHeight) {
|
|
14
|
+
yoga::Node &node, const yoga::Style &baseStyle, float containerWidth, float containerHeight) {
|
|
18
15
|
if (containerWidth <= 0 && containerHeight <= 0) {
|
|
19
16
|
return;
|
|
20
17
|
}
|
|
@@ -43,4 +40,4 @@ inline void applyContainerSizeToYogaNode(
|
|
|
43
40
|
}
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
}
|
|
43
|
+
} // namespace facebook::react
|
package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp
CHANGED
|
@@ -11,7 +11,7 @@ void TrueSheetOverlayViewShadowNode::adjustLayoutWithState() {
|
|
|
11
11
|
|
|
12
12
|
const auto &stateData = getStateData();
|
|
13
13
|
applyContainerSizeToYogaNode(
|
|
14
|
-
|
|
14
|
+
yogaNode_, getConcreteProps().yogaStyle, stateData.containerWidth, stateData.containerHeight);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
}
|
|
17
|
+
} // namespace facebook::react
|
|
@@ -16,11 +16,8 @@ JSI_EXPORT extern const char TrueSheetOverlayViewComponentName[];
|
|
|
16
16
|
* lay out against the full window like the sheet's container.
|
|
17
17
|
*/
|
|
18
18
|
class JSI_EXPORT TrueSheetOverlayViewShadowNode final
|
|
19
|
-
: public ConcreteViewShadowNode<
|
|
20
|
-
|
|
21
|
-
TrueSheetOverlayViewProps,
|
|
22
|
-
TrueSheetOverlayViewEventEmitter,
|
|
23
|
-
TrueSheetViewState> {
|
|
19
|
+
: public ConcreteViewShadowNode<TrueSheetOverlayViewComponentName, TrueSheetOverlayViewProps,
|
|
20
|
+
TrueSheetOverlayViewEventEmitter, TrueSheetViewState> {
|
|
24
21
|
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
|
25
22
|
|
|
26
23
|
public:
|
|
@@ -33,4 +30,4 @@ class JSI_EXPORT TrueSheetOverlayViewShadowNode final
|
|
|
33
30
|
void adjustLayoutWithState();
|
|
34
31
|
};
|
|
35
32
|
|
|
36
|
-
}
|
|
33
|
+
} // namespace facebook::react
|
package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h
CHANGED
|
@@ -8,13 +8,11 @@ namespace facebook::react {
|
|
|
8
8
|
/*
|
|
9
9
|
* Descriptor for <TrueSheetView> component.
|
|
10
10
|
*/
|
|
11
|
-
class TrueSheetViewComponentDescriptor final
|
|
12
|
-
: public ConcreteComponentDescriptor<TrueSheetViewShadowNode> {
|
|
11
|
+
class TrueSheetViewComponentDescriptor final : public ConcreteComponentDescriptor<TrueSheetViewShadowNode> {
|
|
13
12
|
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
|
|
14
13
|
|
|
15
14
|
void adopt(ShadowNode &shadowNode) const override {
|
|
16
|
-
auto &concreteShadowNode =
|
|
17
|
-
static_cast<TrueSheetViewShadowNode &>(shadowNode);
|
|
15
|
+
auto &concreteShadowNode = static_cast<TrueSheetViewShadowNode &>(shadowNode);
|
|
18
16
|
concreteShadowNode.adjustLayoutWithState();
|
|
19
17
|
|
|
20
18
|
ConcreteComponentDescriptor::adopt(shadowNode);
|
|
@@ -25,4 +23,4 @@ class TrueSheetViewComponentDescriptor final
|
|
|
25
23
|
}
|
|
26
24
|
};
|
|
27
25
|
|
|
28
|
-
}
|
|
26
|
+
} // namespace facebook::react
|
|
@@ -11,20 +11,18 @@ void TrueSheetViewShadowNode::adjustLayoutWithState() {
|
|
|
11
11
|
|
|
12
12
|
const auto &stateData = getStateData();
|
|
13
13
|
applyContainerSizeToYogaNode(
|
|
14
|
-
|
|
14
|
+
yogaNode_, getConcreteProps().yogaStyle, stateData.containerWidth, stateData.containerHeight);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
#if !defined(ANDROID)
|
|
18
|
-
void TrueSheetViewShadowNode::setEventDispatcher(
|
|
19
|
-
std::weak_ptr<const EventDispatcher> dispatcher) {
|
|
18
|
+
void TrueSheetViewShadowNode::setEventDispatcher(std::weak_ptr<const EventDispatcher> dispatcher) {
|
|
20
19
|
getStateDataMutable().setEventDispatcher(dispatcher);
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
TrueSheetViewShadowNode::StateData &
|
|
24
|
-
TrueSheetViewShadowNode::getStateDataMutable() {
|
|
22
|
+
TrueSheetViewShadowNode::StateData &TrueSheetViewShadowNode::getStateDataMutable() {
|
|
25
23
|
ensureUnsealed();
|
|
26
24
|
return const_cast<TrueSheetViewShadowNode::StateData &>(getStateData());
|
|
27
25
|
}
|
|
28
26
|
#endif
|
|
29
27
|
|
|
30
|
-
}
|
|
28
|
+
} // namespace facebook::react
|
|
@@ -15,12 +15,8 @@ JSI_EXPORT extern const char TrueSheetViewComponentName[];
|
|
|
15
15
|
/*
|
|
16
16
|
* `ShadowNode` for <TrueSheetView> component.
|
|
17
17
|
*/
|
|
18
|
-
class JSI_EXPORT TrueSheetViewShadowNode final
|
|
19
|
-
|
|
20
|
-
TrueSheetViewComponentName,
|
|
21
|
-
TrueSheetViewProps,
|
|
22
|
-
TrueSheetViewEventEmitter,
|
|
23
|
-
TrueSheetViewState> {
|
|
18
|
+
class JSI_EXPORT TrueSheetViewShadowNode final : public ConcreteViewShadowNode<TrueSheetViewComponentName,
|
|
19
|
+
TrueSheetViewProps, TrueSheetViewEventEmitter, TrueSheetViewState> {
|
|
24
20
|
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
|
25
21
|
|
|
26
22
|
public:
|
|
@@ -42,4 +38,4 @@ class JSI_EXPORT TrueSheetViewShadowNode final
|
|
|
42
38
|
#endif
|
|
43
39
|
};
|
|
44
40
|
|
|
45
|
-
}
|
|
41
|
+
} // namespace facebook::react
|
|
@@ -9,15 +9,13 @@ folly::dynamic TrueSheetViewState::getDynamic() const {
|
|
|
9
9
|
#endif
|
|
10
10
|
|
|
11
11
|
#if !defined(ANDROID)
|
|
12
|
-
void TrueSheetViewState::setEventDispatcher(
|
|
13
|
-
std::weak_ptr<const EventDispatcher> dispatcher) {
|
|
12
|
+
void TrueSheetViewState::setEventDispatcher(std::weak_ptr<const EventDispatcher> dispatcher) {
|
|
14
13
|
eventDispatcher_ = dispatcher;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
std::weak_ptr<const EventDispatcher> TrueSheetViewState::getEventDispatcher()
|
|
18
|
-
const noexcept {
|
|
16
|
+
std::weak_ptr<const EventDispatcher> TrueSheetViewState::getEventDispatcher() const noexcept {
|
|
19
17
|
return eventDispatcher_;
|
|
20
18
|
}
|
|
21
19
|
#endif
|
|
22
20
|
|
|
23
|
-
}
|
|
21
|
+
} // namespace facebook::react
|
|
@@ -23,11 +23,10 @@ class TrueSheetViewState final {
|
|
|
23
23
|
TrueSheetViewState() = default;
|
|
24
24
|
|
|
25
25
|
#ifdef ANDROID
|
|
26
|
-
TrueSheetViewState(
|
|
27
|
-
TrueSheetViewState const &previousState,
|
|
28
|
-
folly::dynamic data)
|
|
26
|
+
TrueSheetViewState(TrueSheetViewState const &previousState, folly::dynamic data)
|
|
29
27
|
: containerWidth(static_cast<float>(data["containerWidth"].getDouble())),
|
|
30
|
-
containerHeight(static_cast<float>(data["containerHeight"].getDouble())) {
|
|
28
|
+
containerHeight(static_cast<float>(data["containerHeight"].getDouble())) {
|
|
29
|
+
}
|
|
31
30
|
#endif
|
|
32
31
|
|
|
33
32
|
float containerWidth{0};
|
|
@@ -49,4 +48,4 @@ class TrueSheetViewState final {
|
|
|
49
48
|
#endif
|
|
50
49
|
};
|
|
51
50
|
|
|
52
|
-
}
|
|
51
|
+
} // namespace facebook::react
|
|
@@ -168,6 +168,8 @@ using namespace facebook::react;
|
|
|
168
168
|
if (_scrollableHandle > 0 && !_detectedScrollView) {
|
|
169
169
|
[self.delegate contentViewScrollViewDidChange];
|
|
170
170
|
}
|
|
171
|
+
|
|
172
|
+
[self updateKeyboardInset];
|
|
171
173
|
}
|
|
172
174
|
|
|
173
175
|
#pragma mark - Scrollable
|
|
@@ -183,6 +185,13 @@ using namespace facebook::react;
|
|
|
183
185
|
_detectedScrollView.scrollView.contentInset = contentInset;
|
|
184
186
|
}
|
|
185
187
|
|
|
188
|
+
- (void)updateKeyboardInset {
|
|
189
|
+
CGFloat keyboardHeight = _keyboardObserver.currentHeight;
|
|
190
|
+
if (_detectedScrollView && keyboardHeight > 0) {
|
|
191
|
+
[self setKeyboardInset:[self keyboardInsetWithHeight:keyboardHeight]];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
186
195
|
- (void)clearScrollable {
|
|
187
196
|
[self setKeyboardInset:0];
|
|
188
197
|
_appliedKeyboardOffset = 0;
|
|
@@ -213,26 +222,22 @@ using namespace facebook::react;
|
|
|
213
222
|
[self applyContentInsetAdjustment];
|
|
214
223
|
|
|
215
224
|
// If keyboard is currently showing, re-apply the keyboard inset to the new ScrollView
|
|
216
|
-
|
|
217
|
-
if (keyboardHeight > 0) {
|
|
218
|
-
[self setKeyboardInset:[self keyboardInsetWithHeight:keyboardHeight]];
|
|
219
|
-
}
|
|
225
|
+
[self updateKeyboardInset];
|
|
220
226
|
}
|
|
221
227
|
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
// floats within the viewport — its clearance is the content padding's job
|
|
225
|
-
// (the caret reveal accounts for it, see footerOcclusion).
|
|
228
|
+
// Short or nested scroll views can end above the sheet's bottom edge.
|
|
229
|
+
// Their frame also accounts for space occupied by a relative footer.
|
|
226
230
|
- (CGFloat)keyboardInsetWithHeight:(CGFloat)height {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
+
UIScrollView *scrollView = _detectedScrollView.scrollView;
|
|
232
|
+
UIWindow *window = scrollView.window;
|
|
233
|
+
CGRect scrollFrame = [scrollView convertRect:scrollView.bounds toView:window];
|
|
234
|
+
CGFloat keyboardTop = CGRectGetMaxY(window.bounds) - height;
|
|
235
|
+
CGFloat inset = MAX(0, CGRectGetMaxY(scrollFrame) - keyboardTop);
|
|
231
236
|
|
|
232
237
|
// UIKit stacks the safe area on top of contentInset while the adjustment
|
|
233
238
|
// behavior is automatic — take it out so the total lands on the keyboard edge.
|
|
234
239
|
if (_appliedContentInsetAdjustment) {
|
|
235
|
-
inset = MAX(0, inset -
|
|
240
|
+
inset = MAX(0, inset - scrollView.safeAreaInsets.bottom);
|
|
236
241
|
}
|
|
237
242
|
|
|
238
243
|
// Track how much of keyboardOffset actually lands in the inset so the caret
|
|
@@ -242,7 +247,6 @@ using namespace facebook::react;
|
|
|
242
247
|
|
|
243
248
|
// Content that already fits above the keyboard has nothing to reveal — the
|
|
244
249
|
// inset would only open blank scroll range below it (huge gap at the bottom).
|
|
245
|
-
UIScrollView *scrollView = _detectedScrollView.scrollView;
|
|
246
250
|
if (scrollView.contentSize.height <= scrollView.bounds.size.height - adjustedInset) {
|
|
247
251
|
_appliedKeyboardOffset = 0;
|
|
248
252
|
return 0;
|
|
@@ -334,12 +338,14 @@ using namespace facebook::react;
|
|
|
334
338
|
|
|
335
339
|
CGFloat inset = [self keyboardInsetWithHeight:height];
|
|
336
340
|
[UIView animateWithDuration:duration
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
341
|
+
delay:0
|
|
342
|
+
options:curve | UIViewAnimationOptionBeginFromCurrentState
|
|
343
|
+
animations:^{
|
|
344
|
+
[self setKeyboardInset:inset];
|
|
345
|
+
}
|
|
346
|
+
completion:^(BOOL finished) {
|
|
347
|
+
[self updateKeyboardInset];
|
|
348
|
+
}];
|
|
343
349
|
|
|
344
350
|
// Defer scroll until the next run loop so content insets are applied first
|
|
345
351
|
if (firstResponder) {
|
|
@@ -363,7 +369,7 @@ using namespace facebook::react;
|
|
|
363
369
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
364
370
|
// Typing can grow the content (e.g. a multiline input) past the fits-above-
|
|
365
371
|
// the-keyboard threshold — keep the inset in sync before revealing the caret.
|
|
366
|
-
[self
|
|
372
|
+
[self updateKeyboardInset];
|
|
367
373
|
[self scrollToFocusedCaretAnimated:YES];
|
|
368
374
|
});
|
|
369
375
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lodev09/react-native-true-sheet",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.12",
|
|
4
4
|
"description": "The true native bottom sheet experience for your React Native Apps.",
|
|
5
5
|
"source": "./src/index.ts",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"typecheck": "tsc",
|
|
59
59
|
"lint": "eslint --fix \"**/*.{ts,tsx}\"",
|
|
60
60
|
"format": "prettier --write \"**/*.{ts,tsx}\"",
|
|
61
|
-
"tidy": "yarn typecheck && yarn lint && yarn format && scripts/objclint.sh && scripts/ktlint.sh",
|
|
61
|
+
"tidy": "yarn typecheck && yarn lint && yarn format && scripts/objclint.sh && scripts/cpplint.sh && scripts/ktlint.sh",
|
|
62
62
|
"clean": "scripts/clean.sh",
|
|
63
63
|
"prepare": "bob build",
|
|
64
64
|
"release": "release-it",
|