react-native-nitro-modal 0.3.0-rc → 0.3.1-rc

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.
Files changed (53) hide show
  1. package/README.md +5 -1
  2. package/android/src/main/java/com/margelo/nitro/nitromodal/BottomSheetPresenter.kt +73 -9
  3. package/android/src/main/java/com/margelo/nitro/nitromodal/HybridNitroModal.kt +4 -0
  4. package/android/src/main/java/com/margelo/nitro/nitromodal/ModalConfig.kt +4 -0
  5. package/ios/HybridNitroModal.swift +5 -1
  6. package/ios/ModalConfig.swift +4 -0
  7. package/ios/SheetView.swift +82 -10
  8. package/lib/module/NitroModal.js +16 -1
  9. package/lib/module/NitroModal.js.map +1 -1
  10. package/lib/module/NitroModalView.web.js +32 -2
  11. package/lib/module/NitroModalView.web.js.map +1 -1
  12. package/lib/module/web/ModalConfig.js +3 -1
  13. package/lib/module/web/ModalConfig.js.map +1 -1
  14. package/lib/module/web/ModalPresenter.js.map +1 -1
  15. package/lib/module/web/SheetPresenter.js +66 -7
  16. package/lib/module/web/SheetPresenter.js.map +1 -1
  17. package/lib/module/web/dom.js +3 -0
  18. package/lib/module/web/dom.js.map +1 -1
  19. package/lib/typescript/src/NitroModal.d.ts +10 -1
  20. package/lib/typescript/src/NitroModal.d.ts.map +1 -1
  21. package/lib/typescript/src/NitroModal.nitro.d.ts +8 -0
  22. package/lib/typescript/src/NitroModal.nitro.d.ts.map +1 -1
  23. package/lib/typescript/src/NitroModalView.web.d.ts.map +1 -1
  24. package/lib/typescript/src/web/ModalConfig.d.ts +4 -0
  25. package/lib/typescript/src/web/ModalConfig.d.ts.map +1 -1
  26. package/lib/typescript/src/web/ModalPresenter.d.ts +4 -0
  27. package/lib/typescript/src/web/ModalPresenter.d.ts.map +1 -1
  28. package/lib/typescript/src/web/SheetPresenter.d.ts +12 -1
  29. package/lib/typescript/src/web/SheetPresenter.d.ts.map +1 -1
  30. package/lib/typescript/src/web/dom.d.ts +2 -0
  31. package/lib/typescript/src/web/dom.d.ts.map +1 -1
  32. package/nitrogen/generated/android/c++/JHybridNitroModalSpec.cpp +18 -0
  33. package/nitrogen/generated/android/c++/JHybridNitroModalSpec.hpp +4 -0
  34. package/nitrogen/generated/android/c++/views/JHybridNitroModalStateUpdater.cpp +10 -0
  35. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/HybridNitroModalSpec.kt +12 -0
  36. package/nitrogen/generated/ios/NitroModal-Swift-Cxx-Bridge.hpp +15 -0
  37. package/nitrogen/generated/ios/c++/HybridNitroModalSpecSwift.hpp +14 -0
  38. package/nitrogen/generated/ios/c++/views/HybridNitroModalComponent.mm +12 -0
  39. package/nitrogen/generated/ios/swift/HybridNitroModalSpec.swift +2 -0
  40. package/nitrogen/generated/ios/swift/HybridNitroModalSpec_cxx.swift +48 -0
  41. package/nitrogen/generated/shared/c++/HybridNitroModalSpec.cpp +4 -0
  42. package/nitrogen/generated/shared/c++/HybridNitroModalSpec.hpp +4 -0
  43. package/nitrogen/generated/shared/c++/views/HybridNitroModalComponent.cpp +4 -0
  44. package/nitrogen/generated/shared/c++/views/HybridNitroModalComponent.hpp +6 -0
  45. package/nitrogen/generated/shared/json/NitroModalConfig.json +2 -0
  46. package/package.json +1 -1
  47. package/src/NitroModal.nitro.ts +8 -0
  48. package/src/NitroModal.tsx +25 -0
  49. package/src/NitroModalView.web.tsx +26 -1
  50. package/src/web/ModalConfig.ts +6 -0
  51. package/src/web/ModalPresenter.ts +4 -0
  52. package/src/web/SheetPresenter.ts +72 -5
  53. package/src/web/dom.ts +3 -0
