react-native-tinyui 3.1.0 → 3.2.0

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 (40) hide show
  1. package/README.md +76 -5
  2. package/ios/TipKit/TinyuiTipPopoverProvider.swift +29 -2
  3. package/ios/TipKit/TinyuiTipPopoverView.mm +10 -0
  4. package/ios/TipKit/TinyuiTipView.mm +9 -0
  5. package/ios/TipKit/TinyuiTipViewProvider.swift +8 -2
  6. package/ios/TipKit/TinyuiTipsRuntime.swift +12 -0
  7. package/lib/module/TipKit/Group.js +52 -0
  8. package/lib/module/TipKit/Group.js.map +1 -0
  9. package/lib/module/TipKit/Popover.js +15 -1
  10. package/lib/module/TipKit/Popover.js.map +1 -1
  11. package/lib/module/TipKit/TipPopoverNativeComponent.ts +7 -0
  12. package/lib/module/TipKit/TipViewNativeComponent.ts +6 -0
  13. package/lib/module/TipKit/View.js +13 -1
  14. package/lib/module/TipKit/View.js.map +1 -1
  15. package/lib/module/TipKit/index.js +2 -0
  16. package/lib/module/TipKit/index.js.map +1 -1
  17. package/lib/module/index.js.map +1 -1
  18. package/lib/typescript/src/TipKit/Group.d.ts +13 -0
  19. package/lib/typescript/src/TipKit/Group.d.ts.map +1 -0
  20. package/lib/typescript/src/TipKit/Popover.d.ts.map +1 -1
  21. package/lib/typescript/src/TipKit/TipPopoverNativeComponent.d.ts +5 -0
  22. package/lib/typescript/src/TipKit/TipPopoverNativeComponent.d.ts.map +1 -1
  23. package/lib/typescript/src/TipKit/TipViewNativeComponent.d.ts +4 -0
  24. package/lib/typescript/src/TipKit/TipViewNativeComponent.d.ts.map +1 -1
  25. package/lib/typescript/src/TipKit/View.d.ts.map +1 -1
  26. package/lib/typescript/src/TipKit/index.d.ts +3 -1
  27. package/lib/typescript/src/TipKit/index.d.ts.map +1 -1
  28. package/lib/typescript/src/TipKit/types.d.ts +18 -0
  29. package/lib/typescript/src/TipKit/types.d.ts.map +1 -1
  30. package/lib/typescript/src/index.d.ts +1 -1
  31. package/lib/typescript/src/index.d.ts.map +1 -1
  32. package/package.json +1 -1
  33. package/src/TipKit/Group.tsx +76 -0
  34. package/src/TipKit/Popover.tsx +16 -2
  35. package/src/TipKit/TipPopoverNativeComponent.ts +7 -0
  36. package/src/TipKit/TipViewNativeComponent.ts +6 -0
  37. package/src/TipKit/View.tsx +14 -2
  38. package/src/TipKit/index.ts +4 -0
  39. package/src/TipKit/types.ts +24 -0
  40. package/src/index.tsx +2 -0
package/README.md CHANGED
@@ -82,7 +82,7 @@ Available components:
82
82
  - `Stepper`
83
83
  - `ConcentricView`
84
84
  - `SFSymbol`
85
- - `TipKit` (enables `TipKit.View`, `TipKit.Popover`, `TipKit.configure`, `TipKit.resetDatastore` and `TipKit.invalidate`)
85
+ - `TipKit` (enables `TipKit.Group`, `TipKit.View`, `TipKit.Popover`, `TipKit.configure`, `TipKit.resetDatastore` and `TipKit.invalidate`)
86
86
 
87
87
  `TipKit` is one optional module containing both native views,
88
88
  `TinyuiTipPopoverView` and `TinyuiTipView`. Select it once in your app's
@@ -431,8 +431,77 @@ The remaining props are shared by both components:
431
431
  | `ignoresDisplayFrequency` | Exempts this tip from the app-wide display interval | `false` |
432
432
  | `arrowEdge` | `top`, `bottom`, `leading`, `trailing`; Popover also accepts `auto`, View accepts `none` | Popover: `auto`; View: `none` |
433
433
  | `onActionPress` | Receives the selected `{ id, title }`; does not automatically invalidate | — |
434
+ | `onInvalidated` | Receives `{ reason }` when invalidated, including persisted invalidation on mount; Popover waits until dismissal finishes | — |
434
435
  | `onError` | Receives `{ code, message }`; otherwise a warning is logged | — |
435
436
 
437
+ `TipKit.Popover` also accepts `invalidateOnOutsideDismiss`. It defaults to
438
+ `false`, or inherits its Group's value. When enabled, tapping outside the bubble
439
+ invalidates the tip with `tipClosed`. Programmatic hiding, disabling, unmounting
440
+ and leaving the screen do not themselves invalidate it.
441
+
442
+ ### Ordered groups
443
+
444
+ `TipKit.Group` presents tips in the explicit `tipIds` order. It is a React
445
+ coordinator available on **iOS 17+**, backed by native TipKit eligibility and
446
+ persisted invalidation; it does not wrap Apple's iOS 18 `TipGroup` API.
447
+ `priority` currently supports only `ordered` and defaults to it. The Group adds
448
+ no layout view, so its tips can be nested in ordinary layout components.
449
+
450
+ ```tsx
451
+ // At app startup, before mounting tips:
452
+ await TipKit.configure({ displayFrequency: 'immediate' });
453
+
454
+ // In your screen:
455
+ <TipKit.Group
456
+ priority="ordered"
457
+ tipIds={['favorite-v1', 'share-v1']}
458
+ enabled={isScreenFocused}
459
+ invalidateOnOutsideDismiss
460
+ >
461
+ <TipKit.Popover tipId="favorite-v1" title="Save your favorites">
462
+ <Button
463
+ title="Favorite"
464
+ onPress={async () => {
465
+ await TipKit.invalidate('favorite-v1', 'actionPerformed');
466
+ saveFavorite();
467
+ }}
468
+ />
469
+ </TipKit.Popover>
470
+ <TipKit.Popover tipId="share-v1" title="Share with a friend">
471
+ <Button
472
+ title="Share"
473
+ onPress={async () => {
474
+ await TipKit.invalidate('share-v1', 'actionPerformed');
475
+ shareItem();
476
+ }}
477
+ />
478
+ </TipKit.Popover>
479
+ </TipKit.Group>;
480
+ ```
481
+
482
+ - The system close button, `TipKit.invalidate`, or native display limits complete
483
+ a step. The next tip is enabled after the preceding popover has finished
484
+ dismissing. Action buttons still require explicit invalidation.
485
+ - Outside dismissal does **not** complete a step by default. Opt in with
486
+ `invalidateOnOutsideDismiss`, either on the Group or an individual Popover.
487
+ An explicit Popover value overrides the Group's value.
488
+ - Already-invalidated tips are skipped when the group mounts again. Keep IDs
489
+ stable across launches. Progress is driven by native state, not JS storage.
490
+ - The next tip still obeys native eligibility and display frequency. Use
491
+ `immediate` at startup for consecutive tips; TinyUI otherwise defaults to
492
+ `daily`.
493
+ - Use each declared ID for one `TipKit.View` or `TipKit.Popover` in the group.
494
+ A missing, disabled or ineligible current tip blocks later tips. Keep the
495
+ current tip mounted and enabled until it reports invalidation; invalidate it
496
+ instead of immediately disabling it when its feature is used.
497
+ - `enabled={false}` pauses the group without completing a step. Groups are
498
+ independent; this is not a global queue for other tips, sheets or screens.
499
+
500
+ `onInvalidated` reports `actionPerformed`, `tipClosed`, `displayCountExceeded`,
501
+ `displayDurationExceeded`, or `unknown` for an unrecognized native reason.
502
+ It is a state notification, not an outside-dismiss callback, and can fire again
503
+ when an already-invalidated tip resumes observation.
504
+
436
505
  Both components accept standard `ViewProps` and a native view ref. For Popover,
437
506
  `style` lays out the anchor, not the bubble. UIKit chooses the bubble's size and may adapt
438
507
  the arrow to available space; leading/trailing follow layout direction. Bubble
@@ -481,8 +550,9 @@ launch will erase users' tip history on every launch.
481
550
  requires configuration first. It persistently invalidates the ID even when no
482
551
  view for that tip is mounted. `reason` may be `actionPerformed` or `tipClosed`.
483
552
 
484
- Both native views observe TipKit's `shouldDisplayUpdates` to show or remove
485
- the tip. Eligibility and visibility changes are not sent to JavaScript.
553
+ Both native views observe TipKit's `statusUpdates` to show or remove
554
+ the tip. Invalidation is sent to JavaScript through `onInvalidated`; other
555
+ eligibility and visibility changes are not sent to JavaScript.
486
556
  Call `invalidate` with `actionPerformed` after the feature is used, or with
487
557
  `tipClosed` to permanently dismiss the tip. TipKit also handles the system
488
558
  close button and display limits.
@@ -496,7 +566,7 @@ with the same ID share their TipKit history. Keep `maxDisplayCount` and
496
566
  tip. Hiding a tip, unmounting it or reconfiguring TinyUI never resets history.
497
567
 
498
568
  Use `enabled={isScreenFocused && businessCondition}` with your navigation
499
- library. Each mounted, enabled Popover anchor starts its own `shouldDisplayUpdates`
569
+ library. Each mounted, enabled Popover anchor starts its own `statusUpdates`
500
570
  observation once it has a size and a parent view controller. Disabling,
501
571
  detaching or recycling the component stops observation and dismisses its
502
572
  bubble; changing `tipId` starts a new observation. This follows the independent
@@ -517,7 +587,8 @@ detached or recycled. They do not present a view controller or block interaction
517
587
  with the rest of the screen. Both presentations use the same datastore; an
518
588
  invalidation affects every instance of the same `tipId`.
519
589
 
520
- Native rule/event builders and TipGroup are not exposed. The example's
590
+ Native rule/event builders and Apple's TipGroup are not exposed. Use the
591
+ React `TipKit.Group` above for ordered presentation. The example's
521
592
  **Inline view** switch toggles between both presentations. Its **New demo tip**
522
593
  button deliberately creates another
