@drakkar.software/octospaces-ui 0.4.1 → 0.4.3
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/CHANGELOG.md +34 -0
- package/dist/index.d.ts +63 -13
- package/dist/index.js +76 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/sidebar/SpaceSwitcher.tsx +182 -60
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* Headless themed space-switcher component.
|
|
3
3
|
*
|
|
4
4
|
* Renders a trigger button (active-space avatar + name + chevron) that opens a
|
|
5
|
-
* dropdown listing all spaces with per-row selection
|
|
5
|
+
* dropdown listing all spaces with per-row selection (+ optional unread badges),
|
|
6
|
+
* a "see all" overflow row, a "join or create" action, a "browse spaces" action,
|
|
6
7
|
* optional space settings, and an app-provided footer slot (account section, etc.).
|
|
7
8
|
*
|
|
8
9
|
* The popup container (Popover on desktop, Sheet on mobile) is fully delegated to
|
|
9
10
|
* the host via `renderContainer` so this package stays free of modal dependencies.
|
|
10
|
-
* Avatars and
|
|
11
|
+
* Avatars, icons and badges are delegated via render-props for the same reason.
|
|
11
12
|
*
|
|
12
13
|
* @example
|
|
13
14
|
* ```tsx
|
|
@@ -27,13 +28,34 @@
|
|
|
27
28
|
* )}
|
|
28
29
|
* renderIcon={(name, size, color) => <Icon name={SWITCHER_ICON[name]} size={size} color={color} />}
|
|
29
30
|
* renderContainer={({ isOpen, onClose, anchorRef, children }) => (
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* </Popover>
|
|
34
|
-
* </>
|
|
31
|
+
* <Popover visible={isOpen} onClose={onClose} anchorRef={anchorRef} placement="bottom-start" width={240}>
|
|
32
|
+
* {children}
|
|
33
|
+
* </Popover>
|
|
35
34
|
* )}
|
|
36
|
-
* footerSlot={<AccountSwitcher onRequestClose={
|
|
35
|
+
* footerSlot={(close) => <AccountSwitcher onRequestClose={close} onViewProfile={...} />}
|
|
36
|
+
* />
|
|
37
|
+
*
|
|
38
|
+
* // OctoChat — appbar variant with bottom Sheet, overflow + badges
|
|
39
|
+
* <SpaceSwitcher
|
|
40
|
+
* spaces={spaces}
|
|
41
|
+
* activeId={activeId}
|
|
42
|
+
* onSelect={(id) => { tapFeedback(); setActiveId(id); }}
|
|
43
|
+
* onAdd={() => router.push('/join')}
|
|
44
|
+
* onBrowse={() => router.push('/spaces/explore')}
|
|
45
|
+
* onSettings={() => router.push(`/space/${activeId}`)}
|
|
46
|
+
* maxVisible={5}
|
|
47
|
+
* onSeeAll={() => router.push('/spaces')}
|
|
48
|
+
* seeAllLabel="See all spaces"
|
|
49
|
+
* variant="appbar"
|
|
50
|
+
* renderTriggerAvatar={(space, size) => <Avatar label={space?.short ?? ''} image={space?.image} size={size} />}
|
|
51
|
+
* renderSpaceAvatar={(space, size) => <Avatar label={space.short ?? ''} image={space.image} size={size} />}
|
|
52
|
+
* renderIcon={(name, size, color) => <Icon name={SWITCHER_ICON[name]} size={size} color={color} />}
|
|
53
|
+
* renderBadge={(count) => <Badge count={count} />}
|
|
54
|
+
* renderTriggerBadge={() => <UnreadDot />}
|
|
55
|
+
* renderContainer={({ isOpen, onClose, children }) => (
|
|
56
|
+
* <BottomSheet visible={isOpen} onClose={onClose}>{children}</BottomSheet>
|
|
57
|
+
* )}
|
|
58
|
+
* footerSlot={(close) => <AccountSwitcher onRequestClose={close} onViewProfile={...} />}
|
|
37
59
|
* />
|
|
38
60
|
* ```
|
|
39
61
|
*/
|
|
@@ -53,20 +75,35 @@ export interface SwitcherSpace {
|
|
|
53
75
|
short?: string;
|
|
54
76
|
/** Uploaded space image URI; absent → host renders monogram. */
|
|
55
77
|
image?: string;
|
|
78
|
+
/** Unread message count displayed as a badge on the row. */
|
|
79
|
+
unread?: number;
|
|
56
80
|
}
|
|
57
81
|
|
|
58
82
|
/** Icon name union for the switcher's built-in glyphs. */
|
|
59
|
-
export type SwitcherIconName =
|
|
83
|
+
export type SwitcherIconName =
|
|
84
|
+
| 'chevron-down'
|
|
85
|
+
| 'chevron-right'
|
|
86
|
+
| 'check'
|
|
87
|
+
| 'plus'
|
|
88
|
+
| 'gear'
|
|
89
|
+
| 'globe';
|
|
60
90
|
|
|
61
91
|
export interface SpaceSwitcherProps {
|
|
62
92
|
spaces: SwitcherSpace[];
|
|
63
93
|
activeId?: string | null;
|
|
64
94
|
/** Called when the user taps a space row. */
|
|
65
95
|
onSelect: (id: string) => void;
|
|
96
|
+
|
|
66
97
|
/** "Join or create a space" action. Omit to hide the row. */
|
|
67
98
|
onAdd?: () => void;
|
|
68
99
|
/** Override the add-row label. @default "Join or create a space" */
|
|
69
100
|
addLabel?: string;
|
|
101
|
+
|
|
102
|
+
/** "Browse spaces" action (e.g. a public directory). Omit to hide the row. */
|
|
103
|
+
onBrowse?: () => void;
|
|
104
|
+
/** Override the browse-row label. @default "Browse spaces" */
|
|
105
|
+
browseLabel?: string;
|
|
106
|
+
|
|
70
107
|
/**
|
|
71
108
|
* "Space settings" action. Only shown when both `onSettings` and `activeId`
|
|
72
109
|
* are provided. Omit to hide.
|
|
@@ -74,6 +111,19 @@ export interface SpaceSwitcherProps {
|
|
|
74
111
|
onSettings?: () => void;
|
|
75
112
|
/** Override the settings-row label. @default "Space settings" */
|
|
76
113
|
settingsLabel?: string;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* When set, limits how many space rows are rendered inline.
|
|
117
|
+
* If `spaces.length > maxVisible` AND `onSeeAll` is also set, a "See all"
|
|
118
|
+
* row is appended after the visible rows. Without `onSeeAll`, overflow rows
|
|
119
|
+
* are simply hidden.
|
|
120
|
+
*/
|
|
121
|
+
maxVisible?: number;
|
|
122
|
+
/** Called when the user taps the "See all" overflow row. */
|
|
123
|
+
onSeeAll?: () => void;
|
|
124
|
+
/** Override the see-all-row label. @default "See all spaces" */
|
|
125
|
+
seeAllLabel?: string;
|
|
126
|
+
|
|
77
127
|
/**
|
|
78
128
|
* Visual variant:
|
|
79
129
|
* - `'sidebar'` — compact left-aligned trigger for the desktop sidebar header.
|
|
@@ -100,6 +150,12 @@ export interface SpaceSwitcherProps {
|
|
|
100
150
|
*/
|
|
101
151
|
renderTriggerAvatar?: (space: SwitcherSpace | null, size: number) => React.ReactNode;
|
|
102
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Render an overlay node anchored top-right of the trigger avatar — used for
|
|
155
|
+
* an "other spaces have unread" aggregate indicator. Omit to hide the overlay.
|
|
156
|
+
*/
|
|
157
|
+
renderTriggerBadge?: () => React.ReactNode;
|
|
158
|
+
|
|
103
159
|
/**
|
|
104
160
|
* Render a space row's leading avatar.
|
|
105
161
|
* Receives the `SwitcherSpace` and a pixel size.
|
|
@@ -108,16 +164,23 @@ export interface SpaceSwitcherProps {
|
|
|
108
164
|
renderSpaceAvatar?: (space: SwitcherSpace, size: number) => React.ReactNode;
|
|
109
165
|
|
|
110
166
|
/**
|
|
111
|
-
* Render an icon glyph. Name is one of `
|
|
167
|
+
* Render an icon glyph. Name is one of the `SwitcherIconName` union values.
|
|
112
168
|
* Omit to hide chevron, check, and action icons (spaces remain selectable).
|
|
113
169
|
*/
|
|
114
170
|
renderIcon?: (name: SwitcherIconName, size: number, color: string) => React.ReactNode;
|
|
115
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Render an unread-count badge on a space row.
|
|
174
|
+
* Receives the count (always > 0 when called). Omit to hide badges.
|
|
175
|
+
*/
|
|
176
|
+
renderBadge?: (count: number) => React.ReactNode;
|
|
177
|
+
|
|
116
178
|
/**
|
|
117
179
|
* Footer rendered below the space list + action rows — use for account-switcher
|
|
118
|
-
* sections
|
|
180
|
+
* sections. Receives `close` so the account section can dismiss the dropdown after
|
|
181
|
+
* an action (e.g. `<AccountSwitcher onRequestClose={close} />`). Fully app-owned.
|
|
119
182
|
*/
|
|
120
|
-
footerSlot?: React.ReactNode;
|
|
183
|
+
footerSlot?: (close: () => void) => React.ReactNode;
|
|
121
184
|
}
|
|
122
185
|
|
|
123
186
|
// ── Hover-aware Pressable (RN-Web) ────────────────────────────────────────────
|
|
@@ -135,13 +198,20 @@ export function SpaceSwitcher({
|
|
|
135
198
|
onSelect,
|
|
136
199
|
onAdd,
|
|
137
200
|
addLabel = 'Join or create a space',
|
|
201
|
+
onBrowse,
|
|
202
|
+
browseLabel = 'Browse spaces',
|
|
138
203
|
onSettings,
|
|
139
204
|
settingsLabel = 'Space settings',
|
|
205
|
+
maxVisible,
|
|
206
|
+
onSeeAll,
|
|
207
|
+
seeAllLabel = 'See all spaces',
|
|
140
208
|
variant,
|
|
141
209
|
renderContainer,
|
|
142
210
|
renderTriggerAvatar,
|
|
211
|
+
renderTriggerBadge,
|
|
143
212
|
renderSpaceAvatar,
|
|
144
213
|
renderIcon,
|
|
214
|
+
renderBadge,
|
|
145
215
|
footerSlot,
|
|
146
216
|
}: SpaceSwitcherProps) {
|
|
147
217
|
const theme = useOctoSpacesTheme();
|
|
@@ -154,34 +224,32 @@ export function SpaceSwitcher({
|
|
|
154
224
|
const active = spaces.find((s) => s.id === activeId) ?? spaces[0] ?? null;
|
|
155
225
|
|
|
156
226
|
const close = () => setOpen(false);
|
|
157
|
-
const handleSelect = (id: string) => {
|
|
158
|
-
close();
|
|
159
|
-
|
|
160
|
-
};
|
|
161
|
-
const
|
|
162
|
-
close();
|
|
163
|
-
onAdd?.();
|
|
164
|
-
};
|
|
165
|
-
const handleSettings = () => {
|
|
166
|
-
close();
|
|
167
|
-
onSettings?.();
|
|
168
|
-
};
|
|
227
|
+
const handleSelect = (id: string) => { close(); onSelect(id); };
|
|
228
|
+
const handleAdd = () => { close(); onAdd?.(); };
|
|
229
|
+
const handleBrowse = () => { close(); onBrowse?.(); };
|
|
230
|
+
const handleSettings = () => { close(); onSettings?.(); };
|
|
231
|
+
const handleSeeAll = () => { close(); onSeeAll?.(); };
|
|
169
232
|
|
|
170
233
|
// ── spacing lookups ──────────────────────────────────────────────────────
|
|
171
|
-
const sp1
|
|
172
|
-
const sp2
|
|
173
|
-
const sp3
|
|
174
|
-
const sp4
|
|
234
|
+
const sp1 = (sp['1'] as number | undefined) ?? 4;
|
|
235
|
+
const sp2 = (sp['2'] as number | undefined) ?? 8;
|
|
236
|
+
const sp3 = (sp['3'] as number | undefined) ?? 12;
|
|
237
|
+
const sp4 = (sp['4'] as number | undefined) ?? 16;
|
|
175
238
|
const radMd = (radii['md'] as number | undefined) ?? 6;
|
|
176
239
|
|
|
177
|
-
const bodyFont
|
|
178
|
-
const bodySize
|
|
179
|
-
const bodyLine
|
|
240
|
+
const bodyFont = fonts['body'] ?? undefined;
|
|
241
|
+
const bodySize = typeScale['callout']?.size ?? 13;
|
|
242
|
+
const bodyLine = typeScale['callout']?.lineHeight ?? 18;
|
|
180
243
|
const labelSize = typeScale['caption']?.size ?? 11;
|
|
181
244
|
const labelLine = typeScale['caption']?.lineHeight ?? 16;
|
|
182
245
|
|
|
246
|
+
// ── overflow: which rows to show inline ─────────────────────────────────
|
|
247
|
+
const overflow =
|
|
248
|
+
maxVisible != null && onSeeAll != null && spaces.length > maxVisible;
|
|
249
|
+
const visibleSpaces = overflow ? spaces.slice(0, maxVisible) : spaces;
|
|
250
|
+
|
|
183
251
|
// ── trigger style ────────────────────────────────────────────────────────
|
|
184
|
-
const
|
|
252
|
+
const baseStyle =
|
|
185
253
|
variant === 'sidebar'
|
|
186
254
|
? {
|
|
187
255
|
flex: 1 as const,
|
|
@@ -192,9 +260,6 @@ export function SpaceSwitcher({
|
|
|
192
260
|
paddingVertical: sp1 + 2,
|
|
193
261
|
borderRadius: radMd,
|
|
194
262
|
minWidth: 0,
|
|
195
|
-
backgroundColor: triggerHovered
|
|
196
|
-
? (colors.primarySubtle ?? 'rgba(0,0,0,0.05)')
|
|
197
|
-
: 'transparent',
|
|
198
263
|
}
|
|
199
264
|
: {
|
|
200
265
|
flexDirection: 'row' as const,
|
|
@@ -204,9 +269,6 @@ export function SpaceSwitcher({
|
|
|
204
269
|
paddingHorizontal: sp2,
|
|
205
270
|
paddingVertical: sp1,
|
|
206
271
|
borderRadius: radMd,
|
|
207
|
-
backgroundColor: triggerHovered
|
|
208
|
-
? (colors.primarySubtle ?? 'rgba(0,0,0,0.05)')
|
|
209
|
-
: 'transparent',
|
|
210
272
|
};
|
|
211
273
|
|
|
212
274
|
// ── dropdown content ─────────────────────────────────────────────────────
|
|
@@ -224,7 +286,7 @@ export function SpaceSwitcher({
|
|
|
224
286
|
/>
|
|
225
287
|
) : null}
|
|
226
288
|
|
|
227
|
-
{
|
|
289
|
+
{visibleSpaces.map((s) => (
|
|
228
290
|
<SpaceRow
|
|
229
291
|
key={s.id}
|
|
230
292
|
space={s}
|
|
@@ -232,6 +294,7 @@ export function SpaceSwitcher({
|
|
|
232
294
|
onPress={() => handleSelect(s.id)}
|
|
233
295
|
renderAvatar={renderSpaceAvatar}
|
|
234
296
|
renderIcon={renderIcon}
|
|
297
|
+
renderBadge={renderBadge}
|
|
235
298
|
colors={colors}
|
|
236
299
|
bodyFont={bodyFont}
|
|
237
300
|
bodySize={bodySize}
|
|
@@ -243,6 +306,23 @@ export function SpaceSwitcher({
|
|
|
243
306
|
/>
|
|
244
307
|
))}
|
|
245
308
|
|
|
309
|
+
{overflow ? (
|
|
310
|
+
<ActionRow
|
|
311
|
+
label={seeAllLabel}
|
|
312
|
+
iconName="chevron-right"
|
|
313
|
+
onPress={handleSeeAll}
|
|
314
|
+
renderIcon={renderIcon}
|
|
315
|
+
colors={colors}
|
|
316
|
+
bodyFont={bodyFont}
|
|
317
|
+
bodySize={bodySize}
|
|
318
|
+
bodyLine={bodyLine}
|
|
319
|
+
sp2={sp2}
|
|
320
|
+
sp3={sp3}
|
|
321
|
+
sp4={sp4}
|
|
322
|
+
radMd={radMd}
|
|
323
|
+
/>
|
|
324
|
+
) : null}
|
|
325
|
+
|
|
246
326
|
{onAdd ? (
|
|
247
327
|
<ActionRow
|
|
248
328
|
label={spaces.length > 0 ? addLabel : 'Create your first space'}
|
|
@@ -260,6 +340,23 @@ export function SpaceSwitcher({
|
|
|
260
340
|
/>
|
|
261
341
|
) : null}
|
|
262
342
|
|
|
343
|
+
{onBrowse ? (
|
|
344
|
+
<ActionRow
|
|
345
|
+
label={browseLabel}
|
|
346
|
+
iconName="globe"
|
|
347
|
+
onPress={handleBrowse}
|
|
348
|
+
renderIcon={renderIcon}
|
|
349
|
+
colors={colors}
|
|
350
|
+
bodyFont={bodyFont}
|
|
351
|
+
bodySize={bodySize}
|
|
352
|
+
bodyLine={bodyLine}
|
|
353
|
+
sp2={sp2}
|
|
354
|
+
sp3={sp3}
|
|
355
|
+
sp4={sp4}
|
|
356
|
+
radMd={radMd}
|
|
357
|
+
/>
|
|
358
|
+
) : null}
|
|
359
|
+
|
|
263
360
|
{onSettings && active ? (
|
|
264
361
|
<ActionRow
|
|
265
362
|
label={settingsLabel}
|
|
@@ -287,7 +384,7 @@ export function SpaceSwitcher({
|
|
|
287
384
|
marginHorizontal: sp2,
|
|
288
385
|
}}
|
|
289
386
|
/>
|
|
290
|
-
{footerSlot}
|
|
387
|
+
{footerSlot(close)}
|
|
291
388
|
</>
|
|
292
389
|
) : null}
|
|
293
390
|
</View>
|
|
@@ -304,9 +401,25 @@ export function SpaceSwitcher({
|
|
|
304
401
|
onPress={() => setOpen(true)}
|
|
305
402
|
onMouseEnter={() => setTriggerHovered(true)}
|
|
306
403
|
onMouseLeave={() => setTriggerHovered(false)}
|
|
307
|
-
style={
|
|
404
|
+
style={({ pressed }) => [
|
|
405
|
+
baseStyle,
|
|
406
|
+
{
|
|
407
|
+
backgroundColor: pressed
|
|
408
|
+
? (colors.primarySubtle ?? 'rgba(0,0,0,0.08)')
|
|
409
|
+
: triggerHovered
|
|
410
|
+
? (colors.primarySubtle ?? 'rgba(0,0,0,0.05)')
|
|
411
|
+
: 'transparent',
|
|
412
|
+
},
|
|
413
|
+
]}
|
|
308
414
|
>
|
|
309
|
-
{renderTriggerAvatar
|
|
415
|
+
{renderTriggerAvatar != null || renderTriggerBadge != null ? (
|
|
416
|
+
<View style={styles.avatarWrap}>
|
|
417
|
+
{renderTriggerAvatar ? renderTriggerAvatar(active, 22) : null}
|
|
418
|
+
{renderTriggerBadge ? (
|
|
419
|
+
<View style={styles.triggerBadge}>{renderTriggerBadge()}</View>
|
|
420
|
+
) : null}
|
|
421
|
+
</View>
|
|
422
|
+
) : null}
|
|
310
423
|
<Text
|
|
311
424
|
numberOfLines={1}
|
|
312
425
|
style={
|
|
@@ -334,6 +447,11 @@ export function SpaceSwitcher({
|
|
|
334
447
|
|
|
335
448
|
// ── Internal helpers ──────────────────────────────────────────────────────────
|
|
336
449
|
|
|
450
|
+
const styles = StyleSheet.create({
|
|
451
|
+
avatarWrap: { position: 'relative' },
|
|
452
|
+
triggerBadge: { position: 'absolute', top: -2, right: -2 },
|
|
453
|
+
});
|
|
454
|
+
|
|
337
455
|
interface SectionLabelProps {
|
|
338
456
|
label: string;
|
|
339
457
|
color: string;
|
|
@@ -372,6 +490,7 @@ interface SpaceRowProps {
|
|
|
372
490
|
onPress: () => void;
|
|
373
491
|
renderAvatar?: (space: SwitcherSpace, size: number) => React.ReactNode;
|
|
374
492
|
renderIcon?: (name: SwitcherIconName, size: number, color: string) => React.ReactNode;
|
|
493
|
+
renderBadge?: (count: number) => React.ReactNode;
|
|
375
494
|
colors: ReturnType<typeof useOctoSpacesTheme>['colors'];
|
|
376
495
|
bodyFont: string | undefined;
|
|
377
496
|
bodySize: number;
|
|
@@ -388,6 +507,7 @@ function SpaceRow({
|
|
|
388
507
|
onPress,
|
|
389
508
|
renderAvatar,
|
|
390
509
|
renderIcon,
|
|
510
|
+
renderBadge,
|
|
391
511
|
colors,
|
|
392
512
|
bodyFont,
|
|
393
513
|
bodySize,
|
|
@@ -398,10 +518,7 @@ function SpaceRow({
|
|
|
398
518
|
radMd,
|
|
399
519
|
}: SpaceRowProps) {
|
|
400
520
|
const [hovered, setHovered] = useState(false);
|
|
401
|
-
|
|
402
|
-
const bg = hovered
|
|
403
|
-
? (colors.primarySubtle ?? 'rgba(0,0,0,0.04)')
|
|
404
|
-
: 'transparent';
|
|
521
|
+
const unread = space.unread ?? 0;
|
|
405
522
|
|
|
406
523
|
return (
|
|
407
524
|
<Pressable
|
|
@@ -411,15 +528,19 @@ function SpaceRow({
|
|
|
411
528
|
onPress={onPress}
|
|
412
529
|
onMouseEnter={() => setHovered(true)}
|
|
413
530
|
onMouseLeave={() => setHovered(false)}
|
|
414
|
-
style={{
|
|
415
|
-
flexDirection: 'row',
|
|
416
|
-
alignItems: 'center',
|
|
531
|
+
style={({ pressed }) => ({
|
|
532
|
+
flexDirection: 'row' as const,
|
|
533
|
+
alignItems: 'center' as const,
|
|
417
534
|
gap: sp3,
|
|
418
535
|
paddingHorizontal: sp4,
|
|
419
536
|
paddingVertical: sp2,
|
|
420
537
|
borderRadius: radMd,
|
|
421
|
-
backgroundColor:
|
|
422
|
-
|
|
538
|
+
backgroundColor: pressed
|
|
539
|
+
? (colors.primarySubtle ?? 'rgba(0,0,0,0.08)')
|
|
540
|
+
: hovered
|
|
541
|
+
? (colors.primarySubtle ?? 'rgba(0,0,0,0.04)')
|
|
542
|
+
: 'transparent',
|
|
543
|
+
})}
|
|
423
544
|
>
|
|
424
545
|
{renderAvatar ? renderAvatar(space, 24) : null}
|
|
425
546
|
<Text
|
|
@@ -438,6 +559,7 @@ function SpaceRow({
|
|
|
438
559
|
>
|
|
439
560
|
{space.name}
|
|
440
561
|
</Text>
|
|
562
|
+
{unread > 0 && renderBadge ? renderBadge(unread) : null}
|
|
441
563
|
{active && renderIcon ? renderIcon('check', 15, colors.primary) : null}
|
|
442
564
|
</Pressable>
|
|
443
565
|
);
|
|
@@ -474,10 +596,6 @@ function ActionRow({
|
|
|
474
596
|
}: ActionRowProps) {
|
|
475
597
|
const [hovered, setHovered] = useState(false);
|
|
476
598
|
|
|
477
|
-
const bg = hovered
|
|
478
|
-
? (colors.primarySubtle ?? 'rgba(0,0,0,0.04)')
|
|
479
|
-
: 'transparent';
|
|
480
|
-
|
|
481
599
|
return (
|
|
482
600
|
<Pressable
|
|
483
601
|
accessibilityRole="menuitem"
|
|
@@ -485,15 +603,19 @@ function ActionRow({
|
|
|
485
603
|
onPress={onPress}
|
|
486
604
|
onMouseEnter={() => setHovered(true)}
|
|
487
605
|
onMouseLeave={() => setHovered(false)}
|
|
488
|
-
style={{
|
|
489
|
-
flexDirection: 'row',
|
|
490
|
-
alignItems: 'center',
|
|
606
|
+
style={({ pressed }) => ({
|
|
607
|
+
flexDirection: 'row' as const,
|
|
608
|
+
alignItems: 'center' as const,
|
|
491
609
|
gap: sp3,
|
|
492
610
|
paddingHorizontal: sp4,
|
|
493
611
|
paddingVertical: sp2,
|
|
494
612
|
borderRadius: radMd,
|
|
495
|
-
backgroundColor:
|
|
496
|
-
|
|
613
|
+
backgroundColor: pressed
|
|
614
|
+
? (colors.primarySubtle ?? 'rgba(0,0,0,0.08)')
|
|
615
|
+
: hovered
|
|
616
|
+
? (colors.primarySubtle ?? 'rgba(0,0,0,0.04)')
|
|
617
|
+
: 'transparent',
|
|
618
|
+
})}
|
|
497
619
|
>
|
|
498
620
|
{renderIcon ? (
|
|
499
621
|
<View style={{ width: 24, alignItems: 'center', justifyContent: 'center' }}>
|