@@ -16,6 +16,9 @@ export declare class SheetPresenter extends ModalPresenter {
16
16
  private drag;
17
17
  /** Vertical velocity of the swipe that requested the dismissal. */
18
18
  private releaseVelocity;
19
+ /** The sheet rests below its lowest detent, the indicator spinning above it. */
20
+ private refreshing;
21
+ private refreshSpin;
19
22
  /** The sheet's top edge in the viewport. */
20
23
  private readonly top;
21
24
  constructor(config: ModalConfig, listener: PresenterListener);
@@ -23,7 +26,7 @@ export declare class SheetPresenter extends ModalPresenter {
23
26
  protected didShow(): void;
24
27
  protected animateIn(): void;
25
28
  protected animateOut(onEnd: () => void): void;
26
- protected configDidChange(): void;
29
+ protected configDidChange(previous: ModalConfig): void;
27
30
  protected viewportDidChange(): void;
28
31
  protected contentSizeDidChange(): void;
29
32
  protected stopAnimations(): void;
@@ -35,8 +38,16 @@ export declare class SheetPresenter extends ModalPresenter {
35
38
  /** Sheet top when resting on `detents[index]`. The bottom safe area is added below the content. */
36
39
  private restingTop;
37
40
  private get detentTops();
41
+ /** Where the sheet settles on `detents[index]`: held below the lowest detent while refreshing. */
42
+ private settledTop;
43
+ private get settledTops();
38
44
  private layout;
39
45
  private render;
46
+ /**
47
+ * Centered in the gap a pull uncovers below the lowest detent, fading in
48
+ * as the pull nears the threshold.
49
+ */
50
+ private renderRefreshIndicator;
40
51
  /** Fully dimmed at every detent; fades out below the lowest one. */
41
52
  private backdropAlpha;
42
53
  private motion;
@@ -1 +1 @@
1
- {"version":3,"file":"SheetPresenter.d.ts","sourceRoot":"","sources":["../../../../src/web/SheetPresenter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAqB,CAAC;AAEvD,OAAO,EAKL,KAAK,MAAM,EACX,KAAK,IAAI,EACV,MAAM,UAAO,CAAC;AACf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAe,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAkB,CAAC;AAgG1E,oEAAoE;AACpE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,WAAW,EAAE,EACtB,QAAQ,EAAE,IAAI,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,GAChB,IAAI,CAQN;AAcD;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,cAAc;IAChD,OAAO,CAAC,aAAa,CAAK;IAC1B,gFAAgF;IAChF,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,IAAI,CAAqB;IACjC,mEAAmE;IACnE,OAAO,CAAC,eAAe,CAAK;IAC5B,4CAA4C;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAElB;gBAEU,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB;IAQ5D,YAAY,CAAC,KAAK,EAAE,MAAM;IAO1B,SAAS,CAAC,OAAO;IAejB,SAAS,CAAC,SAAS;IAKnB,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,IAAI;IAYtC,SAAS,CAAC,eAAe;IAMzB,SAAS,CAAC,iBAAiB;IAK3B,SAAS,CAAC,oBAAoB;IAM9B,SAAS,CAAC,cAAc;IAIxB,SAAS,CAAC,QAAQ;IAalB,OAAO,KAAK,OAAO,GAIlB;IAED,OAAO,KAAK,kBAAkB,GAM7B;IAED,OAAO,KAAK,YAAY,GAIvB;IAED,OAAO,CAAC,MAAM;IAQd,mGAAmG;IACnG,OAAO,CAAC,UAAU;IAelB,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,CAAC,MAAM;IA0Bd,OAAO,CAAC,MAAM;IAMd,oEAAoE;IACpE,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,MAAM;IAYd,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,SAAS;IAwBjB,6GAA6G;IAC7G,OAAO,CAAC,KAAK;IAoBb,OAAO,CAAC,QAAQ;IAqBhB,OAAO,CAAC,QAAQ;IA4ChB,OAAO,CAAC,OAAO;IA2Cf,kFAAkF;IAClF,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,QAAQ;IAWhB,kGAAkG;IAClG,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,gBAAgB,CAiBtB;IAEF,OAAO,CAAC,eAAe,CAqBrB;IAEF,OAAO,CAAC,cAAc,CAKpB;IAIF,OAAO,CAAC,iBAAiB,CAqBvB;IAEF,OAAO,CAAC,iBAAiB,CAkBvB;IAEF,OAAO,CAAC,eAAe,CAIrB;CACH"}
1
+ {"version":3,"file":"SheetPresenter.d.ts","sourceRoot":"","sources":["../../../../src/web/SheetPresenter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAqB,CAAC;AAEvD,OAAO,EAOL,KAAK,MAAM,EACX,KAAK,IAAI,EACV,MAAM,UAAO,CAAC;AACf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAe,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAkB,CAAC;AAmG1E,oEAAoE;AACpE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,WAAW,EAAE,EACtB,QAAQ,EAAE,IAAI,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,GAChB,IAAI,CAQN;AAcD;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,cAAc;IAChD,OAAO,CAAC,aAAa,CAAK;IAC1B,gFAAgF;IAChF,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,IAAI,CAAqB;IACjC,mEAAmE;IACnE,OAAO,CAAC,eAAe,CAAK;IAC5B,gFAAgF;IAChF,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAA0B;IAC7C,4CAA4C;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAElB;gBAEU,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB;IAS5D,YAAY,CAAC,KAAK,EAAE,MAAM;IAO1B,SAAS,CAAC,OAAO;IAejB,SAAS,CAAC,SAAS;IAKnB,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,IAAI;IAYtC,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,WAAW;IAS/C,SAAS,CAAC,iBAAiB;IAK3B,SAAS,CAAC,oBAAoB;IAM9B,SAAS,CAAC,cAAc;IAIxB,SAAS,CAAC,QAAQ;IAelB,OAAO,KAAK,OAAO,GAIlB;IAED,OAAO,KAAK,kBAAkB,GAM7B;IAED,OAAO,KAAK,YAAY,GAIvB;IAED,OAAO,CAAC,MAAM;IAQd,mGAAmG;IACnG,OAAO,CAAC,UAAU;IAelB,OAAO,KAAK,UAAU,GAErB;IAED,kGAAkG;IAClG,OAAO,CAAC,UAAU;IAOlB,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,CAAC,MAAM;IA8Bd,OAAO,CAAC,MAAM;IAOd;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA2B9B,oEAAoE;IACpE,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,MAAM;IAYd,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,SAAS;IAwBjB,6GAA6G;IAC7G,OAAO,CAAC,KAAK;IAoBb,OAAO,CAAC,QAAQ;IAsBhB,OAAO,CAAC,QAAQ;IA4ChB,OAAO,CAAC,OAAO;IA+Cf,kFAAkF;IAClF,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,QAAQ;IAWhB,kGAAkG;IAClG,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,gBAAgB,CAiBtB;IAEF,OAAO,CAAC,eAAe,CAqBrB;IAEF,OAAO,CAAC,cAAc,CAKpB;IAIF,OAAO,CAAC,iBAAiB,CAqBvB;IAEF,OAAO,CAAC,iBAAiB,CAkBvB;IAEF,OAAO,CAAC,eAAe,CAIrB;CACH"}
@@ -10,6 +10,8 @@ export interface Insets {
10
10
  }
11
11
  export declare const ZERO_INSETS: Insets;
12
12
  export declare const canUseDOM: boolean;
13
+ /** Width and height of the pull-to-refresh indicator. */
14
+ export declare const REFRESH_INDICATOR_SIZE = 24;
13
15
  /** Converts a color from `processColor` (0xAARRGGBB) to CSS, scaling its alpha by `opacity`. */
14
16
  export declare function toCSSColor(argb: number, opacity?: number): string;
15
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../../../src/web/dom.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,WAAW,EAAE,MAAiD,CAAC;AAE5E,eAAO,MAAM,SAAS,SAC4C,CAAC;AAEnE,gGAAgG;AAChG,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,CAM5D;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAmB3C;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAcrD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AASD,gGAAgG;AAChG,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,IAAI,EAAE,OAAO,GACZ,WAAW,GAAG,IAAI,CAMpB;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAC7B,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAWT;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAO/D;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,SAUhC;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAK9C;AAID;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAMrC"}
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../../../src/web/dom.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,WAAW,EAAE,MAAiD,CAAC;AAE5E,eAAO,MAAM,SAAS,SAC4C,CAAC;AAEnE,yDAAyD;AACzD,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,gGAAgG;AAChG,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,CAM5D;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAmB3C;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAcrD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AASD,gGAAgG;AAChG,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,IAAI,EAAE,OAAO,GACZ,WAAW,GAAG,IAAI,CAMpB;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAC7B,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAWT;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAO/D;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,SAUhC;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAK9C;AAID;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAMrC"}
@@ -244,6 +244,24 @@ namespace margelo::nitro::nitromodal {
244
244
  static const auto method = _javaPart->javaClassStatic()->getMethod<void(jboolean /* pullToRefreshEnabled */)>("setPullToRefreshEnabled");
245
245
  method(_javaPart, pullToRefreshEnabled);
246
246
  }
247
+ std::optional<bool> JHybridNitroModalSpec::getRefreshing() {
248
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<jni::JBoolean>()>("getRefreshing");
249
+ auto __result = method(_javaPart);
250
+ return __result != nullptr ? std::make_optional(static_cast<bool>(__result->value())) : std::nullopt;
251
+ }
252
+ void JHybridNitroModalSpec::setRefreshing(std::optional<bool> refreshing) {
253
+ static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<jni::JBoolean> /* refreshing */)>("setRefreshing");
254
+ method(_javaPart, refreshing.has_value() ? jni::JBoolean::valueOf(refreshing.value()) : nullptr);
255
+ }
256
+ std::optional<double> JHybridNitroModalSpec::getRefreshIndicatorColor() {
257
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<jni::JDouble>()>("getRefreshIndicatorColor");
258
+ auto __result = method(_javaPart);
259
+ return __result != nullptr ? std::make_optional(__result->value()) : std::nullopt;
260
+ }
261
+ void JHybridNitroModalSpec::setRefreshIndicatorColor(std::optional<double> refreshIndicatorColor) {
262
+ static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<jni::JDouble> /* refreshIndicatorColor */)>("setRefreshIndicatorColor");
263
+ method(_javaPart, refreshIndicatorColor.has_value() ? jni::JDouble::valueOf(refreshIndicatorColor.value()) : nullptr);
264
+ }
247
265
  std::optional<std::function<void()>> JHybridNitroModalSpec::getOnPresent() {
248
266
  static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JFunc_void::javaobject>()>("getOnPresent_cxx");
249
267
  auto __result = method(_javaPart);
@@ -84,6 +84,10 @@ namespace margelo::nitro::nitromodal {
84
84
  void setPopupAnimation(PopupAnimation popupAnimation) override;
85
85
  bool getPullToRefreshEnabled() override;
86
86
  void setPullToRefreshEnabled(bool pullToRefreshEnabled) override;
87
+ std::optional<bool> getRefreshing() override;
88
+ void setRefreshing(std::optional<bool> refreshing) override;
89
+ std::optional<double> getRefreshIndicatorColor() override;
90
+ void setRefreshIndicatorColor(std::optional<double> refreshIndicatorColor) override;
87
91
  std::optional<std::function<void()>> getOnPresent() override;
88
92
  void setOnPresent(const std::optional<std::function<void()>>& onPresent) override;
89
93
  std::optional<std::function<void(DismissReason /* reason */)>> getOnDismiss() override;
@@ -138,6 +138,16 @@ void JHybridNitroModalStateUpdater::updateViewProps(jni::alias_ref<jni::JClass>
138
138
  : !newProps->pullToRefreshEnabled.hasSameValue(oldProps->pullToRefreshEnabled)) {
139
139
  hybridView->setPullToRefreshEnabled(newProps->pullToRefreshEnabled.get());
140
140
  }
141
+ if (oldProps == nullptr
142
+ ? newProps->refreshing.isProvided()
143
+ : !newProps->refreshing.hasSameValue(oldProps->refreshing)) {
144
+ hybridView->setRefreshing(newProps->refreshing.get());
145
+ }
146
+ if (oldProps == nullptr
147
+ ? newProps->refreshIndicatorColor.isProvided()
148
+ : !newProps->refreshIndicatorColor.hasSameValue(oldProps->refreshIndicatorColor)) {
149
+ hybridView->setRefreshIndicatorColor(newProps->refreshIndicatorColor.get());
150
+ }
141
151
  if (oldProps == nullptr
142
152
  ? newProps->onPresent.isProvided()
143
153
  : !newProps->onPresent.hasSameValue(oldProps->onPresent)) {
@@ -129,6 +129,18 @@ abstract class HybridNitroModalSpec: HybridView() {
129
129
  @set:Keep
130
130
  abstract var pullToRefreshEnabled: Boolean
131
131
 
132
+ @get:DoNotStrip
133
+ @get:Keep
134
+ @set:DoNotStrip
135
+ @set:Keep
136
+ abstract var refreshing: Boolean?
137
+
138
+ @get:DoNotStrip
139
+ @get:Keep
140
+ @set:DoNotStrip
141
+ @set:Keep
142
+ abstract var refreshIndicatorColor: Double?
143
+
132
144
  abstract var onPresent: (() -> Unit)?
133
145
 
134
146
  private var onPresent_cxx: Func_void?
@@ -95,6 +95,21 @@ namespace margelo::nitro::nitromodal::bridge::swift {
95
95
  return optional.value();
96
96
  }
97
97
 
98
+ // pragma MARK: std::optional<bool>
99
+ /**
100
+ * Specialized version of `std::optional<bool>`.
101
+ */
102
+ using std__optional_bool_ = std::optional<bool>;
103
+ inline std::optional<bool> create_std__optional_bool_(const bool& value) noexcept {
104
+ return std::optional<bool>(value);
105
+ }
106
+ inline bool has_value_std__optional_bool_(const std::optional<bool>& optional) noexcept {
107
+ return optional.has_value();
108
+ }
109
+ inline bool get_std__optional_bool_(const std::optional<bool>& optional) noexcept {
110
+ return optional.value();
111
+ }
112
+
98
113
  // pragma MARK: std::function<void()>
99
114
  /**
100
115
  * Specialized version of `std::function<void()>`.
@@ -189,6 +189,20 @@ namespace margelo::nitro::nitromodal {
189
189
  inline void setPullToRefreshEnabled(bool pullToRefreshEnabled) noexcept override {
190
190
  _swiftPart.setPullToRefreshEnabled(std::forward<decltype(pullToRefreshEnabled)>(pullToRefreshEnabled));
191
191
  }
192
+ inline std::optional<bool> getRefreshing() noexcept override {
193
+ auto __result = _swiftPart.getRefreshing();
194
+ return __result;
195
+ }
196
+ inline void setRefreshing(std::optional<bool> refreshing) noexcept override {
197
+ _swiftPart.setRefreshing(refreshing);
198
+ }
199
+ inline std::optional<double> getRefreshIndicatorColor() noexcept override {
200
+ auto __result = _swiftPart.getRefreshIndicatorColor();
201
+ return __result;
202
+ }
203
+ inline void setRefreshIndicatorColor(std::optional<double> refreshIndicatorColor) noexcept override {
204
+ _swiftPart.setRefreshIndicatorColor(refreshIndicatorColor);
205
+ }
192
206
  inline std::optional<std::function<void()>> getOnPresent() noexcept override {
193
207
  auto __result = _swiftPart.getOnPresent();
194
208
  return __result;
@@ -200,6 +200,18 @@ using namespace margelo::nitro::nitromodal::views;
200
200
  : !newViewProps.pullToRefreshEnabled.hasSameValue(oldViewProps->pullToRefreshEnabled)) {
201
201
  swiftPart.setPullToRefreshEnabled(newViewProps.pullToRefreshEnabled.get());
202
202
  }
203
+ // refreshing: optional
204
+ if (oldViewProps == nullptr
205
+ ? newViewProps.refreshing.isProvided()
206
+ : !newViewProps.refreshing.hasSameValue(oldViewProps->refreshing)) {
207
+ swiftPart.setRefreshing(newViewProps.refreshing.get());
208
+ }
209
+ // refreshIndicatorColor: optional
210
+ if (oldViewProps == nullptr
211
+ ? newViewProps.refreshIndicatorColor.isProvided()
212
+ : !newViewProps.refreshIndicatorColor.hasSameValue(oldViewProps->refreshIndicatorColor)) {
213
+ swiftPart.setRefreshIndicatorColor(newViewProps.refreshIndicatorColor.get());
214
+ }
203
215
  // onPresent: optional
204
216
  if (oldViewProps == nullptr
205
217
  ? newViewProps.onPresent.isProvided()
@@ -27,6 +27,8 @@ public protocol HybridNitroModalSpec_protocol: HybridObject, HybridView {
27
27
  var keyboardBehavior: KeyboardBehavior { get set }
28
28
  var popupAnimation: PopupAnimation { get set }
29
29
  var pullToRefreshEnabled: Bool { get set }
30
+ var refreshing: Bool? { get set }
31
+ var refreshIndicatorColor: Double? { get set }
30
32
  var onPresent: (() -> Void)? { get set }
31
33
  var onDismiss: ((_ reason: DismissReason) -> Void)? { get set }
32
34
  var onDetentChange: ((_ index: Double) -> Void)? { get set }
@@ -346,6 +346,54 @@ open class HybridNitroModalSpec_cxx {
346
346
  }
347
347
  }
348
348
 
349
+ public final var refreshing: bridge.std__optional_bool_ {
350
+ @inline(__always)
351
+ get {
352
+ return { () -> bridge.std__optional_bool_ in
353
+ if let __unwrappedValue = self.__implementation.refreshing {
354
+ return bridge.create_std__optional_bool_(__unwrappedValue)
355
+ } else {
356
+ return .init()
357
+ }
358
+ }()
359
+ }
360
+ @inline(__always)
361
+ set {
362
+ self.__implementation.refreshing = { () -> Bool? in
363
+ if bridge.has_value_std__optional_bool_(newValue) {
364
+ let __unwrapped = bridge.get_std__optional_bool_(newValue)
365
+ return __unwrapped
366
+ } else {
367
+ return nil
368
+ }
369
+ }()
370
+ }
371
+ }
372
+
373
+ public final var refreshIndicatorColor: bridge.std__optional_double_ {
374
+ @inline(__always)
375
+ get {
376
+ return { () -> bridge.std__optional_double_ in
377
+ if let __unwrappedValue = self.__implementation.refreshIndicatorColor {
378
+ return bridge.create_std__optional_double_(__unwrappedValue)
379
+ } else {
380
+ return .init()
381
+ }
382
+ }()
383
+ }
384
+ @inline(__always)
385
+ set {
386
+ self.__implementation.refreshIndicatorColor = { () -> Double? in
387
+ if bridge.has_value_std__optional_double_(newValue) {
388
+ let __unwrapped = bridge.get_std__optional_double_(newValue)
389
+ return __unwrapped
390
+ } else {
391
+ return nil
392
+ }
393
+ }()
394
+ }
395
+ }
396
+
349
397
  public final var onPresent: bridge.std__optional_std__function_void____ {
350
398
  @inline(__always)
351
399
  get {
@@ -48,6 +48,10 @@ namespace margelo::nitro::nitromodal {
48
48
  prototype.registerHybridSetter("popupAnimation", &HybridNitroModalSpec::setPopupAnimation);
49
49
  prototype.registerHybridGetter("pullToRefreshEnabled", &HybridNitroModalSpec::getPullToRefreshEnabled);
50
50
  prototype.registerHybridSetter("pullToRefreshEnabled", &HybridNitroModalSpec::setPullToRefreshEnabled);
51
+ prototype.registerHybridGetter("refreshing", &HybridNitroModalSpec::getRefreshing);
52
+ prototype.registerHybridSetter("refreshing", &HybridNitroModalSpec::setRefreshing);
53
+ prototype.registerHybridGetter("refreshIndicatorColor", &HybridNitroModalSpec::getRefreshIndicatorColor);
54
+ prototype.registerHybridSetter("refreshIndicatorColor", &HybridNitroModalSpec::setRefreshIndicatorColor);
51
55
  prototype.registerHybridGetter("onPresent", &HybridNitroModalSpec::getOnPresent);
52
56
  prototype.registerHybridSetter("onPresent", &HybridNitroModalSpec::setOnPresent);
53
57
  prototype.registerHybridGetter("onDismiss", &HybridNitroModalSpec::getOnDismiss);
@@ -98,6 +98,10 @@ namespace margelo::nitro::nitromodal {
98
98
  virtual void setPopupAnimation(PopupAnimation popupAnimation) = 0;
99
99
  virtual bool getPullToRefreshEnabled() = 0;
100
100
  virtual void setPullToRefreshEnabled(bool pullToRefreshEnabled) = 0;
101
+ virtual std::optional<bool> getRefreshing() = 0;
102
+ virtual void setRefreshing(std::optional<bool> refreshing) = 0;
103
+ virtual std::optional<double> getRefreshIndicatorColor() = 0;
104
+ virtual void setRefreshIndicatorColor(std::optional<double> refreshIndicatorColor) = 0;
101
105
  virtual std::optional<std::function<void()>> getOnPresent() = 0;
102
106
  virtual void setOnPresent(const std::optional<std::function<void()>>& onPresent) = 0;
103
107
  virtual std::optional<std::function<void(DismissReason /* reason */)>> getOnDismiss() = 0;
@@ -37,6 +37,8 @@ namespace margelo::nitro::nitromodal::views {
37
37
  keyboardBehavior(nitro::ReactProp<KeyboardBehavior>::fromRawValue("NitroModal", "keyboardBehavior", rawProps, sourceProps.keyboardBehavior)),
38
38
  popupAnimation(nitro::ReactProp<PopupAnimation>::fromRawValue("NitroModal", "popupAnimation", rawProps, sourceProps.popupAnimation)),
39
39
  pullToRefreshEnabled(nitro::ReactProp<bool>::fromRawValue("NitroModal", "pullToRefreshEnabled", rawProps, sourceProps.pullToRefreshEnabled)),
40
+ refreshing(nitro::ReactProp<std::optional<bool>>::fromRawValue("NitroModal", "refreshing", rawProps, sourceProps.refreshing)),
41
+ refreshIndicatorColor(nitro::ReactProp<std::optional<double>>::fromRawValue("NitroModal", "refreshIndicatorColor", rawProps, sourceProps.refreshIndicatorColor)),
40
42
  onPresent(nitro::ReactProp<std::optional<std::function<void()>>>::fromRawValue("NitroModal", "onPresent", rawProps, sourceProps.onPresent)),
41
43
  onDismiss(nitro::ReactProp<std::optional<std::function<void(DismissReason /* reason */)>>>::fromRawValue("NitroModal", "onDismiss", rawProps, sourceProps.onDismiss)),
42
44
  onDetentChange(nitro::ReactProp<std::optional<std::function<void(double /* index */)>>>::fromRawValue("NitroModal", "onDetentChange", rawProps, sourceProps.onDetentChange)),
@@ -66,6 +68,8 @@ namespace margelo::nitro::nitromodal::views {
66
68
  case hashString("keyboardBehavior"): return true;
67
69
  case hashString("popupAnimation"): return true;
68
70
  case hashString("pullToRefreshEnabled"): return true;
71
+ case hashString("refreshing"): return true;
72
+ case hashString("refreshIndicatorColor"): return true;
69
73
  case hashString("onPresent"): return true;
70
74
  case hashString("onDismiss"): return true;
71
75
  case hashString("onDetentChange"): return true;
@@ -67,6 +67,8 @@ namespace margelo::nitro::nitromodal::views {
67
67
  nitro::ReactProp<KeyboardBehavior> keyboardBehavior;
68
68
  nitro::ReactProp<PopupAnimation> popupAnimation;
69
69
  nitro::ReactProp<bool> pullToRefreshEnabled;
70
+ nitro::ReactProp<std::optional<bool>> refreshing;
71
+ nitro::ReactProp<std::optional<double>> refreshIndicatorColor;
70
72
  nitro::ReactProp<std::optional<std::function<void()>>> onPresent;
71
73
  nitro::ReactProp<std::optional<std::function<void(DismissReason /* reason */)>>> onDismiss;
72
74
  nitro::ReactProp<std::optional<std::function<void(double /* index */)>>> onDetentChange;
@@ -96,6 +98,8 @@ namespace margelo::nitro::nitromodal::views {
96
98
  keyboardBehavior.hasSameValue(other.keyboardBehavior) &&
97
99
  popupAnimation.hasSameValue(other.popupAnimation) &&
98
100
  pullToRefreshEnabled.hasSameValue(other.pullToRefreshEnabled) &&
101
+ refreshing.hasSameValue(other.refreshing) &&
102
+ refreshIndicatorColor.hasSameValue(other.refreshIndicatorColor) &&
99
103
  onPresent.hasSameValue(other.onPresent) &&
100
104
  onDismiss.hasSameValue(other.onDismiss) &&
101
105
  onDetentChange.hasSameValue(other.onDetentChange) &&
@@ -126,6 +130,8 @@ namespace margelo::nitro::nitromodal::views {
126
130
  keyboardBehavior.isProvided() ||
127
131
  popupAnimation.isProvided() ||
128
132
  pullToRefreshEnabled.isProvided() ||
133
+ refreshing.isProvided() ||
134
+ refreshIndicatorColor.isProvided() ||
129
135
  onPresent.isProvided() ||
130
136
  onDismiss.isProvided() ||
131
137
  onDetentChange.isProvided() ||
@@ -21,6 +21,8 @@
21
21
  "keyboardBehavior": true,
22
22
  "popupAnimation": true,
23
23
  "pullToRefreshEnabled": true,
24
+ "refreshing": true,
25
+ "refreshIndicatorColor": true,
24
26
  "onPresent": true,
25
27
  "onDismiss": true,
26
28
  "onDetentChange": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-modal",
3
- "version": "0.3.0-rc",
3
+ "version": "0.3.1-rc",
4
4
  "description": "react native native modal",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -86,6 +86,14 @@ export interface NitroModalProps extends HybridViewProps {
86
86
  * `onPullToRefresh`. Needs `dismissOnSwipe` off (always the case inline).
87
87
  */
88
88
  pullToRefreshEnabled: boolean;
89
+ /**
90
+ * A refresh is in progress: the sheet rests pulled down below its lowest
91
+ * detent with an activity indicator above it. Native starts refreshing on
92
+ * its own when a pull is released. `undefined` shows no indicator.
93
+ */
94
+ refreshing?: boolean;
95
+ /** Refresh indicator color as a processed ARGB color. Omit for the platform default. */
96
+ refreshIndicatorColor?: number;
89
97
 
90
98
  /** The present transition finished. */
91
99
  onPresent?: () => void;
@@ -1,4 +1,5 @@
1
1
  import {
2
+ useEffect,
2
3
  useImperativeHandle,
3
4
  useLayoutEffect,
4
5
  useMemo,
@@ -111,6 +112,15 @@ export interface NitroModalProps {
111
112
  * sheet resting on its lowest detent.
112
113
  */
113
114
  onPullToRefresh?: () => void;
115
+ /**
116
+ * Whether a refresh is in progress, like `RefreshControl`'s `refreshing`.
117
+ * While true, the sheet stays pulled down below its lowest detent with an
118
+ * activity indicator above it. Set it to `true` in `onPullToRefresh` and
119
+ * back to `false` when done. Leave undefined to show no indicator.
120
+ */
121
+ refreshing?: boolean;
122
+ /** Color of the refresh indicator. Defaults to the platform style. */
123
+ refreshIndicatorColor?: ColorValue;
114
124
  children?: ReactNode;
115
125
  testID?: string;
116
126
  ref?: Ref<NitroModalRef>;
@@ -158,6 +168,8 @@ export function NitroModal({
158
168
  onBackdropPress,
159
169
  onBackButtonPress,
160
170
  onPullToRefresh,
171
+ refreshing,
172
+ refreshIndicatorColor,
161
173
  children,
162
174
  testID,
163
175
  ref,
@@ -182,12 +194,21 @@ export function NitroModal({
182
194
  // is laid out there so `measure()`, which presses rely on, matches the
183
195
  // screen; native cancels the offset out on screen.
184
196
  const [restingTop, setRestingTop] = useState(0);
197
+ // Native starts refreshing as soon as a pull is released. Reporting `true`
198
+ // for the render that follows, then `refreshing` again, stops it if the
199
+ // handler didn't start a refresh (unchanged props never reach native).
200
+ const isRefreshControlled = refreshing !== undefined;
201
+ const [pullPending, setPullPending] = useState(false);
202
+ useEffect(() => {
203
+ if (pullPending) setPullPending(false);
204
+ }, [pullPending]);
185
205
  const hybridRef = useRef<NitroModalHybridView | null>(null);
186
206
 
187
207
  // Native callbacks are created once (stable props, no native updates on
188
208
  // re-render) and read the latest handlers from this ref.
189
209
  const latest = useRef({
190
210
  isControlled,
211
+ isRefreshControlled,
191
212
  onPresent,
192
213
  onDismiss,
193
214
  onDetentChange,
@@ -198,6 +219,7 @@ export function NitroModal({
198
219
  useLayoutEffect(() => {
199
220
  latest.current = {
200
221
  isControlled,
222
+ isRefreshControlled,
201
223
  onPresent,
202
224
  onDismiss,
203
225
  onDetentChange,
@@ -231,6 +253,7 @@ export function NitroModal({
231
253
  latest.current.onBackButtonPress?.();
232
254
  }),
233
255
  onPullToRefresh: callback(() => {
256
+ if (latest.current.isRefreshControlled) setPullPending(true);
234
257
  latest.current.onPullToRefresh?.();
235
258
  }),
236
259
  onRestingTopChange: callback((top: number) => {
@@ -315,6 +338,8 @@ export function NitroModal({
315
338
  keyboardBehavior={keyboardBehavior}
316
339
  popupAnimation={popupAnimation}
317
340
  pullToRefreshEnabled={onPullToRefresh != null}
341
+ refreshing={isRefreshControlled ? refreshing || pullPending : undefined}
342
+ refreshIndicatorColor={toNativeColor(refreshIndicatorColor)}
318
343
  {...nativeCallbacks}
319
344
  >
320
345
  {renderContent ? (
@@ -11,7 +11,7 @@ import {
11
11
  import { Modal, View, type StyleProp, type ViewStyle } from 'react-native';
12
12
  import type { ReactNativeView } from 'react-native-nitro-modules';
13
13
  import type { NitroModalMethods, NitroModalProps } from './NitroModal.nitro';
14
- import { clipOverflow } from './web/dom';
14
+ import { clipOverflow, REFRESH_INDICATOR_SIZE } from './web/dom';
15
15
  import { ModalController } from './web/ModalController';
16
16
 
17
17
  interface WebNitroModalViewProps extends NitroModalProps {
@@ -45,6 +45,8 @@ function WebNitroModalView(props: WebNitroModalViewProps) {
45
45
  const surface = useRef<HTMLDivElement>(null);
46
46
  const content = useRef<HTMLDivElement>(null);
47
47
  const grabber = useRef<HTMLDivElement>(null);
48
+ const refreshIndicator = useRef<HTMLDivElement>(null);
49
+ const refreshSpinner = useRef<HTMLDivElement>(null);
48
50
 
49
51
  useLayoutEffect(() => {
50
52
  controller.attach();
@@ -67,6 +69,8 @@ function WebNitroModalView(props: WebNitroModalViewProps) {
67
69
  surface: surface.current!,
68
70
  content: content.current!,
69
71
  grabber: grabber.current!,
72
+ refreshIndicator: refreshIndicator.current!,
73
+ refreshSpinner: refreshSpinner.current!,
70
74
  });
71
75
  return () => controller.elementsWillUnmount();
72
76
  }, [controller, mounted]);
@@ -98,6 +102,9 @@ function WebNitroModalView(props: WebNitroModalViewProps) {
98
102
  }
99
103
  >
100
104
  <div ref={backdrop} aria-hidden style={styles.backdrop} />
105
+ <div ref={refreshIndicator} aria-hidden style={styles.refreshIndicator}>
106
+ <div ref={refreshSpinner} style={styles.refreshSpinner} />
107
+ </div>
101
108
  <div ref={surface} style={styles.surface}>
102
109
  <div ref={content} style={styles.content}>
103
110
  {children}
@@ -172,6 +179,24 @@ const styles = {
172
179
  backgroundColor: 'rgba(127, 127, 127, 0.4)',
173
180
  pointerEvents: 'none',
174
181
  },
182
+ refreshIndicator: {
183
+ position: 'absolute',
184
+ left: 0,
185
+ top: 0,
186
+ width: REFRESH_INDICATOR_SIZE,
187
+ height: REFRESH_INDICATOR_SIZE,
188
+ opacity: 0,
189
+ pointerEvents: 'none',
190
+ },
191
+ // Colored through `color` by the presenter.
192
+ refreshSpinner: {
193
+ width: '100%',
194
+ height: '100%',
195
+ boxSizing: 'border-box',
196
+ borderRadius: '50%',
197
+ border: '2.5px solid currentColor',
198
+ borderTopColor: 'transparent',
199
+ },
175
200
  } satisfies Record<string, CSSProperties>;
176
201
 
177
202
  export const NitroModalView = WebNitroModalView as unknown as ReactNativeView<
@@ -31,6 +31,10 @@ export interface ModalConfig {
31
31
  keyboardBehavior: KeyboardBehavior;
32
32
  popupAnimation: PopupAnimation;
33
33
  pullToRefreshEnabled: boolean;
34
+ /** A refresh is in progress; `null` shows no refresh indicator. */
35
+ refreshing: boolean | null;
36
+ /** 0xAARRGGBB; `null` uses the default. */
37
+ refreshIndicatorColor: number | null;
34
38
  }
35
39
 
36
40
  export function makeConfig(props: NitroModalProps): ModalConfig {
@@ -55,6 +59,8 @@ export function makeConfig(props: NitroModalProps): ModalConfig {
55
59
  keyboardBehavior: props.keyboardBehavior,
56
60
  popupAnimation: props.popupAnimation,
57
61
  pullToRefreshEnabled: props.pullToRefreshEnabled,
62
+ refreshing: props.refreshing ?? null,
63
+ refreshIndicatorColor: props.refreshIndicatorColor ?? null,
58
64
  };
59
65
  }
60
66
 
@@ -23,6 +23,10 @@ export interface ModalElements {
23
23
  /** Hosts the React content. */
24
24
  content: HTMLElement;
25
25
  grabber: HTMLElement;
26
+ /** Behind the sheet, uncovered as it's pulled down to refresh. */
27
+ refreshIndicator: HTMLElement;
28
+ /** The spinning ring inside `refreshIndicator`. */
29
+ refreshSpinner: HTMLElement;
26
30
  }
27
31
 
28
32
  export interface PresenterListener {