523
594
  ID for trying the behavior again without clearing the app's TipKit datastore.
@@ -4,6 +4,7 @@ import UIKit
4
4
  @objc public protocol TinyuiTipPopoverDelegate: AnyObject {
5
5
  func onTipAction(tipId: String, id: String, title: String)
6
6
  func onTipError(tipId: String, code: String, message: String)
7
+ func onTipInvalidated(tipId: String, reason: String)
7
8
  }
8
9
 
9
10
  @MainActor
@@ -26,6 +27,8 @@ import UIKit
26
27
  private var presentedTipId: String?
27
28
  private var isPresenting = false
28
29
  private var isDismissing = false
30
+ private var invalidateOnOutsideDismiss = false
31
+ private var pendingInvalidation: (tipId: String, reason: String)?
29
32
 
30
33
  @objc public convenience init(delegate: TinyuiTipPopoverDelegate) {
31
34
  self.init(frame: .zero)
@@ -34,6 +37,7 @@ import UIKit
34
37
 
35
38
  @objc public func configure(_ configuration: [String: Any], enabled: Bool, arrowEdge: String) {
36
39
  let nextTip = TinyuiTip(configuration: configuration)
40
+ if tip?.id != nextTip.id { pendingInvalidation = nil }
37
41
  if tip?.id != nextTip.id || self.enabled != enabled {
38
42
  stop()
39
43
  lastError = nil
@@ -41,6 +45,7 @@ import UIKit
41
45
  tip = nextTip
42
46
  self.enabled = enabled
43
47
  self.arrowEdge = arrowEdge
48
+ invalidateOnOutsideDismiss = configuration["invalidateOnOutsideDismiss"] as? Bool ?? false
44
49
  // Validate changed options even when an observation is already running.
45
50
  do {
46
51
  try TinyuiTipsRuntime.shared.remember(nextTip)
@@ -87,10 +92,16 @@ import UIKit
87
92
  }
88
93
 
89
94
  observation = Task { @MainActor [weak self] in
90
- for await shouldDisplay in tip.shouldDisplayUpdates {
95
+ var reportedInvalidation = false
96
+ for await status in tip.statusUpdates {
91
97
  guard !Task.isCancelled, let self else { break }
92
- self.shouldDisplay = shouldDisplay
98
+ if case .available = status { self.shouldDisplay = true } else { self.shouldDisplay = false }
99
+ if case .invalidated(let reason) = status, !reportedInvalidation {
100
+ reportedInvalidation = true
101
+ self.pendingInvalidation = (tip.id, TinyuiTipsRuntime.invalidationReason(reason))
102
+ }
93
103
  self.updatePresentation()
104
+ self.reportInvalidationIfDismissed()
94
105
  }
95
106
  }
96
107
  }
@@ -178,11 +189,25 @@ import UIKit
178
189
  presentedTipId = nil
179
190
  isPresenting = false
180
191
  isDismissing = false
192
+ reportInvalidationIfDismissed()
193
+ }
194
+
195
+ private func reportInvalidationIfDismissed() {
196
+ // The next grouped anchor must not present until this transition finishes.
197
+ guard controller == nil, let event = pendingInvalidation else { return }
198
+ pendingInvalidation = nil
199
+ delegate?.onTipInvalidated(tipId: event.tipId, reason: event.reason)
181
200
  }
182
201
 
183
202
  public func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
184
203
  guard let controller, presentationController.presentedViewController === controller else { return }
204
+ let dismissedTip = presentedTipId == tip?.id ? tip : nil
205
+ let shouldInvalidate = invalidateOnOutsideDismiss && !isDismissing
185
206
  finishDismissal(controller)
207
+ // Programmatic hiding, navigation and recycling do not complete a tip.
208
+ if shouldInvalidate, let dismissedTip, case .available = dismissedTip.status {
209
+ dismissedTip.invalidate(reason: .tipClosed)
210
+ }
186
211
  }
187
212
 
188
213
  public func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle { .none }
@@ -199,6 +224,8 @@ import UIKit
199
224
  enabled = false
200
225
  tip = nil
201
226
  lastError = nil
227
+ pendingInvalidation = nil
228
+ invalidateOnOutsideDismiss = false
202
229
  stop()
203
230
  parentViewController = nil
204
231
  }
@@ -65,6 +65,7 @@ using namespace facebook::react;
65
65
  @"actions": actions,
66
66
  @"maxDisplayCount": @(next.maxDisplayCount),
67
67
  @"ignoresDisplayFrequency": @(next.ignoresDisplayFrequency),
68
+ @"invalidateOnOutsideDismiss": @(next.invalidateOnOutsideDismiss),
68
69
  } enabled:next.enabled arrowEdge:RCTNSStringFromString(next.arrowEdge)];
69
70
  [super updateProps:props oldProps:oldProps];
70
71
  }
@@ -87,6 +88,15 @@ using namespace facebook::react;
87
88
  });
88
89
  }
89
90
 
91
+ - (void)onTipInvalidatedWithTipId:(NSString *)tipId reason:(NSString *)reason
92
+ {
93
+ if (_eventEmitter == nullptr) return;
94
+ std::static_pointer_cast<const TinyuiTipPopoverViewEventEmitter>(_eventEmitter)->onTipInvalidated({
95
+ .tipId = std::string(tipId.UTF8String ?: ""),
96
+ .reason = std::string(reason.UTF8String ?: "unknown"),
97
+ });
98
+ }
99
+
90
100
  - (void)prepareForRecycle
91
101
  {
92
102
  [_provider reset];
@@ -83,6 +83,15 @@ using namespace facebook::react;
83
83
  });
84
84
  }
85
85
 
86
+ - (void)onTipInvalidatedWithTipId:(NSString *)tipId reason:(NSString *)reason
87
+ {
88
+ if (_eventEmitter == nullptr) return;
89
+ std::static_pointer_cast<const TinyuiTipViewEventEmitter>(_eventEmitter)->onTipInvalidated({
90
+ .tipId = std::string(tipId.UTF8String ?: ""),
91
+ .reason = std::string(reason.UTF8String ?: "unknown"),
92
+ });
93
+ }
94
+
86
95
  - (void)prepareForRecycle
87
96
  {
88
97
  _state.reset();
@@ -5,6 +5,7 @@ import UIKit
5
5
  @objc public protocol TinyuiTipViewDelegate: AnyObject {
6
6
  func onTipAction(tipId: String, id: String, title: String)
7
7
  func onTipError(tipId: String, code: String, message: String)
8
+ func onTipInvalidated(tipId: String, reason: String)
8
9
  // Fabric consumes this size directly; it is not a JavaScript event.
9
10
  func onTipSizeChange(tipId: String, width: CGFloat, height: CGFloat)
10
11
  }
@@ -69,9 +70,14 @@ import UIKit
69
70
  return
70
71
  }
71
72
  observation = Task { @MainActor [weak self] in
72
- for await shouldDisplay in tip.shouldDisplayUpdates {
73
+ var reportedInvalidation = false
74
+ for await status in tip.statusUpdates {
73
75
  guard !Task.isCancelled, let self else { break }
74
- if shouldDisplay { self.showTip() } else { self.removeTip() }
76
+ if case .available = status { self.showTip() } else { self.removeTip() }
77
+ if case .invalidated(let reason) = status, !reportedInvalidation {
78
+ reportedInvalidation = true
79
+ self.delegate?.onTipInvalidated(tipId: tip.id, reason: TinyuiTipsRuntime.invalidationReason(reason))
80
+ }
75
81
  }
76
82
  }
77
83
  }
@@ -80,6 +80,18 @@ import Foundation
80
80
  ])
81
81
  }
82
82
 
