@drakkar.software/octospaces-ui 0.4.2 → 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/dist/index.d.ts +62 -30
- package/dist/index.js +80 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/sidebar/SpaceSwitcher.tsx +183 -81
|
@@ -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,35 +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
|
|
|
116
172
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
173
|
+
* Render an unread-count badge on a space row.
|
|
174
|
+
* Receives the count (always > 0 when called). Omit to hide badges.
|
|
119
175
|
*/
|
|
120
|
-
|
|
176
|
+
renderBadge?: (count: number) => React.ReactNode;
|
|
121
177
|
|
|
122
178
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* switching and a dropdown is redundant.
|
|
127
|
-
*
|
|
128
|
-
* @example
|
|
129
|
-
* ```tsx
|
|
130
|
-
* // Navigate to space details instead of opening the picker (desktop sidebar)
|
|
131
|
-
* <SpaceSwitcher
|
|
132
|
-
* onTriggerPress={() => router.push(`/space/${activeId}`)}
|
|
133
|
-
* // renderContainer still required but never called when onTriggerPress is set
|
|
134
|
-
* renderContainer={() => null}
|
|
135
|
-
* ...
|
|
136
|
-
* />
|
|
137
|
-
* ```
|
|
179
|
+
* Footer rendered below the space list + action rows — use for account-switcher
|
|
180
|
+
* sections. Receives `close` so the account section can dismiss the dropdown after
|
|
181
|
+
* an action (e.g. `<AccountSwitcher onRequestClose={close} />`). Fully app-owned.
|
|
138
182
|
*/
|
|
139
|
-
|
|
183
|
+
footerSlot?: (close: () => void) => React.ReactNode;
|
|
140
184
|
}
|
|
141
185
|
|
|
142
186
|
// ── Hover-aware Pressable (RN-Web) ────────────────────────────────────────────
|
|
@@ -154,15 +198,21 @@ export function SpaceSwitcher({
|
|
|
154
198
|
onSelect,
|
|
155
199
|
onAdd,
|
|
156
200
|
addLabel = 'Join or create a space',
|
|
201
|
+
onBrowse,
|
|
202
|
+
browseLabel = 'Browse spaces',
|
|
157
203
|
onSettings,
|
|
158
204
|
settingsLabel = 'Space settings',
|
|
205
|
+
maxVisible,
|
|
206
|
+
onSeeAll,
|
|
207
|
+
seeAllLabel = 'See all spaces',
|
|
159
208
|
variant,
|
|
160
209
|
renderContainer,
|
|
161
210
|
renderTriggerAvatar,
|
|
211
|
+
renderTriggerBadge,
|
|
162
212
|
renderSpaceAvatar,
|
|
163
213
|
renderIcon,
|
|
214
|
+
renderBadge,
|
|
164
215
|
footerSlot,
|
|
165
|
-
onTriggerPress,
|
|
166
216
|
}: SpaceSwitcherProps) {
|
|
167
217
|
const theme = useOctoSpacesTheme();
|
|
168
218
|
const { colors, type: typeScale, fonts, spacing: sp, radii } = theme;
|
|
@@ -174,34 +224,32 @@ export function SpaceSwitcher({
|
|
|
174
224
|
const active = spaces.find((s) => s.id === activeId) ?? spaces[0] ?? null;
|
|
175
225
|
|
|
176
226
|
const close = () => setOpen(false);
|
|
177
|
-
const handleSelect = (id: string) => {
|
|
178
|
-
close();
|
|
179
|
-
|
|
180
|
-
};
|
|
181
|
-
const
|
|
182
|
-
close();
|
|
183
|
-
onAdd?.();
|
|
184
|
-
};
|
|
185
|
-
const handleSettings = () => {
|
|
186
|
-
close();
|
|
187
|
-
onSettings?.();
|
|
188
|
-
};
|
|
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?.(); };
|
|
189
232
|
|
|
190
233
|
// ── spacing lookups ──────────────────────────────────────────────────────
|
|
191
|
-
const sp1
|
|
192
|
-
const sp2
|
|
193
|
-
const sp3
|
|
194
|
-
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;
|
|
195
238
|
const radMd = (radii['md'] as number | undefined) ?? 6;
|
|
196
239
|
|
|
197
|
-
const bodyFont
|
|
198
|
-
const bodySize
|
|
199
|
-
const bodyLine
|
|
240
|
+
const bodyFont = fonts['body'] ?? undefined;
|
|
241
|
+
const bodySize = typeScale['callout']?.size ?? 13;
|
|
242
|
+
const bodyLine = typeScale['callout']?.lineHeight ?? 18;
|
|
200
243
|
const labelSize = typeScale['caption']?.size ?? 11;
|
|
201
244
|
const labelLine = typeScale['caption']?.lineHeight ?? 16;
|
|
202
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
|
+
|
|
203
251
|
// ── trigger style ────────────────────────────────────────────────────────
|
|
204
|
-
const
|
|
252
|
+
const baseStyle =
|
|
205
253
|
variant === 'sidebar'
|
|
206
254
|
? {
|
|
207
255
|
flex: 1 as const,
|
|
@@ -212,9 +260,6 @@ export function SpaceSwitcher({
|
|
|
212
260
|
paddingVertical: sp1 + 2,
|
|
213
261
|
borderRadius: radMd,
|
|
214
262
|
minWidth: 0,
|
|
215
|
-
backgroundColor: triggerHovered
|
|
216
|
-
? (colors.primarySubtle ?? 'rgba(0,0,0,0.05)')
|
|
217
|
-
: 'transparent',
|
|
218
263
|
}
|
|
219
264
|
: {
|
|
220
265
|
flexDirection: 'row' as const,
|
|
@@ -224,9 +269,6 @@ export function SpaceSwitcher({
|
|
|
224
269
|
paddingHorizontal: sp2,
|
|
225
270
|
paddingVertical: sp1,
|
|
226
271
|
borderRadius: radMd,
|
|
227
|
-
backgroundColor: triggerHovered
|
|
228
|
-
? (colors.primarySubtle ?? 'rgba(0,0,0,0.05)')
|
|
229
|
-
: 'transparent',
|
|
230
272
|
};
|
|
231
273
|
|
|
232
274
|
// ── dropdown content ─────────────────────────────────────────────────────
|
|
@@ -244,7 +286,7 @@ export function SpaceSwitcher({
|
|
|
244
286
|
/>
|
|
245
287
|
) : null}
|
|
246
288
|
|
|
247
|
-
{
|
|
289
|
+
{visibleSpaces.map((s) => (
|
|
248
290
|
<SpaceRow
|
|
249
291
|
key={s.id}
|
|
250
292
|
space={s}
|
|
@@ -252,6 +294,7 @@ export function SpaceSwitcher({
|
|
|
252
294
|
onPress={() => handleSelect(s.id)}
|
|
253
295
|
renderAvatar={renderSpaceAvatar}
|
|
254
296
|
renderIcon={renderIcon}
|
|
297
|
+
renderBadge={renderBadge}
|
|
255
298
|
colors={colors}
|
|
256
299
|
bodyFont={bodyFont}
|
|
257
300
|
bodySize={bodySize}
|
|
@@ -263,6 +306,23 @@ export function SpaceSwitcher({
|
|
|
263
306
|
/>
|
|
264
307
|
))}
|
|
265
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
|
+
|
|
266
326
|
{onAdd ? (
|
|
267
327
|
<ActionRow
|
|
268
328
|
label={spaces.length > 0 ? addLabel : 'Create your first space'}
|
|
@@ -280,6 +340,23 @@ export function SpaceSwitcher({
|
|
|
280
340
|
/>
|
|
281
341
|
) : null}
|
|
282
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
|
+
|
|
283
360
|
{onSettings && active ? (
|
|
284
361
|
<ActionRow
|
|
285
362
|
label={settingsLabel}
|
|
@@ -307,7 +384,7 @@ export function SpaceSwitcher({
|
|
|
307
384
|
marginHorizontal: sp2,
|
|
308
385
|
}}
|
|
309
386
|
/>
|
|
310
|
-
{footerSlot}
|
|
387
|
+
{footerSlot(close)}
|
|
311
388
|
</>
|
|
312
389
|
) : null}
|
|
313
390
|
</View>
|
|
@@ -321,12 +398,28 @@ export function SpaceSwitcher({
|
|
|
321
398
|
accessibilityLabel={active ? `${active.name} — switch space` : 'Switch space'}
|
|
322
399
|
accessibilityState={{ expanded: open }}
|
|
323
400
|
hitSlop={6}
|
|
324
|
-
onPress={
|
|
401
|
+
onPress={() => setOpen(true)}
|
|
325
402
|
onMouseEnter={() => setTriggerHovered(true)}
|
|
326
403
|
onMouseLeave={() => setTriggerHovered(false)}
|
|
327
|
-
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
|
+
]}
|
|
328
414
|
>
|
|
329
|
-
{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}
|
|
330
423
|
<Text
|
|
331
424
|
numberOfLines={1}
|
|
332
425
|
style={
|
|
@@ -344,16 +437,21 @@ export function SpaceSwitcher({
|
|
|
344
437
|
>
|
|
345
438
|
{active?.name ?? 'Spaces'}
|
|
346
439
|
</Text>
|
|
347
|
-
{
|
|
440
|
+
{renderIcon ? renderIcon('chevron-down', 14, colors.textTertiary) : null}
|
|
348
441
|
</Pressable>
|
|
349
442
|
|
|
350
|
-
{
|
|
443
|
+
{renderContainer({ isOpen: open, onClose: close, anchorRef, children: dropdownContent })}
|
|
351
444
|
</>
|
|
352
445
|
);
|
|
353
446
|
}
|
|
354
447
|
|
|
355
448
|
// ── Internal helpers ──────────────────────────────────────────────────────────
|
|
356
449
|
|
|
450
|
+
const styles = StyleSheet.create({
|
|
451
|
+
avatarWrap: { position: 'relative' },
|
|
452
|
+
triggerBadge: { position: 'absolute', top: -2, right: -2 },
|
|
453
|
+
});
|
|
454
|
+
|
|
357
455
|
interface SectionLabelProps {
|
|
358
456
|
label: string;
|
|
359
457
|
color: string;
|
|
@@ -392,6 +490,7 @@ interface SpaceRowProps {
|
|
|
392
490
|
onPress: () => void;
|
|
393
491
|
renderAvatar?: (space: SwitcherSpace, size: number) => React.ReactNode;
|
|
394
492
|
renderIcon?: (name: SwitcherIconName, size: number, color: string) => React.ReactNode;
|
|
493
|
+
renderBadge?: (count: number) => React.ReactNode;
|
|
395
494
|
colors: ReturnType<typeof useOctoSpacesTheme>['colors'];
|
|
396
495
|
bodyFont: string | undefined;
|
|
397
496
|
bodySize: number;
|
|
@@ -408,6 +507,7 @@ function SpaceRow({
|
|
|
408
507
|
onPress,
|
|
409
508
|
renderAvatar,
|
|
410
509
|
renderIcon,
|
|
510
|
+
renderBadge,
|
|
411
511
|
colors,
|
|
412
512
|
bodyFont,
|
|
413
513
|
bodySize,
|
|
@@ -418,10 +518,7 @@ function SpaceRow({
|
|
|
418
518
|
radMd,
|
|
419
519
|
}: SpaceRowProps) {
|
|
420
520
|
const [hovered, setHovered] = useState(false);
|
|
421
|
-
|
|
422
|
-
const bg = hovered
|
|
423
|
-
? (colors.primarySubtle ?? 'rgba(0,0,0,0.04)')
|
|
424
|
-
: 'transparent';
|
|
521
|
+
const unread = space.unread ?? 0;
|
|
425
522
|
|
|
426
523
|
return (
|
|
427
524
|
<Pressable
|
|
@@ -431,15 +528,19 @@ function SpaceRow({
|
|
|
431
528
|
onPress={onPress}
|
|
432
529
|
onMouseEnter={() => setHovered(true)}
|
|
433
530
|
onMouseLeave={() => setHovered(false)}
|
|
434
|
-
style={{
|
|
435
|
-
flexDirection: 'row',
|
|
436
|
-
alignItems: 'center',
|
|
531
|
+
style={({ pressed }) => ({
|
|
532
|
+
flexDirection: 'row' as const,
|
|
533
|
+
alignItems: 'center' as const,
|
|
437
534
|
gap: sp3,
|
|
438
535
|
paddingHorizontal: sp4,
|
|
439
536
|
paddingVertical: sp2,
|
|
440
537
|
borderRadius: radMd,
|
|
441
|
-
backgroundColor:
|
|
442
|
-
|
|
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
|
+
})}
|
|
443
544
|
>
|
|
444
545
|
{renderAvatar ? renderAvatar(space, 24) : null}
|
|
445
546
|
<Text
|
|
@@ -458,6 +559,7 @@ function SpaceRow({
|
|
|
458
559
|
>
|
|
459
560
|
{space.name}
|
|
460
561
|
</Text>
|
|
562
|
+
{unread > 0 && renderBadge ? renderBadge(unread) : null}
|
|
461
563
|
{active && renderIcon ? renderIcon('check', 15, colors.primary) : null}
|
|
462
564
|
</Pressable>
|
|
463
565
|
);
|
|
@@ -494,10 +596,6 @@ function ActionRow({
|
|
|
494
596
|
}: ActionRowProps) {
|
|
495
597
|
const [hovered, setHovered] = useState(false);
|
|
496
598
|
|
|
497
|
-
const bg = hovered
|
|
498
|
-
? (colors.primarySubtle ?? 'rgba(0,0,0,0.04)')
|
|
499
|
-
: 'transparent';
|
|
500
|
-
|
|
501
599
|
return (
|
|
502
600
|
<Pressable
|
|
503
601
|
accessibilityRole="menuitem"
|
|
@@ -505,15 +603,19 @@ function ActionRow({
|
|
|
505
603
|
onPress={onPress}
|
|
506
604
|
onMouseEnter={() => setHovered(true)}
|
|
507
605
|
onMouseLeave={() => setHovered(false)}
|
|
508
|
-
style={{
|
|
509
|
-
flexDirection: 'row',
|
|
510
|
-
alignItems: 'center',
|
|
606
|
+
style={({ pressed }) => ({
|
|
607
|
+
flexDirection: 'row' as const,
|
|
608
|
+
alignItems: 'center' as const,
|
|
511
609
|
gap: sp3,
|
|
512
610
|
paddingHorizontal: sp4,
|
|
513
611
|
paddingVertical: sp2,
|
|
514
612
|
borderRadius: radMd,
|
|
515
|
-
backgroundColor:
|
|
516
|
-
|
|
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
|
+
})}
|
|
517
619
|
>
|
|
518
620
|
{renderIcon ? (
|
|
519
621
|
<View style={{ width: 24, alignItems: 'center', justifyContent: 'center' }}>
|