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.
- package/README.md +60 -1
- package/ios/Core/Tinyui.mm +3 -0
- package/ios/Core/TinyuiComponentClasses.mm +11 -0
- package/ios/SwipeActions/TinyuiSwipeActionsView.h +12 -0
- package/ios/SwipeActions/TinyuiSwipeActionsView.mm +289 -0
- package/lib/module/SwipeActions/SwipeActionsNativeComponent.ts +19 -0
- package/lib/module/SwipeActions/actions.js +21 -0
- package/lib/module/SwipeActions/actions.js.map +1 -0
- package/lib/module/SwipeActions/index.js +43 -0
- package/lib/module/SwipeActions/index.js.map +1 -0
- package/lib/module/SwipeActions/types.js +4 -0
- package/lib/module/SwipeActions/types.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/getNativeTinyui.js.map +1 -1
- package/lib/typescript/src/SwipeActions/SwipeActionsNativeComponent.d.ts +15 -0
- package/lib/typescript/src/SwipeActions/SwipeActionsNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/SwipeActions/actions.d.ts +9 -0
- package/lib/typescript/src/SwipeActions/actions.d.ts.map +1 -0
- package/lib/typescript/src/SwipeActions/index.d.ts +4 -0
- package/lib/typescript/src/SwipeActions/index.d.ts.map +1 -0
- package/lib/typescript/src/SwipeActions/types.d.ts +37 -0
- package/lib/typescript/src/SwipeActions/types.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/getNativeTinyui.d.ts +1 -1
- package/lib/typescript/src/utils/getNativeTinyui.d.ts.map +1 -1
- package/package.json +10 -2
- package/react-native-tinyui.podspec +6 -1
- package/src/SwipeActions/SwipeActionsNativeComponent.ts +19 -0
- package/src/SwipeActions/actions.ts +26 -0
- package/src/SwipeActions/index.tsx +54 -0
- package/src/SwipeActions/types.ts +37 -0
- package/src/index.tsx +7 -0
- 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.
|
package/ios/Core/Tinyui.mm
CHANGED
|
@@ -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,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 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../../src","sources":["SwipeActions/types.ts"],"mappings":"","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -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";
|
package/lib/module/index.js.map
CHANGED
|
@@ -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;
|
|
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.
|
|
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,
|