83
+ static func invalidationReason(_ reason: Tips.InvalidationReason) -> String {
84
+ if #available(iOS 18.0, *), reason == .displayDurationExceeded {
85
+ return "displayDurationExceeded"
86
+ }
87
+ switch reason {
88
+ case .actionPerformed: return "actionPerformed"
89
+ case .tipClosed: return "tipClosed"
90
+ case .displayCountExceeded: return "displayCountExceeded"
91
+ default: return "unknown"
92
+ }
93
+ }
94
+
83
95
  func remember(_ tip: TinyuiTip) throws {
84
96
  if let previous = knownTips[tip.id],
85
97
  previous.maximumDisplayCount != tip.maximumDisplayCount || previous.ignoresFrequency != tip.ignoresFrequency {
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+
3
+ import { createContext, useCallback, useContext, useMemo, useState } from 'react';
4
+ import { assertComponentEnabled } from "../utils/index.js";
5
+ import { validateTipId } from "./validation.js";
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ const GroupContext = /*#__PURE__*/createContext(null);
8
+
9
+ /** Orders tips by ID while native TipKit owns eligibility and persisted history. */
10
+ export function Group({
11
+ tipIds,
12
+ priority = 'ordered',
13
+ enabled = true,
14
+ invalidateOnOutsideDismiss = false,
15
+ children
16
+ }) {
17
+ assertComponentEnabled('TipKit');
18
+ if (priority !== 'ordered') {
19
+ throw new Error('[TinyUI] TipKit.Group only supports ordered priority.');
20
+ }
21
+ const ids = new Set();
22
+ for (const tipId of tipIds) {
23
+ validateTipId(tipId);
24
+ if (ids.has(tipId)) {
25
+ throw new Error('[TinyUI] TipKit.Group tipIds must be unique.');
26
+ }
27
+ ids.add(tipId);
28
+ }
29
+ const [completed, setCompleted] = useState(() => new Set());
30
+ const complete = useCallback(tipId => {
31
+ setCompleted(previous => previous.has(tipId) ? previous : new Set([...previous, tipId]));
32
+ }, []);
33
+ const value = useMemo(() => ({
34
+ tipIds: new Set(tipIds),
35
+ currentTipId: tipIds.find(id => !completed.has(id)),
36
+ enabled,
37
+ invalidateOnOutsideDismiss,
38
+ complete
39
+ }), [tipIds, completed, enabled, invalidateOnOutsideDismiss, complete]);
40
+ return /*#__PURE__*/_jsx(GroupContext.Provider, {
41
+ value: value,
42
+ children: children
43
+ });
44
+ }
45
+ export function useTipGroup(tipId) {
46
+ const group = useContext(GroupContext);
47
+ if (group && !group.tipIds.has(tipId)) {
48
+ throw new Error(`[TinyUI] TipKit tipId "${tipId}" is missing from its Group's tipIds.`);
49
+ }
50
+ return group;
51
+ }
52
+ //# sourceMappingURL=Group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["createContext","useCallback","useContext","useMemo","useState","assertComponentEnabled","validateTipId","jsx","_jsx","GroupContext","Group","tipIds","priority","enabled","invalidateOnOutsideDismiss","children","Error","ids","Set","tipId","has","add","completed","setCompleted","complete","previous","value","currentTipId","find","id","Provider","useTipGroup","group"],"sourceRoot":"../../../src","sources":["TipKit/Group.tsx"],"mappings":";;AAAA,SACEA,aAAa,EACbC,WAAW,EACXC,UAAU,EACVC,OAAO,EACPC,QAAQ,QACH,OAAO;AAEd,SAASC,sBAAsB,QAAQ,mBAAU;AAEjD,SAASC,aAAa,QAAQ,iBAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAU7C,MAAMC,YAAY,gBAAGT,aAAa,CAA2B,IAAI,CAAC;;AAElE;AACA,OAAO,SAASU,KAAKA,CAAC;EACpBC,MAAM;EACNC,QAAQ,GAAG,SAAS;EACpBC,OAAO,GAAG,IAAI;EACdC,0BAA0B,GAAG,KAAK;EAClCC;AACa,CAAC,EAAE;EAChBV,sBAAsB,CAAC,QAAQ,CAAC;EAChC,IAAIO,QAAQ,KAAK,SAAS,EAAE;IAC1B,MAAM,IAAII,KAAK,CAAC,uDAAuD,CAAC;EAC1E;EACA,MAAMC,GAAG,GAAG,IAAIC,GAAG,CAAS,CAAC;EAC7B,KAAK,MAAMC,KAAK,IAAIR,MAAM,EAAE;IAC1BL,aAAa,CAACa,KAAK,CAAC;IACpB,IAAIF,GAAG,CAACG,GAAG,CAACD,KAAK,CAAC,EAAE;MAClB,MAAM,IAAIH,KAAK,CAAC,8CAA8C,CAAC;IACjE;IACAC,GAAG,CAACI,GAAG,CAACF,KAAK,CAAC;EAChB;EAEA,MAAM,CAACG,SAAS,EAAEC,YAAY,CAAC,GAAGnB,QAAQ,CACxC,MAAM,IAAIc,GAAG,CAAC,CAChB,CAAC;EACD,MAAMM,QAAQ,GAAGvB,WAAW,CAAEkB,KAAa,IAAK;IAC9CI,YAAY,CAAEE,QAAQ,IACpBA,QAAQ,CAACL,GAAG,CAACD,KAAK,CAAC,GAAGM,QAAQ,GAAG,IAAIP,GAAG,CAAC,CAAC,GAAGO,QAAQ,EAAEN,KAAK,CAAC,CAC/D,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EACN,MAAMO,KAAK,GAAGvB,OAAO,CACnB,OAAO;IACLQ,MAAM,EAAE,IAAIO,GAAG,CAACP,MAAM,CAAC;IACvBgB,YAAY,EAAEhB,MAAM,CAACiB,IAAI,CAAEC,EAAE,IAAK,CAACP,SAAS,CAACF,GAAG,CAACS,EAAE,CAAC,CAAC;IACrDhB,OAAO;IACPC,0BAA0B;IAC1BU;EACF,CAAC,CAAC,EACF,CAACb,MAAM,EAAEW,SAAS,EAAET,OAAO,EAAEC,0BAA0B,EAAEU,QAAQ,CACnE,CAAC;EAED,oBACEhB,IAAA,CAACC,YAAY,CAACqB,QAAQ;IAACJ,KAAK,EAAEA,KAAM;IAAAX,QAAA,EAAEA;EAAQ,CAAwB,CAAC;AAE3E;AAEA,OAAO,SAASgB,WAAWA,CAACZ,KAAa,EAAE;EACzC,MAAMa,KAAK,GAAG9B,UAAU,CAACO,YAAY,CAAC;EACtC,IAAIuB,KAAK,IAAI,CAACA,KAAK,CAACrB,MAAM,CAACS,GAAG,CAACD,KAAK,CAAC,EAAE;IACrC,MAAM,IAAIH,KAAK,CACb,0BAA0BG,KAAK,uCACjC,CAAC;EACH;EACA,OAAOa,KAAK;AACd","ignoreList":[]}
@@ -5,10 +5,12 @@ import { View } from 'react-native';
5
5
  import { assertComponentEnabled } from "../utils/index.js";
6
6
  import NativeTipPopoverView from './TipPopoverNativeComponent';
7
7
  import { validateTip } from "./validation.js";
8
+ import { useTipGroup } from "./Group.js";
8
9
  import { jsx as _jsx } from "react/jsx-runtime";
9
10
  export const Popover = /*#__PURE__*/forwardRef(function TipPopoverRoot(props, ref) {
10
11
  assertComponentEnabled('TipKit');
11
12
  validateTip(props);
13
+ const group = useTipGroup(props.tipId);
12
14
  const {
13
15
  children,
14
16
  tipId,
@@ -21,6 +23,8 @@ export const Popover = /*#__PURE__*/forwardRef(function TipPopoverRoot(props, re
21
23
  ignoresDisplayFrequency = false,
22
24
  arrowEdge = 'auto',
23
25
  onActionPress,
26
+ onInvalidated,
27
+ invalidateOnOutsideDismiss = group?.invalidateOnOutsideDismiss ?? false,
24
28
  onError,
25
29
  ...viewProps
26
30
  } = props;
@@ -33,7 +37,8 @@ export const Popover = /*#__PURE__*/forwardRef(function TipPopoverRoot(props, re
33
37
  message: message,
34
38
  systemImage: systemImage,
35
39
  actions: actions,
36
- enabled: enabled,
40
+ enabled: enabled && (!group || group.enabled && group.currentTipId === tipId),
41
+ invalidateOnOutsideDismiss: invalidateOnOutsideDismiss,
37
42
  maxDisplayCount: maxDisplayCount ?? 0,
38
43
  ignoresDisplayFrequency: ignoresDisplayFrequency,
39
44
  arrowEdge: arrowEdge,
@@ -47,6 +52,15 @@ export const Popover = /*#__PURE__*/forwardRef(function TipPopoverRoot(props, re
47
52
  });
48
53
  }
49
54
  },
55
+ onTipInvalidated: ({
56
+ nativeEvent
57
+ }) => {
58
+ if (nativeEvent.tipId !== tipId) return;
59
+ group?.complete(tipId);
60
+ onInvalidated?.({
61
+ reason: nativeEvent.reason
62
+ });
63
+ },
50
64
  onTipError: ({
51
65
  nativeEvent
52
66
  }) => {
@@ -1 +1 @@
1
- {"version":3,"names":["forwardRef","View","assertComponentEnabled","NativeTipPopoverView","validateTip","jsx","_jsx","Popover","TipPopoverRoot","props","ref","children","tipId","title","message","systemImage","actions","enabled","maxDisplayCount","ignoresDisplayFrequency","arrowEdge","onActionPress","onError","viewProps","collapsable","onTipAction","nativeEvent","id","onTipError","error","code","console","warn","displayName"],"sourceRoot":"../../../src","sources":["TipKit/Popover.tsx"],"mappings":";;AAAA,SAASA,UAAU,QAA2B,OAAO;AACrD,SAASC,IAAI,QAAQ,cAAc;AAEnC,SAASC,sBAAsB,QAAQ,mBAAU;AACjD,OAAOC,oBAAoB,MAAM,6BAA6B;AAE9D,SAASC,WAAW,QAAQ,iBAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAE3C,OAAO,MAAMC,OAAO,gBAAGP,UAAU,CAC/B,SAASQ,cAAcA,CAACC,KAAK,EAAEC,GAAG,EAAE;EAClCR,sBAAsB,CAAC,QAAQ,CAAC;EAChCE,WAAW,CAACK,KAAK,CAAC;EAClB,MAAM;IACJE,QAAQ;IACRC,KAAK;IACLC,KAAK;IACLC,OAAO;IACPC,WAAW;IACXC,OAAO;IACPC,OAAO,GAAG,IAAI;IACdC,eAAe;IACfC,uBAAuB,GAAG,KAAK;IAC/BC,SAAS,GAAG,MAAM;IAClBC,aAAa;IACbC,OAAO;IACP,GAAGC;EACL,CAAC,GAAGd,KAAK;EAET,oBACEH,IAAA,CAACH,oBAAoB;IAAA,GACfoB,SAAS;IACbb,GAAG,EAAEA,GAAI;IACTc,WAAW,EAAE,KAAM;IACnBZ,KAAK,EAAEA,KAAM;IACbC,KAAK,EAAEA,KAAM;IACbC,OAAO,EAAEA,OAAQ;IACjBC,WAAW,EAAEA,WAAY;IACzBC,OAAO,EAAEA,OAAQ;IACjBC,OAAO,EAAEA,OAAQ;IACjBC,eAAe,EAAEA,eAAe,IAAI,CAAE;IACtCC,uBAAuB,EAAEA,uBAAwB;IACjDC,SAAS,EAAEA,SAAU;IACrBK,WAAW,EAAEA,CAAC;MAAEC;IAAY,CAAC,KAAK;MAChC,IAAIA,WAAW,CAACd,KAAK,KAAKA,KAAK,EAAE;QAC/BS,aAAa,GAAG;UAAEM,EAAE,EAAED,WAAW,CAACC,EAAE;UAAEd,KAAK,EAAEa,WAAW,CAACb;QAAM,CAAC,CAAC;MACnE;IACF,CAAE;IACFe,UAAU,EAAEA,CAAC;MAAEF;IAAY,CAAC,KAAK;MAC/B,IAAIA,WAAW,CAACd,KAAK,KAAKA,KAAK,EAAE;MACjC,MAAMiB,KAAK,GAAG;QACZC,IAAI,EAAEJ,WAAW,CAACI,IAAI;QACtBhB,OAAO,EAAEY,WAAW,CAACZ;MACvB,CAAC;MACD,IAAIQ,OAAO,EAAEA,OAAO,CAACO,KAAK,CAAC,CAAC,KAE1BE,OAAO,CAACC,IAAI,CACV,2BAA2BH,KAAK,CAACC,IAAI,KAAKD,KAAK,CAACf,OAAO,EACzD,CAAC;IACL,CAAE;IAAAH,QAAA,eAEFL,IAAA,CAACL,IAAI;MAACuB,WAAW,EAAE,KAAM;MAAAb,QAAA,EAAEA;IAAQ,CAAO;EAAC,CACvB,CAAC;AAE3B,CACF,CAAC;AAEDJ,OAAO,CAAC0B,WAAW,GAAG,gBAAgB","ignoreList":[]}
1
+ {"version":3,"names":["forwardRef","View","assertComponentEnabled","NativeTipPopoverView","validateTip","useTipGroup","jsx","_jsx","Popover","TipPopoverRoot","props","ref","group","tipId","children","title","message","systemImage","actions","enabled","maxDisplayCount","ignoresDisplayFrequency","arrowEdge","onActionPress","onInvalidated","invalidateOnOutsideDismiss","onError","viewProps","collapsable","currentTipId","onTipAction","nativeEvent","id","onTipInvalidated","complete","reason","onTipError","error","code","console","warn","displayName"],"sourceRoot":"../../../src","sources":["TipKit/Popover.tsx"],"mappings":";;AAAA,SAASA,UAAU,QAA2B,OAAO;AACrD,SAASC,IAAI,QAAQ,cAAc;AAEnC,SAASC,sBAAsB,QAAQ,mBAAU;AACjD,OAAOC,oBAAoB,MAAM,6BAA6B;AAE9D,SAASC,WAAW,QAAQ,iBAAc;AAC1C,SAASC,WAAW,QAAQ,YAAS;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAEtC,OAAO,MAAMC,OAAO,gBAAGR,UAAU,CAC/B,SAASS,cAAcA,CAACC,KAAK,EAAEC,GAAG,EAAE;EAClCT,sBAAsB,CAAC,QAAQ,CAAC;EAChCE,WAAW,CAACM,KAAK,CAAC;EAClB,MAAME,KAAK,GAAGP,WAAW,CAACK,KAAK,CAACG,KAAK,CAAC;EACtC,MAAM;IACJC,QAAQ;IACRD,KAAK;IACLE,KAAK;IACLC,OAAO;IACPC,WAAW;IACXC,OAAO;IACPC,OAAO,GAAG,IAAI;IACdC,eAAe;IACfC,uBAAuB,GAAG,KAAK;IAC/BC,SAAS,GAAG,MAAM;IAClBC,aAAa;IACbC,aAAa;IACbC,0BAA0B,GAAGb,KAAK,EAAEa,0BAA0B,IAAI,KAAK;IACvEC,OAAO;IACP,GAAGC;EACL,CAAC,GAAGjB,KAAK;EAET,oBACEH,IAAA,CAACJ,oBAAoB;IAAA,GACfwB,SAAS;IACbhB,GAAG,EAAEA,GAAI;IACTiB,WAAW,EAAE,KAAM;IACnBf,KAAK,EAAEA,KAAM;IACbE,KAAK,EAAEA,KAAM;IACbC,OAAO,EAAEA,OAAQ;IACjBC,WAAW,EAAEA,WAAY;IACzBC,OAAO,EAAEA,OAAQ;IACjBC,OAAO,EACLA,OAAO,KAAK,CAACP,KAAK,IAAKA,KAAK,CAACO,OAAO,IAAIP,KAAK,CAACiB,YAAY,KAAKhB,KAAM,CACtE;IACDY,0BAA0B,EAAEA,0BAA2B;IACvDL,eAAe,EAAEA,eAAe,IAAI,CAAE;IACtCC,uBAAuB,EAAEA,uBAAwB;IACjDC,SAAS,EAAEA,SAAU;IACrBQ,WAAW,EAAEA,CAAC;MAAEC;IAAY,CAAC,KAAK;MAChC,IAAIA,WAAW,CAAClB,KAAK,KAAKA,KAAK,EAAE;QAC/BU,aAAa,GAAG;UAAES,EAAE,EAAED,WAAW,CAACC,EAAE;UAAEjB,KAAK,EAAEgB,WAAW,CAAChB;QAAM,CAAC,CAAC;MACnE;IACF,CAAE;IACFkB,gBAAgB,EAAEA,CAAC;MAAEF;IAAY,CAAC,KAAK;MACrC,IAAIA,WAAW,CAAClB,KAAK,KAAKA,KAAK,EAAE;MACjCD,KAAK,EAAEsB,QAAQ,CAACrB,KAAK,CAAC;MACtBW,aAAa,GAAG;QACdW,MAAM,EAAEJ,WAAW,CAACI;MACtB,CAAC,CAAC;IACJ,CAAE;IACFC,UAAU,EAAEA,CAAC;MAAEL;IAAY,CAAC,KAAK;MAC/B,IAAIA,WAAW,CAAClB,KAAK,KAAKA,KAAK,EAAE;MACjC,MAAMwB,KAAK,GAAG;QACZC,IAAI,EAAEP,WAAW,CAACO,IAAI;QACtBtB,OAAO,EAAEe,WAAW,CAACf;MACvB,CAAC;MACD,IAAIU,OAAO,EAAEA,OAAO,CAACW,KAAK,CAAC,CAAC,KAE1BE,OAAO,CAACC,IAAI,CACV,2BAA2BH,KAAK,CAACC,IAAI,KAAKD,KAAK,CAACrB,OAAO,EACzD,CAAC;IACL,CAAE;IAAAF,QAAA,eAEFP,IAAA,CAACN,IAAI;MAAC2B,WAAW,EAAE,KAAM;MAAAd,QAAA,EAAEA;IAAQ,CAAO;EAAC,CACvB,CAAC;AAE3B,CACF,CAAC;AAEDN,OAAO,CAACiC,WAAW,GAAG,gBAAgB","ignoreList":[]}
@@ -12,6 +12,7 @@ export interface NativeTipPopoverProps extends ViewProps {
12
12
  systemImage?: string;
13
13
  actions?: ReadonlyArray<Readonly<{ id: string; title: string }>>;
14
14
  enabled?: boolean;
15
+ invalidateOnOutsideDismiss?: boolean;
15
16
  maxDisplayCount?: CodegenTypes.Int32;
16
17
  ignoresDisplayFrequency?: boolean;
17
18
  arrowEdge?: string;
@@ -21,6 +22,12 @@ export interface NativeTipPopoverProps extends ViewProps {
21
22
  onTipError?: DirectEventHandler<
22
23
  Readonly<{ tipId: string; code: string; message: string }>
23
24
  >;
25
+ onTipInvalidated?: DirectEventHandler<
26
+ Readonly<{
27
+ tipId: string;
28
+ reason: string;
29
+ }>
30
+ >;
24
31
  }
25
32
 
26
33
  export default codegenNativeComponent<NativeTipPopoverProps>(
@@ -21,6 +21,12 @@ export interface NativeTipViewProps extends ViewProps {
21
21
  onTipError?: DirectEventHandler<
22
22
  Readonly<{ tipId: string; code: string; message: string }>
23
23
  >;
24
+ onTipInvalidated?: DirectEventHandler<
25
+ Readonly<{
26
+ tipId: string;
27
+ reason: string;
28
+ }>
29
+ >;
24
30
  }
25
31
 
26
32
  export default codegenNativeComponent<NativeTipViewProps>('TinyuiTipView', {
@@ -4,10 +4,12 @@ import { forwardRef } from 'react';
4
4
  import { assertComponentEnabled } from "../utils/index.js";
5
5
  import NativeTipView from './TipViewNativeComponent';
6
6
  import { validateTip } from "./validation.js";
7
+ import { useTipGroup } from "./Group.js";
7
8
  import { jsx as _jsx } from "react/jsx-runtime";
8
9
  export const View = /*#__PURE__*/forwardRef(function TipViewRoot(props, ref) {
9
10
  assertComponentEnabled('TipKit');
10
11
  validateTip(props, 'TipKit.View');
12
+ const group = useTipGroup(props.tipId);
11
13
  const {
12
14
  tipId,
13
15
  title,
@@ -19,6 +21,7 @@ export const View = /*#__PURE__*/forwardRef(function TipViewRoot(props, ref) {
19
21
  ignoresDisplayFrequency = false,
20
22
  arrowEdge = 'none',
21
23
  onActionPress,
24
+ onInvalidated,
22
25
  onError,
23
26
  ...viewProps
24
27
  } = props;
@@ -32,7 +35,7 @@ export const View = /*#__PURE__*/forwardRef(function TipViewRoot(props, ref) {
32
35
  message: message,
33
36
  systemImage: systemImage,
34
37
  actions: actions,
35
- enabled: enabled,
38
+ enabled: enabled && (!group || group.enabled && group.currentTipId === tipId),
36
39
  maxDisplayCount: maxDisplayCount ?? 0,
37
40
  ignoresDisplayFrequency: ignoresDisplayFrequency,
38
41
  arrowEdge: arrowEdge,
@@ -46,6 +49,15 @@ export const View = /*#__PURE__*/forwardRef(function TipViewRoot(props, ref) {
46
49
  });
47
50
  }
48
51
  },
52
+ onTipInvalidated: ({
53
+ nativeEvent
54
+ }) => {
55
+ if (nativeEvent.tipId !== tipId) return;
56
+ group?.complete(tipId);
57
+ onInvalidated?.({
58
+ reason: nativeEvent.reason
59
+ });
60
+ },
49
61
  onTipError: ({
50
62
  nativeEvent
51
63
  }) => {
@@ -1 +1 @@
1
- {"version":3,"names":["forwardRef","assertComponentEnabled","NativeTipView","validateTip","jsx","_jsx","View","TipViewRoot","props","ref","tipId","title","message","systemImage","actions","enabled","maxDisplayCount","ignoresDisplayFrequency","arrowEdge","onActionPress","onError","viewProps","children","undefined","collapsable","onTipAction","nativeEvent","id","onTipError","error","code","console","warn","displayName"],"sourceRoot":"../../../src","sources":["TipKit/View.tsx"],"mappings":";;AAAA,SAASA,UAAU,QAA2B,OAAO;AAGrD,SAASC,sBAAsB,QAAQ,mBAAU;AACjD,OAAOC,aAAa,MAAM,0BAA0B;AAEpD,SAASC,WAAW,QAAQ,iBAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAE3C,OAAO,MAAMC,IAAI,gBAAGN,UAAU,CAG5B,SAASO,WAAWA,CAACC,KAAK,EAAEC,GAAG,EAAE;EACjCR,sBAAsB,CAAC,QAAQ,CAAC;EAChCE,WAAW,CAACK,KAAK,EAAE,aAAa,CAAC;EACjC,MAAM;IACJE,KAAK;IACLC,KAAK;IACLC,OAAO;IACPC,WAAW;IACXC,OAAO;IACPC,OAAO,GAAG,IAAI;IACdC,eAAe;IACfC,uBAAuB,GAAG,KAAK;IAC/BC,SAAS,GAAG,MAAM;IAClBC,aAAa;IACbC,OAAO;IACP,GAAGC;EACL,CAAC,GAAGb,KAAK;EAET,oBACEH,IAAA,CAACH,aAAa;IAAA,GACRmB,SAAS;IACbC,QAAQ,EAAEC,SAAU;IACpBd,GAAG,EAAEA,GAAI;IACTe,WAAW,EAAE,KAAM;IACnBd,KAAK,EAAEA,KAAM;IACbC,KAAK,EAAEA,KAAM;IACbC,OAAO,EAAEA,OAAQ;IACjBC,WAAW,EAAEA,WAAY;IACzBC,OAAO,EAAEA,OAAQ;IACjBC,OAAO,EAAEA,OAAQ;IACjBC,eAAe,EAAEA,eAAe,IAAI,CAAE;IACtCC,uBAAuB,EAAEA,uBAAwB;IACjDC,SAAS,EAAEA,SAAU;IACrBO,WAAW,EAAEA,CAAC;MAAEC;IAAY,CAAC,KAAK;MAChC,IAAIA,WAAW,CAAChB,KAAK,KAAKA,KAAK,EAAE;QAC/BS,aAAa,GAAG;UAAEQ,EAAE,EAAED,WAAW,CAACC,EAAE;UAAEhB,KAAK,EAAEe,WAAW,CAACf;QAAM,CAAC,CAAC;MACnE;IACF,CAAE;IACFiB,UAAU,EAAEA,CAAC;MAAEF;IAAY,CAAC,KAAK;MAC/B,IAAIA,WAAW,CAAChB,KAAK,KAAKA,KAAK,EAAE;MACjC,MAAMmB,KAAK,GAAG;QACZC,IAAI,EAAEJ,WAAW,CAACI,IAAI;QACtBlB,OAAO,EAAEc,WAAW,CAACd;MACvB,CAAC;MACD,IAAIQ,OAAO,EAAEA,OAAO,CAACS,KAAK,CAAC,CAAC,KAE1BE,OAAO,CAACC,IAAI,CAAC,wBAAwBH,KAAK,CAACC,IAAI,KAAKD,KAAK,CAACjB,OAAO,EAAE,CAAC;IACxE;EAAE,CACH,CAAC;AAEN,CAAC,CAAC;AAEFN,IAAI,CAAC2B,WAAW,GAAG,aAAa","ignoreList":[]}
1
+ {"version":3,"names":["forwardRef","assertComponentEnabled","NativeTipView","validateTip","useTipGroup","jsx","_jsx","View","TipViewRoot","props","ref","group","tipId","title","message","systemImage","actions","enabled","maxDisplayCount","ignoresDisplayFrequency","arrowEdge","onActionPress","onInvalidated","onError","viewProps","children","undefined","collapsable","currentTipId","onTipAction","nativeEvent","id","onTipInvalidated","complete","reason","onTipError","error","code","console","warn","displayName"],"sourceRoot":"../../../src","sources":["TipKit/View.tsx"],"mappings":";;AAAA,SAASA,UAAU,QAA2B,OAAO;AAGrD,SAASC,sBAAsB,QAAQ,mBAAU;AACjD,OAAOC,aAAa,MAAM,0BAA0B;AAEpD,SAASC,WAAW,QAAQ,iBAAc;AAC1C,SAASC,WAAW,QAAQ,YAAS;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAEtC,OAAO,MAAMC,IAAI,gBAAGP,UAAU,CAG5B,SAASQ,WAAWA,CAACC,KAAK,EAAEC,GAAG,EAAE;EACjCT,sBAAsB,CAAC,QAAQ,CAAC;EAChCE,WAAW,CAACM,KAAK,EAAE,aAAa,CAAC;EACjC,MAAME,KAAK,GAAGP,WAAW,CAACK,KAAK,CAACG,KAAK,CAAC;EACtC,MAAM;IACJA,KAAK;IACLC,KAAK;IACLC,OAAO;IACPC,WAAW;IACXC,OAAO;IACPC,OAAO,GAAG,IAAI;IACdC,eAAe;IACfC,uBAAuB,GAAG,KAAK;IAC/BC,SAAS,GAAG,MAAM;IAClBC,aAAa;IACbC,aAAa;IACbC,OAAO;IACP,GAAGC;EACL,CAAC,GAAGf,KAAK;EAET,oBACEH,IAAA,CAACJ,aAAa;IAAA,GACRsB,SAAS;IACbC,QAAQ,EAAEC,SAAU;IACpBhB,GAAG,EAAEA,GAAI;IACTiB,WAAW,EAAE,KAAM;IACnBf,KAAK,EAAEA,KAAM;IACbC,KAAK,EAAEA,KAAM;IACbC,OAAO,EAAEA,OAAQ;IACjBC,WAAW,EAAEA,WAAY;IACzBC,OAAO,EAAEA,OAAQ;IACjBC,OAAO,EACLA,OAAO,KAAK,CAACN,KAAK,IAAKA,KAAK,CAACM,OAAO,IAAIN,KAAK,CAACiB,YAAY,KAAKhB,KAAM,CACtE;IACDM,eAAe,EAAEA,eAAe,IAAI,CAAE;IACtCC,uBAAuB,EAAEA,uBAAwB;IACjDC,SAAS,EAAEA,SAAU;IACrBS,WAAW,EAAEA,CAAC;MAAEC;IAAY,CAAC,KAAK;MAChC,IAAIA,WAAW,CAAClB,KAAK,KAAKA,KAAK,EAAE;QAC/BS,aAAa,GAAG;UAAEU,EAAE,EAAED,WAAW,CAACC,EAAE;UAAElB,KAAK,EAAEiB,WAAW,CAACjB;QAAM,CAAC,CAAC;MACnE;IACF,CAAE;IACFmB,gBAAgB,EAAEA,CAAC;MAAEF;IAAY,CAAC,KAAK;MACrC,IAAIA,WAAW,CAAClB,KAAK,KAAKA,KAAK,EAAE;MACjCD,KAAK,EAAEsB,QAAQ,CAACrB,KAAK,CAAC;MACtBU,aAAa,GAAG;QACdY,MAAM,EAAEJ,WAAW,CAACI;MACtB,CAAC,CAAC;IACJ,CAAE;IACFC,UAAU,EAAEA,CAAC;MAAEL;IAAY,CAAC,KAAK;MAC/B,IAAIA,WAAW,CAAClB,KAAK,KAAKA,KAAK,EAAE;MACjC,MAAMwB,KAAK,GAAG;QACZC,IAAI,EAAEP,WAAW,CAACO,IAAI;QACtBvB,OAAO,EAAEgB,WAAW,CAAChB;MACvB,CAAC;MACD,IAAIS,OAAO,EAAEA,OAAO,CAACa,KAAK,CAAC,CAAC,KAE1BE,OAAO,CAACC,IAAI,CAAC,wBAAwBH,KAAK,CAACC,IAAI,KAAKD,KAAK,CAACtB,OAAO,EAAE,CAAC;IACxE;EAAE,CACH,CAAC;AAEN,CAAC,CAAC;AAEFP,IAAI,CAACiC,WAAW,GAAG,aAAa","ignoreList":[]}
@@ -4,7 +4,9 @@ import { assertComponentEnabled, getNativeTinyui } from "../utils/index.js";
4
4
  import { validateTipId } from "./validation.js";
5
5
  import { Popover } from "./Popover.js";
6
6
  import { View } from "./View.js";
7
+ import { Group } from "./Group.js";
7
8
  export const TipKit = {
9
+ Group,
8
10
  Popover,
9
11
  View,
10
12
  /**
@@ -1 +1 @@
1
- {"version":3,"names":["assertComponentEnabled","getNativeTinyui","validateTipId","Popover","View","TipKit","resetDatastore","resetTipsDatastore","configure","displayFrequency","includes","Error","configureTips","invalidate","tipId","reason","invalidateTip"],"sourceRoot":"../../../src","sources":["TipKit/index.ts"],"mappings":";;AAAA,SAASA,sBAAsB,EAAEC,eAAe,QAAQ,mBAAU;AAElE,SAASC,aAAa,QAAQ,iBAAc;AAC5C,SAASC,OAAO,QAAQ,cAAW;AACnC,SAASC,IAAI,QAAQ,WAAQ;AAE7B,OAAO,MAAMC,MAAM,GAAG;EACpBF,OAAO;EACPC,IAAI;EACJ;AACF;AACA;AACA;AACA;EACE,MAAME,cAAcA,CAAA,EAAkB;IACpCN,sBAAsB,CAAC,QAAQ,CAAC;IAChC,MAAMC,eAAe,CAAC,CAAC,CAACM,kBAAkB,CAAC,CAAC;EAC9C,CAAC;EAED;EACA,MAAMC,SAASA,CAAC;IACdC,gBAAgB,GAAG;EACA,CAAC,GAAG,CAAC,CAAC,EAAiB;IAC1CT,sBAAsB,CAAC,QAAQ,CAAC;IAChC,IACE,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAACU,QAAQ,CAC7DD,gBACF,CAAC,EACD;MACA,MAAM,IAAIE,KAAK,CACb,iEACF,CAAC;IACH;IACA,MAAMV,eAAe,CAAC,CAAC,CAACW,aAAa,CAACH,gBAAgB,CAAC;EACzD,CAAC;EAED;EACA,MAAMI,UAAUA,CACdC,KAAa,EACbC,MAA6B,GAAG,iBAAiB,EAClC;IACff,sBAAsB,CAAC,QAAQ,CAAC;IAChCE,aAAa,CAACY,KAAK,CAAC;IACpB,IAAIC,MAAM,KAAK,iBAAiB,IAAIA,MAAM,KAAK,WAAW,EAAE;MAC1D,MAAM,IAAIJ,KAAK,CAAC,wDAAwD,CAAC;IAC3E;IACA,MAAMV,eAAe,CAAC,CAAC,CAACe,aAAa,CAACF,KAAK,EAAEC,MAAM,CAAC;EACtD;AACF,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["assertComponentEnabled","getNativeTinyui","validateTipId","Popover","View","Group","TipKit","resetDatastore","resetTipsDatastore","configure","displayFrequency","includes","Error","configureTips","invalidate","tipId","reason","invalidateTip"],"sourceRoot":"../../../src","sources":["TipKit/index.ts"],"mappings":";;AAAA,SAASA,sBAAsB,EAAEC,eAAe,QAAQ,mBAAU;AAElE,SAASC,aAAa,QAAQ,iBAAc;AAC5C,SAASC,OAAO,QAAQ,cAAW;AACnC,SAASC,IAAI,QAAQ,WAAQ;AAC7B,SAASC,KAAK,QAAQ,YAAS;AAE/B,OAAO,MAAMC,MAAM,GAAG;EACpBD,KAAK;EACLF,OAAO;EACPC,IAAI;EACJ;AACF;AACA;AACA;AACA;EACE,MAAMG,cAAcA,CAAA,EAAkB;IACpCP,sBAAsB,CAAC,QAAQ,CAAC;IAChC,MAAMC,eAAe,CAAC,CAAC,CAACO,kBAAkB,CAAC,CAAC;EAC9C,CAAC;EAED;EACA,MAAMC,SAASA,CAAC;IACdC,gBAAgB,GAAG;EACA,CAAC,GAAG,CAAC,CAAC,EAAiB;IAC1CV,sBAAsB,CAAC,QAAQ,CAAC;IAChC,IACE,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAACW,QAAQ,CAC7DD,gBACF,CAAC,EACD;MACA,MAAM,IAAIE,KAAK,CACb,iEACF,CAAC;IACH;IACA,MAAMX,eAAe,CAAC,CAAC,CAACY,aAAa,CAACH,gBAAgB,CAAC;EACzD,CAAC;EAED;EACA,MAAMI,UAAUA,CACdC,KAAa,EACbC,MAA6B,GAAG,iBAAiB,EAClC;IACfhB,sBAAsB,CAAC,QAAQ,CAAC;IAChCE,aAAa,CAACa,KAAK,CAAC;IACpB,IAAIC,MAAM,KAAK,iBAAiB,IAAIA,MAAM,KAAK,WAAW,EAAE;MAC1D,MAAM,IAAIJ,KAAK,CAAC,wDAAwD,CAAC;IAC3E;IACA,MAAMX,eAAe,CAAC,CAAC,CAACgB,aAAa,CAACF,KAAK,EAAEC,MAAM,CAAC;EACtD;AACF,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["Menu","SwipeActions","TipKit","Stepper","ConcentricView","SFSymbol","Popover","PopoverClose","getNativeTinyui","assertComponentEnabled","LiquidGlassText"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,IAAI,QAAQ,iBAAQ;AAC7B,SAASC,YAAY,QAAQ,yBAAgB;AAO7C,SAASC,MAAM,QAAQ,mBAAU;AAuBjC,SAASC,OAAO,QAAQ,oBAAW;AAGnC,SAASC,cAAc,QAAQ,2BAAkB;AAGjD,SAASC,QAAQ,QAAQ,qBAAY;AAWrC,SAASC,OAAO,EAAEC,YAAY,QAAQ,oBAAW;AAUjD,SAASC,eAAe,EAAEC,sBAAsB,QAAQ,kBAAS;AAGjE,SAASC,eAAe,QAAQ,4BAAmB","ignoreList":[]}
1
+ {"version":3,"names":["Menu","SwipeActions","TipKit","Stepper","ConcentricView","SFSymbol","Popover","PopoverClose","getNativeTinyui","assertComponentEnabled","LiquidGlassText"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,IAAI,QAAQ,iBAAQ;AAC7B,SAASC,YAAY,QAAQ,yBAAgB;AAO7C,SAASC,MAAM,QAAQ,mBAAU;AAyBjC,SAASC,OAAO,QAAQ,oBAAW;AAGnC,SAASC,cAAc,QAAQ,2BAAkB;AAGjD,SAASC,QAAQ,QAAQ,qBAAY;AAWrC,SAASC,OAAO,EAAEC,YAAY,QAAQ,oBAAW;AAUjD,SAASC,eAAe,EAAEC,sBAAsB,QAAQ,kBAAS;AAGjE,SAASC,eAAe,QAAQ,4BAAmB","ignoreList":[]}
@@ -0,0 +1,13 @@
1
+ import type { TipGroupProps } from './types.js';
2
+ interface GroupContextValue {
3
+ tipIds: ReadonlySet<string>;
4
+ currentTipId: string | undefined;
5
+ enabled: boolean;
6
+ invalidateOnOutsideDismiss: boolean;
7
+ complete: (tipId: string) => void;
8
+ }
9
+ /** Orders tips by ID while native TipKit owns eligibility and persisted history. */
10
+ export declare function Group({ tipIds, priority, enabled, invalidateOnOutsideDismiss, children, }: TipGroupProps): import("react").JSX.Element;
11
+ export declare function useTipGroup(tipId: string): GroupContextValue | null;
12
+ export {};
13
+ //# sourceMappingURL=Group.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Group.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/Group.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAS,CAAC;AAG7C,UAAU,iBAAiB;IACzB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,0BAA0B,EAAE,OAAO,CAAC;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAID,oFAAoF;AACpF,wBAAgB,KAAK,CAAC,EACpB,MAAM,EACN,QAAoB,EACpB,OAAc,EACd,0BAAkC,EAClC,QAAQ,GACT,EAAE,aAAa,+BAoCf;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,4BAQxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/Popover.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAS,CAAC;AAG/C,eAAO,MAAM,OAAO,6LAwDnB,CAAC"}
1
+ {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/Popover.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAwB,MAAM,YAAS,CAAC;AAIrE,eAAO,MAAM,OAAO,6LAqEnB,CAAC"}
@@ -10,6 +10,7 @@ export interface NativeTipPopoverProps extends ViewProps {
10
10
  title: string;
11
11
  }>>;
12
12
  enabled?: boolean;
13
+ invalidateOnOutsideDismiss?: boolean;
13
14
  maxDisplayCount?: CodegenTypes.Int32;
14
15
  ignoresDisplayFrequency?: boolean;
15
16
  arrowEdge?: string;
@@ -23,6 +24,10 @@ export interface NativeTipPopoverProps extends ViewProps {
23
24
  code: string;
24
25
  message: string;
25
26
  }>>;
27
+ onTipInvalidated?: DirectEventHandler<Readonly<{
28
+ tipId: string;
29
+ reason: string;
30
+ }>>;
26
31
  }
27
32
  declare const _default: import("react-native/types_generated/Libraries/Utilities/codegenNativeComponent").NativeComponentType<NativeTipPopoverProps>;
28
33
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"TipPopoverNativeComponent.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/TipPopoverNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAEpF,MAAM,WAAW,qBAAsB,SAAQ,SAAS;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC;IACrC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,kBAAkB,CAC9B,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CACvD,CAAC;IACF,UAAU,CAAC,EAAE,kBAAkB,CAC7B,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAC3D,CAAC;CACH;;AAED,wBAKE"}
1
+ {"version":3,"file":"TipPopoverNativeComponent.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/TipPopoverNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAEpF,MAAM,WAAW,qBAAsB,SAAQ,SAAS;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,eAAe,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC;IACrC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,kBAAkB,CAC9B,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CACvD,CAAC;IACF,UAAU,CAAC,EAAE,kBAAkB,CAC7B,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAC3D,CAAC;IACF,gBAAgB,CAAC,EAAE,kBAAkB,CACnC,QAAQ,CAAC;QACP,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CACH,CAAC;CACH;;AAED,wBAKE"}
@@ -23,6 +23,10 @@ export interface NativeTipViewProps extends ViewProps {
23
23
  code: string;
24
24
  message: string;
25
25
  }>>;
26
+ onTipInvalidated?: DirectEventHandler<Readonly<{
27
+ tipId: string;
28
+ reason: string;
29
+ }>>;
26
30
  }
27
31
  declare const _default: import("react-native/types_generated/Libraries/Utilities/codegenNativeComponent").NativeComponentType<NativeTipViewProps>;
28
32
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"TipViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/TipViewNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAEpF,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC;IACrC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,kBAAkB,CAC9B,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CACvD,CAAC;IACF,UAAU,CAAC,EAAE,kBAAkB,CAC7B,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAC3D,CAAC;CACH;;AAED,wBAEG"}
1
+ {"version":3,"file":"TipViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/TipViewNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAEpF,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC;IACrC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,kBAAkB,CAC9B,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CACvD,CAAC;IACF,UAAU,CAAC,EAAE,kBAAkB,CAC7B,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAC3D,CAAC;IACF,gBAAgB,CAAC,EAAE,kBAAkB,CACnC,QAAQ,CAAC;QACP,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CACH,CAAC;CACH;;AAED,wBAEG"}
@@ -1 +1 @@
1
- {"version":3,"file":"View.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/View.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAS,CAAC;AAG5C,eAAO,MAAM,IAAI,0LAqDf,CAAC"}
1
+ {"version":3,"file":"View.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/View.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAwB,MAAM,YAAS,CAAC;AAIlE,eAAO,MAAM,IAAI,0LAgEf,CAAC"}
@@ -1,5 +1,7 @@
1
1
  import type { TipInvalidationReason, TipKitConfiguration } from './types.js';
2
+ import { Group } from './Group.js';
2
3
  export declare const TipKit: {
4
+ Group: typeof Group;
3
5
  Popover: import("react").ForwardRefExoticComponent<import("./types.js").TipPopoverProps & import("react").RefAttributes<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>>;
4
6
  View: import("react").ForwardRefExoticComponent<import("./types.js").TipViewProps & import("react").RefAttributes<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>>;
5
7
  /**
@@ -13,5 +15,5 @@ export declare const TipKit: {
13
15
  /** Persistently invalidate a tip, including when its view is not mounted. */
14
16
  invalidate(tipId: string, reason?: TipInvalidationReason): Promise<void>;
15
17
  };
16
- export type { TipAction, TipDisplayFrequency, TipError, TipInvalidationReason, TipKitConfiguration, TipPopoverProps, TipViewProps, } from './types.js';
18
+ export type { TipAction, TipDisplayFrequency, TipError, TipInvalidationReason, TipInvalidationEvent, TipGroupProps, TipKitConfiguration, TipPopoverProps, TipViewProps, } from './types.js';
17
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,YAAS,CAAC;AAK1E,eAAO,MAAM,MAAM;;;IAGjB;;;;OAIG;sBACqB,OAAO,CAAC,IAAI,CAAC;IAKrC,sFAAsF;sCAGnF,mBAAmB,GAAQ,OAAO,CAAC,IAAI,CAAC;IAc3C,6EAA6E;sBAEpE,MAAM,WACL,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC;CAQjB,CAAC;AAEF,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,YAAY,GACb,MAAM,YAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,YAAS,CAAC;AAI1E,OAAO,EAAE,KAAK,EAAE,MAAM,YAAS,CAAC;AAEhC,eAAO,MAAM,MAAM;;;;IAIjB;;;;OAIG;sBACqB,OAAO,CAAC,IAAI,CAAC;IAKrC,sFAAsF;sCAGnF,mBAAmB,GAAQ,OAAO,CAAC,IAAI,CAAC;IAc3C,6EAA6E;sBAEpE,MAAM,WACL,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC;CAQjB,CAAC;AAEF,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,YAAY,GACb,MAAM,YAAS,CAAC"}
@@ -6,6 +6,20 @@ export interface TipKitConfiguration {
6
6
  displayFrequency?: TipDisplayFrequency;
7
7
  }
8
8
  export type TipInvalidationReason = 'actionPerformed' | 'tipClosed';
9
+ export interface TipInvalidationEvent {
10
+ reason: TipInvalidationReason | 'displayCountExceeded' | 'displayDurationExceeded' | 'unknown';
11
+ }
12
+ export interface TipGroupProps {
13
+ /** Stable tip IDs in presentation order, independent of the layout tree. */
14
+ tipIds: readonly string[];
15
+ /** Currently only ordered presentation is supported. Defaults to ordered. */
16
+ priority?: 'ordered';
17
+ /** Pause all tips in this group without completing them. Defaults to true. */
18
+ enabled?: boolean;
19
+ /** Treat tapping outside a popover as completion. Defaults to false. */
20
+ invalidateOnOutsideDismiss?: boolean;
21
+ children: ReactNode;
22
+ }
9
23
  export interface TipAction {
10
24
  /** Unique nonempty identity within this tip, returned by `onActionPress`. */
11
25
  id: string;
@@ -31,9 +45,13 @@ export interface TipContentProps extends Omit<ViewProps, 'children'> {
31
45
  ignoresDisplayFrequency?: boolean;
32
46
  /** Receives the tapped button's id and title; does not automatically invalidate the tip. */
33
47
  onActionPress?: (action: TipAction) => void;
48
+ /** Called for native invalidation, including persisted invalidation on mount. */
49
+ onInvalidated?: (event: TipInvalidationEvent) => void;
34
50
  onError?: (error: TipError) => void;
35
51
  }
36
52
  export interface TipPopoverProps extends TipContentProps {
53
+ /** Invalidate on outside dismissal. Inherits from Group; otherwise false. */
54
+ invalidateOnOutsideDismiss?: boolean;
37
55
  /** Anchor content. Its existing touch handlers are preserved. */
38
56
  children: ReactNode;
39
57
  /** Preferred arrow edge on the bubble; UIKit may adapt to available space. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,mBAAmB,GAC7B,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IAClC,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,GAAG,WAAW,CAAC;AAEpE,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAClE,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC/B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,4FAA4F;IAC5F,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,iEAAiE;IACjE,QAAQ,EAAE,SAAS,CAAC;IACpB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CAChE;AAED,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,yEAAyE;IACzE,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CAChE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/TipKit/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,mBAAmB,GAC7B,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IAClC,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,GAAG,WAAW,CAAC;AAEpE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EACF,qBAAqB,GACrB,sBAAsB,GACtB,yBAAyB,GACzB,SAAS,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAClE,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC/B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,4FAA4F;IAC5F,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;IAC5C,iFAAiF;IACjF,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACtD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,6EAA6E;IAC7E,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,iEAAiE;IACjE,QAAQ,EAAE,SAAS,CAAC;IACpB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CAChE;AAED,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,yEAAyE;IACzE,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CAChE"}
@@ -2,7 +2,7 @@ export { Menu } from './Menu/index.js';
2
2
  export { SwipeActions } from './SwipeActions/index.js';
3
3
  export type { SwipeAction, SwipeActionPressEvent, SwipeActionsEdge, SwipeActionsProps, } from './SwipeActions/index.js';
4
4
  export { TipKit } from './TipKit/index.js';
5
- export type { TipAction, TipDisplayFrequency, TipError, TipInvalidationReason, TipPopoverProps, TipViewProps, TipKitConfiguration, } from './TipKit/index.js';
5
+ export type { TipAction, TipDisplayFrequency, TipError, TipInvalidationReason, TipInvalidationEvent, TipGroupProps, TipPopoverProps, TipViewProps, TipKitConfiguration, } from './TipKit/index.js';
6
6
  export type { MenuActionOption, MenuActionPressEvent, MenuActionPressEventData, MenuDividerOption, MenuItemState, MenuOption, MenuProps, MenuRef, MenuSectionOption, MenuSubmenuOption, } from './Menu/index.js';
7
7
  export { Stepper } from './Stepper/index.js';
8
8
  export type { StepperProps } from './Stepper/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAgB,CAAC;AAC9C,YAAY,EACV,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,yBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAU,CAAC;AAClC,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,mBAAmB,GACpB,MAAM,mBAAU,CAAC;AAClB,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,SAAS,EACT,OAAO,EACP,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,iBAAQ,CAAC;AAEhB,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAW,CAAC;AACpC,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAW,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAAkB,CAAC;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAY,CAAC;AACtC,YAAY,EACV,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,cAAc,GACf,MAAM,qBAAY,CAAC;AAEpB,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAW,CAAC;AAClD,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,YAAY,GACb,MAAM,oBAAW,CAAC;AAEnB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAS,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAS,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAAmB,CAAC;AACpD,YAAY,EACV,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,4BAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAgB,CAAC;AAC9C,YAAY,EACV,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,yBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAU,CAAC;AAClC,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,mBAAmB,GACpB,MAAM,mBAAU,CAAC;AAClB,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,SAAS,EACT,OAAO,EACP,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,iBAAQ,CAAC;AAEhB,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAW,CAAC;AACpC,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAW,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAAkB,CAAC;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAY,CAAC;AACtC,YAAY,EACV,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,cAAc,GACf,MAAM,qBAAY,CAAC;AAEpB,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAW,CAAC;AAClD,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,YAAY,GACb,MAAM,oBAAW,CAAC;AAEnB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAS,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAS,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAAmB,CAAC;AACpD,YAAY,EACV,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,4BAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-tinyui",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Dependency-free native iOS Menu, SwipeActions, Popover, TipKit, Stepper, ConcentricView, SFSymbol and LiquidGlassText components for React Native",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -0,0 +1,76 @@
1
+ import {
2
+ createContext,
3
+ useCallback,
4
+ useContext,
5
+ useMemo,
6
+ useState,
7
+ } from 'react';
8
+
9
+ import { assertComponentEnabled } from '../utils';
10
+ import type { TipGroupProps } from './types';
11
+ import { validateTipId } from './validation';
12
+
13
+ interface GroupContextValue {
14
+ tipIds: ReadonlySet<string>;
15
+ currentTipId: string | undefined;
16
+ enabled: boolean;
17
+ invalidateOnOutsideDismiss: boolean;
18
+ complete: (tipId: string) => void;
19
+ }
20
+
21
+ const GroupContext = createContext<GroupContextValue | null>(null);
22
+
23
+ /** Orders tips by ID while native TipKit owns eligibility and persisted history. */
24
+ export function Group({
25
+ tipIds,
26
+ priority = 'ordered',
27
+ enabled = true,
28
+ invalidateOnOutsideDismiss = false,
29
+ children,
30
+ }: TipGroupProps) {
31
+ assertComponentEnabled('TipKit');
32
+ if (priority !== 'ordered') {
33
+ throw new Error('[TinyUI] TipKit.Group only supports ordered priority.');
34
+ }
35
+ const ids = new Set<string>();
36
+ for (const tipId of tipIds) {
37
+ validateTipId(tipId);
38
+ if (ids.has(tipId)) {
39
+ throw new Error('[TinyUI] TipKit.Group tipIds must be unique.');
40
+ }
41
+ ids.add(tipId);
42
+ }
43
+
44
+ const [completed, setCompleted] = useState<ReadonlySet<string>>(
45
+ () => new Set()
46
+ );
47
+ const complete = useCallback((tipId: string) => {
48
+ setCompleted((previous) =>
49
+ previous.has(tipId) ? previous : new Set([...previous, tipId])
50
+ );
51
+ }, []);
52
+ const value = useMemo(
53
+ () => ({
54
+ tipIds: new Set(tipIds),
55
+ currentTipId: tipIds.find((id) => !completed.has(id)),
56
+ enabled,
57
+ invalidateOnOutsideDismiss,
58
+ complete,
59
+ }),
60
+ [tipIds, completed, enabled, invalidateOnOutsideDismiss, complete]
61
+ );
62
+
63
+ return (
64
+ <GroupContext.Provider value={value}>{children}</GroupContext.Provider>
65
+ );
66
+ }
67
+
68
+ export function useTipGroup(tipId: string) {
69
+ const group = useContext(GroupContext);
70
+ if (group && !group.tipIds.has(tipId)) {
71
+ throw new Error(
72
+ `[TinyUI] TipKit tipId "${tipId}" is missing from its Group's tipIds.`
73
+ );
74
+ }
75
+ return group;
76
+ }
@@ -3,13 +3,15 @@ import { View } from 'react-native';
3
3
 
4
4
  import { assertComponentEnabled } from '../utils';
5
5
  import NativeTipPopoverView from './TipPopoverNativeComponent';
6
- import type { TipPopoverProps } from './types';
6
+ import type { TipPopoverProps, TipInvalidationEvent } from './types';
7
7
  import { validateTip } from './validation';
8
+ import { useTipGroup } from './Group';
8
9
 
9
10
  export const Popover = forwardRef<ComponentRef<typeof View>, TipPopoverProps>(
10
11
  function TipPopoverRoot(props, ref) {
11
12
  assertComponentEnabled('TipKit');
12
13
  validateTip(props);
14
+ const group = useTipGroup(props.tipId);
13
15
  const {
14
16
  children,
15
17
  tipId,
@@ -22,6 +24,8 @@ export const Popover = forwardRef<ComponentRef<typeof View>, TipPopoverProps>(
22
24
  ignoresDisplayFrequency = false,
23
25
  arrowEdge = 'auto',
24
26
  onActionPress,
27
+ onInvalidated,
28
+ invalidateOnOutsideDismiss = group?.invalidateOnOutsideDismiss ?? false,
25
29
  onError,
26
30
  ...viewProps
27
31
  } = props;
@@ -36,7 +40,10 @@ export const Popover = forwardRef<ComponentRef<typeof View>, TipPopoverProps>(
36
40
  message={message}
37
41
  systemImage={systemImage}
38
42
  actions={actions}
39
- enabled={enabled}
43
+ enabled={
44
+ enabled && (!group || (group.enabled && group.currentTipId === tipId))
45
+ }
46
+ invalidateOnOutsideDismiss={invalidateOnOutsideDismiss}
40
47
  maxDisplayCount={maxDisplayCount ?? 0}
41
48
  ignoresDisplayFrequency={ignoresDisplayFrequency}
42
49
  arrowEdge={arrowEdge}
@@ -45,6 +52,13 @@ export const Popover = forwardRef<ComponentRef<typeof View>, TipPopoverProps>(
45
52
  onActionPress?.({ id: nativeEvent.id, title: nativeEvent.title });
46
53
  }
47
54
  }}
55
+ onTipInvalidated={({ nativeEvent }) => {
56
+ if (nativeEvent.tipId !== tipId) return;
57
+ group?.complete(tipId);
58
+ onInvalidated?.({
59
+ reason: nativeEvent.reason as TipInvalidationEvent['reason'],
60
+ });
61
+ }}
48
62
  onTipError={({ nativeEvent }) => {
49
63
  if (nativeEvent.tipId !== tipId) return;
50
64
  const error = {
@@ -12,6 +12,7 @@ export interface NativeTipPopoverProps extends ViewProps {
12
12
  systemImage?: string;
13
13
  actions?: ReadonlyArray<Readonly<{ id: string; title: string }>>;
14
14
  enabled?: boolean;
15
+ invalidateOnOutsideDismiss?: boolean;
15
16
  maxDisplayCount?: CodegenTypes.Int32;
16
17
  ignoresDisplayFrequency?: boolean;
17
18
  arrowEdge?: string;
@@ -21,6 +22,12 @@ export interface NativeTipPopoverProps extends ViewProps {
21
22
  onTipError?: DirectEventHandler<
22
23
  Readonly<{ tipId: string; code: string; message: string }>
23
24
  >;
25
+ onTipInvalidated?: DirectEventHandler<
26
+ Readonly<{
27
+ tipId: string;
28
+ reason: string;
29
+ }>
30
+ >;
24
31
  }
25
32
 
26
33
  export default codegenNativeComponent<NativeTipPopoverProps>(
@@ -21,6 +21,12 @@ export interface NativeTipViewProps extends ViewProps {
21
21
  onTipError?: DirectEventHandler<
22
22
  Readonly<{ tipId: string; code: string; message: string }>
23
23
  >;
24
+ onTipInvalidated?: DirectEventHandler<
25
+ Readonly<{
26
+ tipId: string;
27
+ reason: string;
28
+ }>
29
+ >;
24
30
  }
25
31
 
26
32
  export default codegenNativeComponent<NativeTipViewProps>('TinyuiTipView', {
@@ -3,8 +3,9 @@ import type { View as ReactNativeView } from 'react-native';
3
3
 
4
4
  import { assertComponentEnabled } from '../utils';
5
5
  import NativeTipView from './TipViewNativeComponent';
6
- import type { TipViewProps } from './types';
6
+ import type { TipViewProps, TipInvalidationEvent } from './types';
7
7
  import { validateTip } from './validation';
8
+ import { useTipGroup } from './Group';
8
9
 
9
10
  export const View = forwardRef<
10
11
  ComponentRef<typeof ReactNativeView>,
@@ -12,6 +13,7 @@ export const View = forwardRef<
12
13
  >(function TipViewRoot(props, ref) {
13
14
  assertComponentEnabled('TipKit');
14
15
  validateTip(props, 'TipKit.View');
16
+ const group = useTipGroup(props.tipId);
15
17
  const {
16
18
  tipId,
17
19
  title,
@@ -23,6 +25,7 @@ export const View = forwardRef<
23
25
  ignoresDisplayFrequency = false,
24
26
  arrowEdge = 'none',
25
27
  onActionPress,
28
+ onInvalidated,
26
29
  onError,
27
30
  ...viewProps
28
31
  } = props;
@@ -38,7 +41,9 @@ export const View = forwardRef<
38
41
  message={message}
39
42
  systemImage={systemImage}
40
43
  actions={actions}
41
- enabled={enabled}
44
+ enabled={
45
+ enabled && (!group || (group.enabled && group.currentTipId === tipId))
46
+ }
42
47
  maxDisplayCount={maxDisplayCount ?? 0}
43
48
  ignoresDisplayFrequency={ignoresDisplayFrequency}
44
49
  arrowEdge={arrowEdge}
@@ -47,6 +52,13 @@ export const View = forwardRef<
47
52
  onActionPress?.({ id: nativeEvent.id, title: nativeEvent.title });
48
53
  }
49
54
  }}
55
+ onTipInvalidated={({ nativeEvent }) => {
56
+ if (nativeEvent.tipId !== tipId) return;
57
+ group?.complete(tipId);
58
+ onInvalidated?.({
59
+ reason: nativeEvent.reason as TipInvalidationEvent['reason'],
60
+ });
61
+ }}
50
62
  onTipError={({ nativeEvent }) => {
51
63
  if (nativeEvent.tipId !== tipId) return;
52
64
  const error = {
@@ -3,8 +3,10 @@ import type { TipInvalidationReason, TipKitConfiguration } from './types';
3
3
  import { validateTipId } from './validation';
4
4
  import { Popover } from './Popover';
5
5
  import { View } from './View';
6
+ import { Group } from './Group';
6
7
 
7
8
  export const TipKit = {
9
+ Group,
8
10
  Popover,
9
11
  View,
10
12
  /**
@@ -53,6 +55,8 @@ export type {
53
55
  TipDisplayFrequency,
54
56
  TipError,
55
57
  TipInvalidationReason,
58
+ TipInvalidationEvent,
59
+ TipGroupProps,
56
60
  TipKitConfiguration,
57
61
  TipPopoverProps,
58
62
  TipViewProps,
@@ -11,6 +11,26 @@ export interface TipKitConfiguration {
11
11
 
12
12
  export type TipInvalidationReason = 'actionPerformed' | 'tipClosed';
13
13
 
14
+ export interface TipInvalidationEvent {
15
+ reason:
16
+ | TipInvalidationReason
17
+ | 'displayCountExceeded'
18
+ | 'displayDurationExceeded'
19
+ | 'unknown';
20
+ }
21
+
22
+ export interface TipGroupProps {
23
+ /** Stable tip IDs in presentation order, independent of the layout tree. */
24
+ tipIds: readonly string[];
25
+ /** Currently only ordered presentation is supported. Defaults to ordered. */
26
+ priority?: 'ordered';
27
+ /** Pause all tips in this group without completing them. Defaults to true. */
28
+ enabled?: boolean;
29
+ /** Treat tapping outside a popover as completion. Defaults to false. */
30
+ invalidateOnOutsideDismiss?: boolean;
31
+ children: ReactNode;
32
+ }
33
+
14
34
  export interface TipAction {
15
35
  /** Unique nonempty identity within this tip, returned by `onActionPress`. */
16
36
  id: string;
@@ -38,10 +58,14 @@ export interface TipContentProps extends Omit<ViewProps, 'children'> {
38
58
  ignoresDisplayFrequency?: boolean;
39
59
  /** Receives the tapped button's id and title; does not automatically invalidate the tip. */
40
60
  onActionPress?: (action: TipAction) => void;
61
+ /** Called for native invalidation, including persisted invalidation on mount. */
62
+ onInvalidated?: (event: TipInvalidationEvent) => void;
41
63
  onError?: (error: TipError) => void;
42
64
  }
43
65
 
44
66
  export interface TipPopoverProps extends TipContentProps {
67
+ /** Invalidate on outside dismissal. Inherits from Group; otherwise false. */
68
+ invalidateOnOutsideDismiss?: boolean;
45
69
  /** Anchor content. Its existing touch handlers are preserved. */
46
70
  children: ReactNode;
47
71
  /** Preferred arrow edge on the bubble; UIKit may adapt to available space. */
package/src/index.tsx CHANGED
@@ -12,6 +12,8 @@ export type {
12
12
  TipDisplayFrequency,
13
13
  TipError,
14
14
  TipInvalidationReason,
15
+ TipInvalidationEvent,
16
+ TipGroupProps,
15
17
  TipPopoverProps,
16
18
  TipViewProps,
17
19
  TipKitConfiguration,