react-native-tinyui 3.0.0 → 3.1.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 (35) hide show
  1. package/README.md +60 -1
  2. package/ios/Core/Tinyui.mm +3 -0
  3. package/ios/Core/TinyuiComponentClasses.mm +11 -0
  4. package/ios/SwipeActions/TinyuiSwipeActionsView.h +12 -0
  5. package/ios/SwipeActions/TinyuiSwipeActionsView.mm +289 -0
  6. package/lib/module/SwipeActions/SwipeActionsNativeComponent.ts +19 -0
  7. package/lib/module/SwipeActions/actions.js +21 -0
  8. package/lib/module/SwipeActions/actions.js.map +1 -0
  9. package/lib/module/SwipeActions/index.js +43 -0
  10. package/lib/module/SwipeActions/index.js.map +1 -0
  11. package/lib/module/SwipeActions/types.js +4 -0
  12. package/lib/module/SwipeActions/types.js.map +1 -0
  13. package/lib/module/index.js +1 -0
  14. package/lib/module/index.js.map +1 -1
  15. package/lib/module/utils/getNativeTinyui.js.map +1 -1
  16. package/lib/typescript/src/SwipeActions/SwipeActionsNativeComponent.d.ts +15 -0
  17. package/lib/typescript/src/SwipeActions/SwipeActionsNativeComponent.d.ts.map +1 -0
  18. package/lib/typescript/src/SwipeActions/actions.d.ts +9 -0
  19. package/lib/typescript/src/SwipeActions/actions.d.ts.map +1 -0
  20. package/lib/typescript/src/SwipeActions/index.d.ts +4 -0
  21. package/lib/typescript/src/SwipeActions/index.d.ts.map +1 -0
  22. package/lib/typescript/src/SwipeActions/types.d.ts +37 -0
  23. package/lib/typescript/src/SwipeActions/types.d.ts.map +1 -0
  24. package/lib/typescript/src/index.d.ts +2 -0
  25. package/lib/typescript/src/index.d.ts.map +1 -1
  26. package/lib/typescript/src/utils/getNativeTinyui.d.ts +1 -1
  27. package/lib/typescript/src/utils/getNativeTinyui.d.ts.map +1 -1
  28. package/package.json +10 -2
  29. package/react-native-tinyui.podspec +6 -1
  30. package/src/SwipeActions/SwipeActionsNativeComponent.ts +19 -0
  31. package/src/SwipeActions/actions.ts +26 -0
  32. package/src/SwipeActions/index.tsx +54 -0
  33. package/src/SwipeActions/types.ts +37 -0
  34. package/src/index.tsx +7 -0
  35. package/src/utils/getNativeTinyui.ts +1 -0
package/README.md CHANGED
@@ -11,6 +11,7 @@ staying close to native APIs. It uses UIKit by default and SwiftUI where needed.
11
11
  | Component | What it does |
12
12
  | ---------------------------------- | -------------------------------------------------------------- |
13
13
  | [Menu](#menu) | Present native menus with actions, submenus, and sections |
14
+ | [SwipeActions](#swipeactions) | Reveal native action buttons by swiping React Native rows |
14
15
  | [Popover](#popover) | Show interactive React Native content in a native popover |
15
16
  | [TipKit](#tipkit) | Present contextual tips using Apple's TipKit framework |
16
17
  | [LiquidGlassText](#liquidglasstext) | Render text with native glass effects inside the glyphs |
@@ -75,6 +76,7 @@ use in your app's `package.json`:
75
76
  Available components:
76
77
 
77
78
  - `Menu`
79
+ - `SwipeActions`
78
80
  - `Popover`
79
81
  - `LiquidGlassText`
80
82
  - `Stepper`
@@ -107,6 +109,7 @@ Component-specific JavaScript entry points are also available:
107
109
 
108
110
  ```tsx
109
111
  import { Menu } from 'react-native-tinyui/menu';
112
+ import { SwipeActions } from 'react-native-tinyui/swipe-actions';
110
113
  import { Popover } from 'react-native-tinyui/popover';
111
114
  import { LiquidGlassText } from 'react-native-tinyui/liquid-glass-text';
112
115
  import { Stepper } from 'react-native-tinyui/stepper';
@@ -221,6 +224,62 @@ deprecated `titleColor` field is retained only for source compatibility; use
221
224
  `destructive` for system red styling. Submenus support the same label fields
222
225
  plus `destructive`, `disabled`, `hidden`, and `displayInline`.
223
226
 
227
+ ## SwipeActions
228
+
229
+ `SwipeActions` wraps React Native row content in a native, non-scrolling
230
+ `UITableView` row and uses `UISwipeActionsConfiguration`. It provides the edge
231
+ and full-swipe behavior of SwiftUI's
232
+ [`swipeActions`](https://developer.apple.com/documentation/swiftui/view/swipeactions(edge:allowsfullswipe:content:))
233
+ without requiring a SwiftUI `List`. Use it inside a `FlatList` or `ScrollView`;
234
+ Yoga measures the children, so a fixed row height is optional.
235
+
236
+ ```tsx
237
+ import { SwipeActions } from 'react-native-tinyui/swipe-actions';
238
+
239
+ <SwipeActions
240
+ edge="trailing"
241
+ allowsFullSwipe={false}
242
+ contentContainerStyle={{ backgroundColor: 'white', borderRadius: 12 }}
243
+ actions={[
244
+ { id: 'archive', title: 'Archive', systemImage: 'archivebox', tintColor: '#007AFF' },
245
+ { id: 'delete', title: 'Delete', systemImage: 'trash', destructive: true },
246
+ ]}
247
+ onActionPress={({ nativeEvent }) => handleAction(nativeEvent.id)}
248
+ >
249
+ <Pressable onPress={openMessage} style={{ padding: 16 }}>
250
+ <Text>Weekend plans</Text>
251
+ </Pressable>
252
+ </SwipeActions>;
253
+ ```
254
+
255
+ | Prop | Description | Default |
256
+ | --- | --- | --- |
257
+ | `actions` | Ordered array of native buttons; an empty array disables swiping | Required |
258
+ | `edge` | `leading` or `trailing`, following the row's layout direction | `trailing` |
259
+ | `allowsFullSwipe` | A full swipe performs the **first** action | `true` |
260
+ | `disabled` | Disables swipe actions while preserving child interactions | `false` |
261
+ | `onActionPress` | Receives `{ nativeEvent: { id, title } }` | — |
262
+ | `children` | React Native row content, including pressable children | Required |
263
+ | `contentContainerStyle` | Styles the moving row, including its background, corners and padding | — |
264
+
265
+ Each action accepts `title`, optional `id` (defaults to `item.<index>`),
266
+ `systemImage` (SF Symbol), `tintColor` (button background), and `destructive`.
267
+ IDs must be unique within the row; use explicit IDs when reordering actions.
268
+ Colors support `PlatformColor` and `DynamicColorIOS`. Buttons appear from the
269
+ selected edge inward in array order. `destructive` changes the native appearance;
270
+ your callback decides whether to remove the row from React state.
271
+
272
+ Standard `ViewProps` and a native view ref are supported. `style` applies to the
273
+ stationary outer container; use it for layout, sizing and margins. Put the row's
274
+ background, corners and padding in `contentContainerStyle` (or on your children)
275
+ so they move with the content. A background on `style` stays behind the revealed
276
+ actions. Keep stable list keys.
277
+ Opening another `SwipeActions` row closes the previous one. Updating the action
278
+ configuration, disabling, resizing or unmounting a row dismisses its actions.
279
+ One edge is supported per wrapper; do not nest wrappers to add a second edge.
280
+ This component hosts one native table per mounted row, so use list virtualization
281
+ for large datasets. It does not expose SwiftUI's arbitrary action view content.
282
+
224
283
  ## Popover
225
284
 
226
285
  <img src="docs/screenshots/popover.png" alt="Popover displaying resizable content above its trigger" width="320" />
@@ -744,7 +803,7 @@ visibility state changes apply instantly. Set it to `false` to opt out.
744
803
 
745
804
  ## Example App
746
805
 
747
- The [example app](example/src/App.tsx) demonstrates Menu, Popover, TipKit,
806
+ The [example app](example/src/App.tsx) demonstrates Menu, SwipeActions, Popover, TipKit,
748
807
  LiquidGlassText, Stepper, ConcentricView, and SFSymbol. It includes all native
749
808
  components, so building it requires Xcode 26+. Use iOS 26+ to try the glass effects
750
809
  and the latest SF Symbol features.
@@ -12,6 +12,9 @@
12
12
  #if TINYUI_FEATURE_MENU
13
13
  [components addObject:@"Menu"];
14
14
  #endif
15
+ #if TINYUI_FEATURE_SWIPE_ACTIONS
16
+ [components addObject:@"SwipeActions"];
17
+ #endif
15
18
  #if TINYUI_FEATURE_POPOVER
16
19
  [components addObject:@"Popover"];
17
20
  #endif
@@ -29,6 +29,12 @@ TINYUI_DISABLED_COMPONENT(TinyuiMenuView, TinyuiMenuViewComponentDescriptor)
29
29
  TINYUI_DISABLED_COMPONENT(TinyuiPopoverView, TinyuiPopoverViewComponentDescriptor)
30
30
  #endif
31
31
 
32
+ #if TINYUI_FEATURE_SWIPE_ACTIONS
33
+ #import "TinyuiSwipeActionsView.h"
34
+ #else
35
+ TINYUI_DISABLED_COMPONENT(TinyuiSwipeActionsView, TinyuiSwipeActionsViewComponentDescriptor)
36
+ #endif
37
+
32
38
  #if TINYUI_FEATURE_LIQUID_GLASS_TEXT
33
39
  #import "TinyuiLiquidGlassTextView.h"
34
40
  #else
@@ -68,6 +74,11 @@ Class<RCTComponentViewProtocol> TinyuiMenuViewCls(void)
68
74
  return TinyuiMenuView.class;
69
75
  }
70
76
 
77
+ Class<RCTComponentViewProtocol> TinyuiSwipeActionsViewCls(void)
78
+ {
79
+ return TinyuiSwipeActionsView.class;
80
+ }
81
+
71
82
  Class<RCTComponentViewProtocol> TinyuiPopoverViewCls(void)
72
83
  {
73
84
  return TinyuiPopoverView.class;
@@ -0,0 +1,12 @@
1
+ #if TINYUI_FEATURE_SWIPE_ACTIONS
2
+
3
+ #import <React/RCTViewComponentView.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ @interface TinyuiSwipeActionsView : RCTViewComponentView
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END
11
+
12
+ #endif
@@ -0,0 +1,289 @@
1
+ #if TINYUI_FEATURE_SWIPE_ACTIONS
2
+
3
+ #import "TinyuiSwipeActionsView.h"
4
+
5
+ #import <React/RCTConvert.h>
6
+ #import <React/RCTSurfacePointerHandler.h>
7
+ #import <React/RCTSurfaceTouchHandler.h>
8
+ #import <react/utils/FollyConvert.h>
9
+ #import <react/renderer/components/TinyuiSpec/ComponentDescriptors.h>
10
+ #import <react/renderer/components/TinyuiSpec/EventEmitters.h>
11
+ #import <react/renderer/components/TinyuiSpec/Props.h>
12
+
13
+ using namespace facebook::react;
14
+
15
+ @interface TinyuiSwipeActionsView () <UITableViewDataSource, UITableViewDelegate>
16
+ @end
17
+
18
+ @implementation TinyuiSwipeActionsView {
19
+ UITableView *_tableView;
20
+ UITableViewCell *_cell;
21
+ UIView *_rowView;
22
+ NSArray<NSDictionary *> *_actions;
23
+ BOOL _leading;
24
+ BOOL _allowsFullSwipe;
25
+ BOOL _disabled;
26
+ BOOL _needsConfiguration;
27
+ BOOL _actionsPresented;
28
+ NSUInteger _configurationVersion;
29
+ }
30
+
31
+ // UIKit normally coordinates open rows within one table. Each React row has
32
+ // its own table, so coordinate them without retaining mounted Fabric views.
33
+ static __weak TinyuiSwipeActionsView *activeSwipeView;
34
+
35
+ + (ComponentDescriptorProvider)componentDescriptorProvider
36
+ {
37
+ return concreteComponentDescriptorProvider<TinyuiSwipeActionsViewComponentDescriptor>();
38
+ }
39
+
40
+ - (instancetype)initWithFrame:(CGRect)frame
41
+ {
42
+ if (self = [super initWithFrame:frame]) {
43
+ _props = std::make_shared<const TinyuiSwipeActionsViewProps>();
44
+ _actions = @[];
45
+ _allowsFullSwipe = YES;
46
+
47
+ _cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
48
+ _cell.backgroundColor = UIColor.clearColor;
49
+ _cell.contentView.backgroundColor = UIColor.clearColor;
50
+ _cell.selectionStyle = UITableViewCellSelectionStyleNone;
51
+ _cell.isAccessibilityElement = NO;
52
+
53
+ _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
54
+ _tableView.backgroundColor = UIColor.clearColor;
55
+ _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
56
+ _tableView.scrollEnabled = NO;
57
+ _tableView.showsVerticalScrollIndicator = NO;
58
+ _tableView.showsHorizontalScrollIndicator = NO;
59
+ _tableView.bounces = NO;
60
+ _tableView.delaysContentTouches = NO;
61
+ _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
62
+ _tableView.insetsContentViewsToSafeArea = NO;
63
+ _tableView.sectionHeaderTopPadding = 0;
64
+ _tableView.estimatedRowHeight = 0;
65
+ _tableView.estimatedSectionHeaderHeight = 0;
66
+ _tableView.estimatedSectionFooterHeight = 0;
67
+ _tableView.dataSource = self;
68
+ _tableView.delegate = self;
69
+ // Cover the entire row. Yoga owns the child's frame, including any padding;
70
+ // using RCTView's inset contentView frame would apply that padding twice.
71
+ [self addSubview:_tableView];
72
+ }
73
+ return self;
74
+ }
75
+
76
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
77
+ index:(NSInteger)index
78
+ {
79
+ _rowView = childComponentView;
80
+ [_cell.contentView addSubview:childComponentView];
81
+ }
82
+
83
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
84
+ index:(NSInteger)index
85
+ {
86
+ [childComponentView removeFromSuperview];
87
+ if (_rowView == childComponentView) {
88
+ _rowView = nil;
89
+ [self closeActions];
90
+ }
91
+ }
92
+
93
+ - (void)layoutSubviews
94
+ {
95
+ [super layoutSubviews];
96
+ UISemanticContentAttribute direction = _layoutMetrics.layoutDirection == LayoutDirection::RightToLeft
97
+ ? UISemanticContentAttributeForceRightToLeft
98
+ : UISemanticContentAttributeForceLeftToRight;
99
+ if (!CGSizeEqualToSize(_tableView.bounds.size, self.bounds.size) ||
100
+ _tableView.semanticContentAttribute != direction) {
101
+ [self closeActions];
102
+ }
103
+ _tableView.frame = self.bounds;
104
+ CGFloat height = MAX(1, CGRectGetHeight(self.bounds));
105
+ if (_tableView.rowHeight != height) {
106
+ _tableView.rowHeight = height;
107
+ [_tableView reloadData];
108
+ }
109
+ // Map Yoga's resolved direction to UIKit's logical leading/trailing edges.
110
+ _tableView.semanticContentAttribute = direction;
111
+ }
112
+
113
+ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
114
+ {
115
+ UIView *hit = [super hitTest:point withEvent:event];
116
+ // A tap on the exposed row dismisses its actions. Keep that tap in UIKit,
117
+ // rather than also activating a React child while the row is sliding back.
118
+ if (_actionsPresented && _rowView != nil && [hit isDescendantOfView:_rowView]) {
119
+ return _cell.contentView;
120
+ }
121
+ return hit;
122
+ }
123
+
124
+ - (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point
125
+ {
126
+ // Native action buttons have no Fabric ancestor until this view. Do not let
127
+ // their taps bubble to an outer React Pressable. Child React views still own
128
+ // normal row touches and keep their usual event bubbling.
129
+ return _actionsPresented ? nullptr : [super touchEventEmitterAtPoint:point];
130
+ }
131
+
132
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
133
+ {
134
+ const auto &previous = *std::static_pointer_cast<const TinyuiSwipeActionsViewProps>(_props);
135
+ const auto &next = *std::static_pointer_cast<const TinyuiSwipeActionsViewProps>(props);
136
+ if (_needsConfiguration || previous.actionsConfig != next.actionsConfig || previous.edge != next.edge ||
137
+ previous.allowsFullSwipe != next.allowsFullSwipe || previous.disabled != next.disabled) {
138
+ [self closeActions];
139
+ id config = convertFollyDynamicToId(next.actionsConfig);
140
+ _actions = [config isKindOfClass:NSArray.class] ? config : @[];
141
+ _leading = next.edge == TinyuiSwipeActionsViewEdge::Leading;
142
+ _allowsFullSwipe = next.allowsFullSwipe;
143
+ _disabled = next.disabled;
144
+ _needsConfiguration = NO;
145
+ }
146
+ [super updateProps:props oldProps:oldProps];
147
+ }
148
+
149
+ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
150
+ {
151
+ return 1;
152
+ }
153
+
154
+ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
155
+ {
156
+ return _cell;
157
+ }
158
+
159
+ - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
160
+ {
161
+ return !_disabled && _actions.count > 0 && _rowView != nil;
162
+ }
163
+
164
+ - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView
165
+ leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
166
+ {
167
+ return _leading ? [self swipeConfiguration] : nil;
168
+ }
169
+
170
+ - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView
171
+ trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
172
+ {
173
+ return _leading ? nil : [self swipeConfiguration];
174
+ }
175
+
176
+ - (UISwipeActionsConfiguration *)swipeConfiguration
177
+ {
178
+ if (_disabled || _actions.count == 0 || _rowView == nil) {
179
+ return nil;
180
+ }
181
+
182
+ NSMutableArray<UIContextualAction *> *actions = [NSMutableArray array];
183
+ NSUInteger version = _configurationVersion;
184
+ __weak TinyuiSwipeActionsView *weakSelf = self;
185
+ for (NSDictionary *item in _actions) {
186
+ if (![item isKindOfClass:NSDictionary.class] ||
187
+ ![item[@"id"] isKindOfClass:NSString.class] ||
188
+ ![item[@"title"] isKindOfClass:NSString.class]) {
189
+ continue;
190
+ }
191
+ NSString *identifier = item[@"id"];
192
+ NSString *title = item[@"title"];
193
+ UIContextualActionStyle style = [item[@"destructive"] boolValue]
194
+ ? UIContextualActionStyleDestructive : UIContextualActionStyleNormal;
195
+ UIContextualAction *action = [UIContextualAction contextualActionWithStyle:style
196
+ title:title handler:^(UIContextualAction *selectedAction, UIView *sourceView,
197
+ void (^completionHandler)(BOOL)) {
198
+ TinyuiSwipeActionsView *view = weakSelf;
199
+ if (view == nil || view->_disabled || view.window == nil || view->_rowView == nil ||
200
+ version != view->_configurationVersion) {
201
+ completionHandler(NO);
202
+ return;
203
+ }
204
+ // Finish UIKit's interaction before JS can update or remove the row.
205
+ completionHandler(YES);
206
+ if (view->_eventEmitter != nullptr) {
207
+ std::static_pointer_cast<const TinyuiSwipeActionsViewEventEmitter>(view->_eventEmitter)
208
+ ->onActionPress(TinyuiSwipeActionsViewEventEmitter::OnActionPress{
209
+ .id = std::string(identifier.UTF8String ?: ""),
210
+ .title = std::string(title.UTF8String ?: "")});
211
+ }
212
+ }];
213
+ if ([item[@"systemImage"] isKindOfClass:NSString.class]) {
214
+ action.image = [UIImage systemImageNamed:item[@"systemImage"]];
215
+ }
216
+ if (item[@"tintColor"] != nil && item[@"tintColor"] != NSNull.null) {
217
+ action.backgroundColor = [RCTConvert UIColor:item[@"tintColor"]];
218
+ }
219
+ [actions addObject:action];
220
+ }
221
+ UISwipeActionsConfiguration *configuration = [UISwipeActionsConfiguration configurationWithActions:actions];
222
+ configuration.performsFirstActionWithFullSwipe = _allowsFullSwipe;
223
+ return configuration;
224
+ }
225
+
226
+ - (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
227
+ {
228
+ _actionsPresented = YES;
229
+ // Fabric keeps observing touches handled by recognizers inside its surface.
230
+ // Once UIKit starts a swipe, cancel that React sequence so a child/ancestor
231
+ // Pressable cannot also complete an onPress when the finger is lifted.
232
+ for (UIView *view = self; view != nil; view = view.superview) {
233
+ for (UIGestureRecognizer *recognizer in view.gestureRecognizers) {
234
+ if (recognizer.enabled &&
235
+ ([recognizer isKindOfClass:RCTSurfaceTouchHandler.class] ||
236
+ [recognizer isKindOfClass:RCTSurfacePointerHandler.class])) {
237
+ recognizer.enabled = NO;
238
+ recognizer.enabled = YES;
239
+ }
240
+ }
241
+ }
242
+ if (activeSwipeView != self) {
243
+ [activeSwipeView closeActions];
244
+ }
245
+ activeSwipeView = self;
246
+ }
247
+
248
+ - (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
249
+ {
250
+ _actionsPresented = NO;
251
+ if (activeSwipeView == self) {
252
+ activeSwipeView = nil;
253
+ }
254
+ }
255
+
256
+ - (void)closeActions
257
+ {
258
+ _configurationVersion += 1;
259
+ _actionsPresented = NO;
260
+ [_tableView setEditing:NO animated:NO];
261
+ if (activeSwipeView == self) {
262
+ activeSwipeView = nil;
263
+ }
264
+ }
265
+
266
+ - (void)didMoveToWindow
267
+ {
268
+ [super didMoveToWindow];
269
+ if (self.window == nil) {
270
+ [self closeActions];
271
+ }
272
+ }
273
+
274
+ - (void)prepareForRecycle
275
+ {
276
+ [self closeActions];
277
+ [_rowView removeFromSuperview];
278
+ _rowView = nil;
279
+ _actions = @[];
280
+ _leading = NO;
281
+ _allowsFullSwipe = YES;
282
+ _disabled = NO;
283
+ _needsConfiguration = YES;
284
+ [super prepareForRecycle];
285
+ }
286
+
287
+ @end
288
+
289
+ #endif
@@ -0,0 +1,19 @@
1
+ import {
2
+ codegenNativeComponent,
3
+ type CodegenTypes,
4
+ type ViewProps,
5
+ } from 'react-native';
6
+ import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
7
+
8
+ export interface NativeSwipeActionsProps extends ViewProps {
9
+ actionsConfig: CodegenTypes.UnsafeMixed;
10
+ edge?: CodegenTypes.WithDefault<'leading' | 'trailing', 'trailing'>;
11
+ allowsFullSwipe?: CodegenTypes.WithDefault<boolean, true>;
12
+ disabled?: boolean;
13
+ onActionPress?: DirectEventHandler<Readonly<{ id: string; title: string }>>;
14
+ }
15
+
16
+ export default codegenNativeComponent<NativeSwipeActionsProps>(
17
+ 'TinyuiSwipeActionsView',
18
+ { excludedPlatforms: ['android'] }
19
+ );
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+
3
+ import { processColor } from 'react-native';
4
+ export function serializeSwipeActions(actions) {
5
+ const ids = new Set();
6
+ return actions.map((action, index) => {
7
+ const id = action.id ?? `item.${index}`;
8
+ if (ids.has(id)) {
9
+ throw new Error(`SwipeActions action id "${id}" must be unique.`);
10
+ }
11
+ ids.add(id);
12
+ return {
13
+ id,
14
+ title: action.title,
15
+ systemImage: action.systemImage,
16
+ tintColor: action.tintColor === undefined ? undefined : processColor(action.tintColor),
17
+ destructive: action.destructive ?? false
18
+ };
19
+ });
20
+ }
21
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["processColor","serializeSwipeActions","actions","ids","Set","map","action","index","id","has","Error","add","title","systemImage","tintColor","undefined","destructive"],"sourceRoot":"../../../src","sources":["SwipeActions/actions.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,cAAc;AAI3C,OAAO,SAASC,qBAAqBA,CAACC,OAA+B,EAAE;EACrE,MAAMC,GAAG,GAAG,IAAIC,GAAG,CAAS,CAAC;EAE7B,OAAOF,OAAO,CAACG,GAAG,CAAC,CAACC,MAAM,EAAEC,KAAK,KAAK;IACpC,MAAMC,EAAE,GAAGF,MAAM,CAACE,EAAE,IAAI,QAAQD,KAAK,EAAE;IACvC,IAAIJ,GAAG,CAACM,GAAG,CAACD,EAAE,CAAC,EAAE;MACf,MAAM,IAAIE,KAAK,CAAC,2BAA2BF,EAAE,mBAAmB,CAAC;IACnE;IACAL,GAAG,CAACQ,GAAG,CAACH,EAAE,CAAC;IAEX,OAAO;MACLA,EAAE;MACFI,KAAK,EAAEN,MAAM,CAACM,KAAK;MACnBC,WAAW,EAAEP,MAAM,CAACO,WAAW;MAC/BC,SAAS,EACPR,MAAM,CAACQ,SAAS,KAAKC,SAAS,GAC1BA,SAAS,GACTf,YAAY,CAACM,MAAM,CAACQ,SAAS,CAAC;MACpCE,WAAW,EAAEV,MAAM,CAACU,WAAW,IAAI;IACrC,CAAC;EACH,CAAC,CAAC;AACJ","ignoreList":[]}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+
3
+ import { forwardRef } from 'react';
4
+ import { StyleSheet, View } from 'react-native';
5
+ import { assertComponentEnabled } from "../utils/index.js";
6
+ import { serializeSwipeActions } from "./actions.js";
7
+ import NativeSwipeActionsView from './SwipeActionsNativeComponent';
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ export const SwipeActions = /*#__PURE__*/forwardRef(function SwipeActionsRoot({
10
+ actions,
11
+ children,
12
+ contentContainerStyle,
13
+ edge = 'trailing',
14
+ allowsFullSwipe = true,
15
+ disabled = false,
16
+ style,
17
+ ...viewProps
18
+ }, ref) {
19
+ assertComponentEnabled('SwipeActions');
20
+ return /*#__PURE__*/_jsx(NativeSwipeActionsView, {
21
+ ...viewProps,
22
+ ref: ref,
23
+ actionsConfig: serializeSwipeActions(actions),
24
+ edge: edge,
25
+ allowsFullSwipe: allowsFullSwipe,
26
+ disabled: disabled,
27
+ style: [styles.container, style],
28
+ children: /*#__PURE__*/_jsx(View, {
29
+ collapsable: false,
30
+ style: [styles.content, contentContainerStyle],
31
+ children: children
32
+ })
33
+ });
34
+ });
35
+ const styles = StyleSheet.create({
36
+ container: {
37
+ overflow: 'hidden'
38
+ },
39
+ content: {
40
+ flexGrow: 1
41
+ }
42
+ });
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["forwardRef","StyleSheet","View","assertComponentEnabled","serializeSwipeActions","NativeSwipeActionsView","jsx","_jsx","SwipeActions","SwipeActionsRoot","actions","children","contentContainerStyle","edge","allowsFullSwipe","disabled","style","viewProps","ref","actionsConfig","styles","container","collapsable","content","create","overflow","flexGrow"],"sourceRoot":"../../../src","sources":["SwipeActions/index.tsx"],"mappings":";;AAAA,SAASA,UAAU,QAA2B,OAAO;AACrD,SAASC,UAAU,EAAEC,IAAI,QAAQ,cAAc;AAE/C,SAASC,sBAAsB,QAAQ,mBAAU;AACjD,SAASC,qBAAqB,QAAQ,cAAW;AACjD,OAAOC,sBAAsB,MAAM,+BAA+B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAGnE,OAAO,MAAMC,YAAY,gBAAGR,UAAU,CAGpC,SAASS,gBAAgBA,CACzB;EACEC,OAAO;EACPC,QAAQ;EACRC,qBAAqB;EACrBC,IAAI,GAAG,UAAU;EACjBC,eAAe,GAAG,IAAI;EACtBC,QAAQ,GAAG,KAAK;EAChBC,KAAK;EACL,GAAGC;AACL,CAAC,EACDC,GAAG,EACH;EACAf,sBAAsB,CAAC,cAAc,CAAC;EAEtC,oBACEI,IAAA,CAACF,sBAAsB;IAAA,GACjBY,SAAS;IACbC,GAAG,EAAEA,GAAI;IACTC,aAAa,EAAEf,qBAAqB,CAACM,OAAO,CAAE;IAC9CG,IAAI,EAAEA,IAAK;IACXC,eAAe,EAAEA,eAAgB;IACjCC,QAAQ,EAAEA,QAAS;IACnBC,KAAK,EAAE,CAACI,MAAM,CAACC,SAAS,EAAEL,KAAK,CAAE;IAAAL,QAAA,eAEjCJ,IAAA,CAACL,IAAI;MAACoB,WAAW,EAAE,KAAM;MAACN,KAAK,EAAE,CAACI,MAAM,CAACG,OAAO,EAAEX,qBAAqB,CAAE;MAAAD,QAAA,EACtEA;IAAQ,CACL;EAAC,CACe,CAAC;AAE7B,CAAC,CAAC;AAEF,MAAMS,MAAM,GAAGnB,UAAU,CAACuB,MAAM,CAAC;EAC/BH,SAAS,EAAE;IAAEI,QAAQ,EAAE;EAAS,CAAC;EACjCF,OAAO,EAAE;IAAEG,QAAQ,EAAE;EAAE;AACzB,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export {};
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["SwipeActions/types.ts"],"mappings":"","ignoreList":[]}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  export { Menu } from "./Menu/index.js";
4
+ export { SwipeActions } from "./SwipeActions/index.js";
4
5
  export { TipKit } from "./TipKit/index.js";
5
6
  export { Stepper } from "./Stepper/index.js";
6
7
  export { ConcentricView } from "./ConcentricView/index.js";
@@ -1 +1 @@
1
- {"version":3,"names":["Menu","TipKit","Stepper","ConcentricView","SFSymbol","Popover","PopoverClose","getNativeTinyui","assertComponentEnabled","LiquidGlassText"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,IAAI,QAAQ,iBAAQ;AAC7B,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;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 +1 @@
1
- {"version":3,"names":["NativeTinyui","nativeTinyui","enabledComponents","getNativeTinyui","Error","assertComponentEnabled","component","tinyui","Set","getEnabledComponents","has"],"sourceRoot":"../../../src","sources":["utils/getNativeTinyui.ts"],"mappings":";;AAAA,OAAOA,YAAY,MAAqB,oBAAiB;AAWzD,IAAIC,YAAqC;AACzC,IAAIC,iBAAkD;;AAEtD;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAAA,EAAS;EACtCF,YAAY,KAAKD,YAAY;EAC7B,IAAIC,YAAY,IAAI,IAAI,EAAE;IACxB,MAAM,IAAIG,KAAK,CACb,sDAAsD,GACpD,8DACJ,CAAC;EACH;EACA,OAAOH,YAAY;AACrB;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASI,sBAAsBA,CAACC,SAA0B,EAAQ;EACvE,MAAMC,MAAM,GAAGJ,eAAe,CAAC,CAAC;EAChCD,iBAAiB,KAAK,IAAIM,GAAG,CAACD,MAAM,CAACE,oBAAoB,CAAC,CAAC,CAAC;EAE5D,IAAI,CAACP,iBAAiB,CAACQ,GAAG,CAACJ,SAAS,CAAC,EAAE;IACrC,MAAM,IAAIF,KAAK,CACb,gBAAgBE,SAAS,+BAA+B,GACtD,QAAQA,SAAS,kDAAkD,GACnE,sCACJ,CAAC;EACH;AACF","ignoreList":[]}
1
+ {"version":3,"names":["NativeTinyui","nativeTinyui","enabledComponents","getNativeTinyui","Error","assertComponentEnabled","component","tinyui","Set","getEnabledComponents","has"],"sourceRoot":"../../../src","sources":["utils/getNativeTinyui.ts"],"mappings":";;AAAA,OAAOA,YAAY,MAAqB,oBAAiB;AAYzD,IAAIC,YAAqC;AACzC,IAAIC,iBAAkD;;AAEtD;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAAA,EAAS;EACtCF,YAAY,KAAKD,YAAY;EAC7B,IAAIC,YAAY,IAAI,IAAI,EAAE;IACxB,MAAM,IAAIG,KAAK,CACb,sDAAsD,GACpD,8DACJ,CAAC;EACH;EACA,OAAOH,YAAY;AACrB;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASI,sBAAsBA,CAACC,SAA0B,EAAQ;EACvE,MAAMC,MAAM,GAAGJ,eAAe,CAAC,CAAC;EAChCD,iBAAiB,KAAK,IAAIM,GAAG,CAACD,MAAM,CAACE,oBAAoB,CAAC,CAAC,CAAC;EAE5D,IAAI,CAACP,iBAAiB,CAACQ,GAAG,CAACJ,SAAS,CAAC,EAAE;IACrC,MAAM,IAAIF,KAAK,CACb,gBAAgBE,SAAS,+BAA+B,GACtD,QAAQA,SAAS,kDAAkD,GACnE,sCACJ,CAAC;EACH;AACF","ignoreList":[]}
@@ -0,0 +1,15 @@
1
+ import { type CodegenTypes, type ViewProps } from 'react-native';
2
+ import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
3
+ export interface NativeSwipeActionsProps extends ViewProps {
4
+ actionsConfig: CodegenTypes.UnsafeMixed;
5
+ edge?: CodegenTypes.WithDefault<'leading' | 'trailing', 'trailing'>;
6
+ allowsFullSwipe?: CodegenTypes.WithDefault<boolean, true>;
7
+ disabled?: boolean;
8
+ onActionPress?: DirectEventHandler<Readonly<{
9
+ id: string;
10
+ title: string;
11
+ }>>;
12
+ }
13
+ declare const _default: import("react-native/types_generated/Libraries/Utilities/codegenNativeComponent").NativeComponentType<NativeSwipeActionsProps>;
14
+ export default _default;
15
+ //# sourceMappingURL=SwipeActionsNativeComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwipeActionsNativeComponent.d.ts","sourceRoot":"","sources":["../../../../src/SwipeActions/SwipeActionsNativeComponent.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,uBAAwB,SAAQ,SAAS;IACxD,aAAa,EAAE,YAAY,CAAC,WAAW,CAAC;IACxC,IAAI,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,SAAS,GAAG,UAAU,EAAE,UAAU,CAAC,CAAC;IACpE,eAAe,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CAC7E;;AAED,wBAGE"}
@@ -0,0 +1,9 @@
1
+ import type { SwipeAction } from './types.js';
2
+ export declare function serializeSwipeActions(actions: readonly SwipeAction[]): {
3
+ id: string;
4
+ title: string;
5
+ systemImage: string | undefined;
6
+ tintColor: import("react-native").ProcessedColorValue | null | undefined;
7
+ destructive: boolean;
8
+ }[];
9
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../../src/SwipeActions/actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAS,CAAC;AAE3C,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE;;;;;;IAqBpE"}
@@ -0,0 +1,4 @@
1
+ import type { SwipeActionsProps } from './types.js';
2
+ export declare const SwipeActions: import("react").ForwardRefExoticComponent<SwipeActionsProps & import("react").RefAttributes<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>>;
3
+ export type { SwipeAction, SwipeActionPressEvent, SwipeActionsEdge, SwipeActionsProps, } from './types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/SwipeActions/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAS,CAAC;AAEjD,eAAO,MAAM,YAAY,+LAiCvB,CAAC;AAOH,YAAY,EACV,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,YAAS,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { ColorValue, StyleProp, ViewProps, ViewStyle } from 'react-native';
3
+ export type SwipeActionsEdge = 'leading' | 'trailing';
4
+ export interface SwipeAction {
5
+ /** Stable identifier. Defaults to `item.<index>` when omitted. */
6
+ id?: string;
7
+ /** Button title and accessible action name. */
8
+ title: string;
9
+ /** SF Symbol name. */
10
+ systemImage?: string;
11
+ /** Native action background color, including semantic and dynamic colors. */
12
+ tintColor?: ColorValue;
13
+ /** Uses the system destructive appearance. Does not remove the React row. */
14
+ destructive?: boolean;
15
+ }
16
+ export type SwipeActionPressEvent = Readonly<{
17
+ nativeEvent: Readonly<{
18
+ id: string;
19
+ title: string;
20
+ }>;
21
+ }>;
22
+ export interface SwipeActionsProps extends Omit<ViewProps, 'children'> {
23
+ /** The React Native row content. */
24
+ children: ReactNode;
25
+ /** Styles the moving row, including its background, corners and padding. */
26
+ contentContainerStyle?: StyleProp<ViewStyle>;
27
+ /** Actions ordered from the selected edge inward. */
28
+ actions: readonly SwipeAction[];
29
+ /** Logical edge; respects layout direction. Defaults to `trailing`. */
30
+ edge?: SwipeActionsEdge;
31
+ /** A full swipe performs the first action. Defaults to `true`. */
32
+ allowsFullSwipe?: boolean;
33
+ /** Disables swipe actions without disabling the row's children. */
34
+ disabled?: boolean;
35
+ onActionPress?: (event: SwipeActionPressEvent) => void;
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/SwipeActions/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEhF,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,UAAU,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,WAAW,EAAE,QAAQ,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD,CAAC,CAAC;AAEH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IACpE,oCAAoC;IACpC,QAAQ,EAAE,SAAS,CAAC;IACpB,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7C,qDAAqD;IACrD,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IAChC,uEAAuE;IACvE,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,kEAAkE;IAClE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACxD"}
@@ -1,4 +1,6 @@
1
1
  export { Menu } from './Menu/index.js';
2
+ export { SwipeActions } from './SwipeActions/index.js';
3
+ export type { SwipeAction, SwipeActionPressEvent, SwipeActionsEdge, SwipeActionsProps, } from './SwipeActions/index.js';
2
4
  export { TipKit } from './TipKit/index.js';
3
5
  export type { TipAction, TipDisplayFrequency, TipError, TipInvalidationReason, TipPopoverProps, TipViewProps, TipKitConfiguration, } from './TipKit/index.js';
4
6
  export type { MenuActionOption, MenuActionPressEvent, MenuActionPressEventData, MenuDividerOption, MenuItemState, MenuOption, MenuProps, MenuRef, MenuSectionOption, MenuSubmenuOption, } from './Menu/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,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,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,5 +1,5 @@
1
1
  import { type Spec } from '../NativeTinyui.js';
2
- export type TinyuiComponent = 'Menu' | 'Popover' | 'LiquidGlassText' | 'Stepper' | 'ConcentricView' | 'SFSymbol' | 'TipKit';
2
+ export type TinyuiComponent = 'Menu' | 'SwipeActions' | 'Popover' | 'LiquidGlassText' | 'Stepper' | 'ConcentricView' | 'SFSymbol' | 'TipKit';
3
3
  /**
4
4
  * Returns the Tinyui TurboModule instance. The native module is always
5
5
  * compiled (Core), so this is safe to call.
@@ -1 +1 @@
1
- {"version":3,"file":"getNativeTinyui.d.ts","sourceRoot":"","sources":["../../../../src/utils/getNativeTinyui.ts"],"names":[],"mappings":"AAAA,OAAqB,EAAE,KAAK,IAAI,EAAE,MAAM,oBAAiB,CAAC;AAE1D,MAAM,MAAM,eAAe,GACvB,MAAM,GACN,SAAS,GACT,iBAAiB,GACjB,SAAS,GACT,gBAAgB,GAChB,UAAU,GACV,QAAQ,CAAC;AAKb;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAStC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,eAAe,GAAG,IAAI,CAWvE"}
1
+ {"version":3,"file":"getNativeTinyui.d.ts","sourceRoot":"","sources":["../../../../src/utils/getNativeTinyui.ts"],"names":[],"mappings":"AAAA,OAAqB,EAAE,KAAK,IAAI,EAAE,MAAM,oBAAiB,CAAC;AAE1D,MAAM,MAAM,eAAe,GACvB,MAAM,GACN,cAAc,GACd,SAAS,GACT,iBAAiB,GACjB,SAAS,GACT,gBAAgB,GAChB,UAAU,GACV,QAAQ,CAAC;AAKb;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAStC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,eAAe,GAAG,IAAI,CAWvE"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-tinyui",
3
- "version": "3.0.0",
4
- "description": "Dependency-free native iOS Menu, Popover, TipKit, Stepper, ConcentricView, SFSymbol and LiquidGlassText components for React Native",
3
+ "version": "3.1.0",
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",
7
7
  "exports": {
@@ -20,6 +20,11 @@
20
20
  "types": "./lib/typescript/src/Popover/index.d.ts",
21
21
  "default": "./lib/module/Popover/index.js"
22
22
  },
23
+ "./swipe-actions": {
24
+ "react-native-tinyui-source": "./src/SwipeActions/index.tsx",
25
+ "types": "./lib/typescript/src/SwipeActions/index.d.ts",
26
+ "default": "./lib/module/SwipeActions/index.js"
27
+ },
23
28
  "./stepper": {
24
29
  "react-native-tinyui-source": "./src/Stepper/index.tsx",
25
30
  "types": "./lib/typescript/src/Stepper/index.d.ts",
@@ -152,6 +157,9 @@
152
157
  }
153
158
  },
154
159
  "components": {
160
+ "TinyuiSwipeActionsView": {
161
+ "className": "TinyuiSwipeActionsView"
162
+ },
155
163
  "TinyuiMenuView": {
156
164
  "className": "TinyuiMenuView"
157
165
  },
@@ -4,6 +4,11 @@ require "pathname"
4
4
  package = JSON.parse(File.read(File.join(__dir__, "package.json")))
5
5
 
6
6
  components = {
7
+ "SwipeActions" => {
8
+ :source_files => "ios/SwipeActions/**/*.{h,m,mm,swift,cpp}",
9
+ :definition => "TINYUI_FEATURE_SWIPE_ACTIONS=1",
10
+ :frameworks => ["UIKit"],
11
+ },
7
12
  "Menu" => {
8
13
  :source_files => "ios/Menu/**/*.{h,m,mm,swift,cpp}",
9
14
  :definition => "TINYUI_FEATURE_MENU=1",
@@ -100,7 +105,7 @@ Pod::Spec.new do |s|
100
105
  s.source = { :git => "https://github.com/luoxuhai/react-native-tinyui.git", :tag => "#{s.version}" }
101
106
 
102
107
  s.source_files = source_files
103
- s.private_header_files = ["ios/Core/**/*.h", "ios/Menu/**/*.h", "ios/Popover/**/*.h", "ios/LiquidGlassText/**/*.h", "ios/Stepper/**/*.h", "ios/ConcentricView/**/*.h", "ios/SFSymbol/**/*.h", "ios/TipKit/**/*.h"]
108
+ s.private_header_files = ["ios/Core/**/*.h", "ios/Menu/**/*.h", "ios/SwipeActions/**/*.h", "ios/Popover/**/*.h", "ios/LiquidGlassText/**/*.h", "ios/Stepper/**/*.h", "ios/ConcentricView/**/*.h", "ios/SFSymbol/**/*.h", "ios/TipKit/**/*.h"]
104
109
  s.preserve_paths = "ios/LiquidGlassText/GlassText-LICENSE"
105
110
  s.swift_version = "5.0"
106
111
  s.frameworks = frameworks unless frameworks.empty?
@@ -0,0 +1,19 @@
1
+ import {
2
+ codegenNativeComponent,
3
+ type CodegenTypes,
4
+ type ViewProps,
5
+ } from 'react-native';
6
+ import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
7
+
8
+ export interface NativeSwipeActionsProps extends ViewProps {
9
+ actionsConfig: CodegenTypes.UnsafeMixed;
10
+ edge?: CodegenTypes.WithDefault<'leading' | 'trailing', 'trailing'>;
11
+ allowsFullSwipe?: CodegenTypes.WithDefault<boolean, true>;
12
+ disabled?: boolean;
13
+ onActionPress?: DirectEventHandler<Readonly<{ id: string; title: string }>>;
14
+ }
15
+
16
+ export default codegenNativeComponent<NativeSwipeActionsProps>(
17
+ 'TinyuiSwipeActionsView',
18
+ { excludedPlatforms: ['android'] }
19
+ );
@@ -0,0 +1,26 @@
1
+ import { processColor } from 'react-native';
2
+
3
+ import type { SwipeAction } from './types';
4
+
5
+ export function serializeSwipeActions(actions: readonly SwipeAction[]) {
6
+ const ids = new Set<string>();
7
+
8
+ return actions.map((action, index) => {
9
+ const id = action.id ?? `item.${index}`;
10
+ if (ids.has(id)) {
11
+ throw new Error(`SwipeActions action id "${id}" must be unique.`);
12
+ }
13
+ ids.add(id);
14
+
15
+ return {
16
+ id,
17
+ title: action.title,
18
+ systemImage: action.systemImage,
19
+ tintColor:
20
+ action.tintColor === undefined
21
+ ? undefined
22
+ : processColor(action.tintColor),
23
+ destructive: action.destructive ?? false,
24
+ };
25
+ });
26
+ }
@@ -0,0 +1,54 @@
1
+ import { forwardRef, type ComponentRef } from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
+
4
+ import { assertComponentEnabled } from '../utils';
5
+ import { serializeSwipeActions } from './actions';
6
+ import NativeSwipeActionsView from './SwipeActionsNativeComponent';
7
+ import type { SwipeActionsProps } from './types';
8
+
9
+ export const SwipeActions = forwardRef<
10
+ ComponentRef<typeof View>,
11
+ SwipeActionsProps
12
+ >(function SwipeActionsRoot(
13
+ {
14
+ actions,
15
+ children,
16
+ contentContainerStyle,
17
+ edge = 'trailing',
18
+ allowsFullSwipe = true,
19
+ disabled = false,
20
+ style,
21
+ ...viewProps
22
+ },
23
+ ref
24
+ ) {
25
+ assertComponentEnabled('SwipeActions');
26
+
27
+ return (
28
+ <NativeSwipeActionsView
29
+ {...viewProps}
30
+ ref={ref}
31
+ actionsConfig={serializeSwipeActions(actions)}
32
+ edge={edge}
33
+ allowsFullSwipe={allowsFullSwipe}
34
+ disabled={disabled}
35
+ style={[styles.container, style]}
36
+ >
37
+ <View collapsable={false} style={[styles.content, contentContainerStyle]}>
38
+ {children}
39
+ </View>
40
+ </NativeSwipeActionsView>
41
+ );
42
+ });
43
+
44
+ const styles = StyleSheet.create({
45
+ container: { overflow: 'hidden' },
46
+ content: { flexGrow: 1 },
47
+ });
48
+
49
+ export type {
50
+ SwipeAction,
51
+ SwipeActionPressEvent,
52
+ SwipeActionsEdge,
53
+ SwipeActionsProps,
54
+ } from './types';
@@ -0,0 +1,37 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { ColorValue, StyleProp, ViewProps, ViewStyle } from 'react-native';
3
+
4
+ export type SwipeActionsEdge = 'leading' | 'trailing';
5
+
6
+ export interface SwipeAction {
7
+ /** Stable identifier. Defaults to `item.<index>` when omitted. */
8
+ id?: string;
9
+ /** Button title and accessible action name. */
10
+ title: string;
11
+ /** SF Symbol name. */
12
+ systemImage?: string;
13
+ /** Native action background color, including semantic and dynamic colors. */
14
+ tintColor?: ColorValue;
15
+ /** Uses the system destructive appearance. Does not remove the React row. */
16
+ destructive?: boolean;
17
+ }
18
+
19
+ export type SwipeActionPressEvent = Readonly<{
20
+ nativeEvent: Readonly<{ id: string; title: string }>;
21
+ }>;
22
+
23
+ export interface SwipeActionsProps extends Omit<ViewProps, 'children'> {
24
+ /** The React Native row content. */
25
+ children: ReactNode;
26
+ /** Styles the moving row, including its background, corners and padding. */
27
+ contentContainerStyle?: StyleProp<ViewStyle>;
28
+ /** Actions ordered from the selected edge inward. */
29
+ actions: readonly SwipeAction[];
30
+ /** Logical edge; respects layout direction. Defaults to `trailing`. */
31
+ edge?: SwipeActionsEdge;
32
+ /** A full swipe performs the first action. Defaults to `true`. */
33
+ allowsFullSwipe?: boolean;
34
+ /** Disables swipe actions without disabling the row's children. */
35
+ disabled?: boolean;
36
+ onActionPress?: (event: SwipeActionPressEvent) => void;
37
+ }
package/src/index.tsx CHANGED
@@ -1,4 +1,11 @@
1
1
  export { Menu } from './Menu';
2
+ export { SwipeActions } from './SwipeActions';
3
+ export type {
4
+ SwipeAction,
5
+ SwipeActionPressEvent,
6
+ SwipeActionsEdge,
7
+ SwipeActionsProps,
8
+ } from './SwipeActions';
2
9
  export { TipKit } from './TipKit';
3
10
  export type {
4
11
  TipAction,
@@ -2,6 +2,7 @@ import NativeTinyui, { type Spec } from '../NativeTinyui';
2
2
 
3
3
  export type TinyuiComponent =
4
4
  | 'Menu'
5
+ | 'SwipeActions'
5
6
  | 'Popover'
6
7
  | 'LiquidGlassText'
7
8
  | 'Stepper'