@tastic/profile 0.14.0 → 0.14.1
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.js +41 -30
- package/dist/index.mjs +41 -30
- package/package.json +1 -1
- package/src/ProfilePicker.tsx +29 -17
package/dist/index.js
CHANGED
|
@@ -167,13 +167,14 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
167
167
|
host.toggle(id);
|
|
168
168
|
};
|
|
169
169
|
const triggerLabel = (selectedProfile?.name ?? guestLabel).toUpperCase();
|
|
170
|
+
const manageFooter = !!onManage && !(colorSection && colorPage);
|
|
170
171
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: [styles2.anchor, open && styles2.anchorOpen], onLayout: handleAnchorLayout, children: [
|
|
171
172
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.TouchableRipple, { onPress: handleTriggerPress, borderless: chipTrigger, style: [styles2.trigger, chipTrigger && styles2.chipTrigger, triggerStyle], accessibilityRole: "button", accessibilityLabel: triggerLabel, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { ref: triggerRef, collapsable: false, style: chipTrigger ? styles2.chipTriggerInner : styles2.triggerInner, children: [
|
|
172
173
|
chipTrigger && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(IdentityChip, { color, tag: selectedProfile?.tag, icon: selectedProfile ? "account" : nullIcon, size: CHIP_SIZE }),
|
|
173
174
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles2.triggerLabel, { color: chipTrigger ? fg : color }], numberOfLines: 1, children: triggerLabel }),
|
|
174
175
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "menu-down", size: 16, color: chipTrigger ? fg : color })
|
|
175
176
|
] }) }),
|
|
176
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_hud.PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: chipTrigger ? triggerWidth : TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime4.
|
|
177
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_hud.PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: chipTrigger ? triggerWidth : TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
177
178
|
import_react_native2.View,
|
|
178
179
|
{
|
|
179
180
|
style: [
|
|
@@ -185,41 +186,43 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
185
186
|
maxHeight
|
|
186
187
|
}
|
|
187
188
|
],
|
|
188
|
-
children:
|
|
189
|
-
colorSection && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
190
|
-
|
|
191
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
189
|
+
children: [
|
|
190
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_auto_paper2.FadingScrollView, { contentContainerStyle: [styles2.menuContent, manageFooter && styles2.menuContentAboveFooter], showsVerticalScrollIndicator: false, children: colorSection && colorPage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ColorPage, { section: colorSection, profileColor: selectedProfile?.color, fg, onBack: () => setColorPage(false) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
191
|
+
colorSection && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ColorRow, { section: colorSection, fg, dividerColor: color, onPress: () => setColorPage(true) }),
|
|
192
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.TouchableRipple, { onPress: handleSelectGuest, style: [styles2.row, selectedId === null && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: styles2.rowInner, children: [
|
|
193
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, { style: styles2.guestChip, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: nullIcon, size: 13, color: selectedId === null ? (0, import_auto_paper2.getContrastColor)(color) : fg }) }),
|
|
194
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles2.rowLabel, { color: selectedId === null ? (0, import_auto_paper2.getContrastColor)(color) : fg }], children: nullLabel })
|
|
195
|
+
] }) }),
|
|
196
|
+
sortedProfiles.map((profile) => {
|
|
197
|
+
const taken = profile.id === takenId;
|
|
198
|
+
const selected = selectedId === profile.id;
|
|
199
|
+
const rowColor = colorPreview ? colorPreview(profile.color) : profile.color;
|
|
200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.TouchableRipple, { disabled: taken, onPress: () => handleSelectExisting(profile), style: [styles2.row, selected && { backgroundColor: rowColor }], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: [styles2.rowInner, taken && styles2.rowDisabled], children: [
|
|
201
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ProfileChip, { profile, filled: !selected }),
|
|
202
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
203
|
+
import_react_native_paper2.Text,
|
|
204
|
+
{
|
|
205
|
+
style: [
|
|
206
|
+
styles2.rowLabel,
|
|
207
|
+
{
|
|
208
|
+
color: selected ? (0, import_auto_paper2.getContrastColor)(rowColor) : fg
|
|
209
|
+
}
|
|
210
|
+
],
|
|
211
|
+
numberOfLines: 1,
|
|
212
|
+
children: profile.name
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
] }) }, profile.id);
|
|
216
|
+
})
|
|
217
|
+
] }) }, colorSection && colorPage ? "color" : "list"),
|
|
218
|
+
manageFooter && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: styles2.menuFooter, children: [
|
|
216
219
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, { style: [styles2.divider, { backgroundColor: color }] }),
|
|
217
220
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.TouchableRipple, { onPress: handleManage, style: styles2.row, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: styles2.manageRowInner, children: [
|
|
218
221
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "account-cog-outline", size: 16, color }),
|
|
219
222
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles2.manageLabel, { color: fg }], children: "Manage" })
|
|
220
223
|
] }) })
|
|
221
224
|
] })
|
|
222
|
-
]
|
|
225
|
+
]
|
|
223
226
|
}
|
|
224
227
|
) })
|
|
225
228
|
] });
|
|
@@ -345,6 +348,14 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
345
348
|
menuContent: {
|
|
346
349
|
padding: LIST_PADDING
|
|
347
350
|
},
|
|
351
|
+
// With Manage pinned below, its own padding takes the bottom edge (same total height as before).
|
|
352
|
+
menuContentAboveFooter: {
|
|
353
|
+
paddingBottom: 0
|
|
354
|
+
},
|
|
355
|
+
menuFooter: {
|
|
356
|
+
paddingBottom: LIST_PADDING,
|
|
357
|
+
paddingHorizontal: LIST_PADDING
|
|
358
|
+
},
|
|
348
359
|
// The selected profile's own color (see ColorSection).
|
|
349
360
|
profileDot: {
|
|
350
361
|
borderRadius: 4,
|
package/dist/index.mjs
CHANGED
|
@@ -124,13 +124,14 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
124
124
|
host.toggle(id);
|
|
125
125
|
};
|
|
126
126
|
const triggerLabel = (selectedProfile?.name ?? guestLabel).toUpperCase();
|
|
127
|
+
const manageFooter = !!onManage && !(colorSection && colorPage);
|
|
127
128
|
return /* @__PURE__ */ jsxs(View2, { style: [styles2.anchor, open && styles2.anchorOpen], onLayout: handleAnchorLayout, children: [
|
|
128
129
|
/* @__PURE__ */ jsx4(TouchableRipple, { onPress: handleTriggerPress, borderless: chipTrigger, style: [styles2.trigger, chipTrigger && styles2.chipTrigger, triggerStyle], accessibilityRole: "button", accessibilityLabel: triggerLabel, children: /* @__PURE__ */ jsxs(View2, { ref: triggerRef, collapsable: false, style: chipTrigger ? styles2.chipTriggerInner : styles2.triggerInner, children: [
|
|
129
130
|
chipTrigger && /* @__PURE__ */ jsx4(IdentityChip, { color, tag: selectedProfile?.tag, icon: selectedProfile ? "account" : nullIcon, size: CHIP_SIZE }),
|
|
130
131
|
/* @__PURE__ */ jsx4(Text2, { style: [styles2.triggerLabel, { color: chipTrigger ? fg : color }], numberOfLines: 1, children: triggerLabel }),
|
|
131
132
|
/* @__PURE__ */ jsx4(Icon2, { source: "menu-down", size: 16, color: chipTrigger ? fg : color })
|
|
132
133
|
] }) }),
|
|
133
|
-
/* @__PURE__ */ jsx4(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: chipTrigger ? triggerWidth : TRIGGER_HEIGHT, children: /* @__PURE__ */
|
|
134
|
+
/* @__PURE__ */ jsx4(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: chipTrigger ? triggerWidth : TRIGGER_HEIGHT, children: /* @__PURE__ */ jsxs(
|
|
134
135
|
View2,
|
|
135
136
|
{
|
|
136
137
|
style: [
|
|
@@ -142,41 +143,43 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
142
143
|
maxHeight
|
|
143
144
|
}
|
|
144
145
|
],
|
|
145
|
-
children:
|
|
146
|
-
colorSection && /* @__PURE__ */ jsx4(
|
|
147
|
-
|
|
148
|
-
/* @__PURE__ */ jsx4(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
/* @__PURE__ */ jsx4(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
146
|
+
children: [
|
|
147
|
+
/* @__PURE__ */ jsx4(FadingScrollView, { contentContainerStyle: [styles2.menuContent, manageFooter && styles2.menuContentAboveFooter], showsVerticalScrollIndicator: false, children: colorSection && colorPage ? /* @__PURE__ */ jsx4(ColorPage, { section: colorSection, profileColor: selectedProfile?.color, fg, onBack: () => setColorPage(false) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
148
|
+
colorSection && /* @__PURE__ */ jsx4(ColorRow, { section: colorSection, fg, dividerColor: color, onPress: () => setColorPage(true) }),
|
|
149
|
+
/* @__PURE__ */ jsx4(TouchableRipple, { onPress: handleSelectGuest, style: [styles2.row, selectedId === null && { backgroundColor: color }], children: /* @__PURE__ */ jsxs(View2, { style: styles2.rowInner, children: [
|
|
150
|
+
/* @__PURE__ */ jsx4(View2, { style: styles2.guestChip, children: /* @__PURE__ */ jsx4(Icon2, { source: nullIcon, size: 13, color: selectedId === null ? getContrastColor2(color) : fg }) }),
|
|
151
|
+
/* @__PURE__ */ jsx4(Text2, { style: [styles2.rowLabel, { color: selectedId === null ? getContrastColor2(color) : fg }], children: nullLabel })
|
|
152
|
+
] }) }),
|
|
153
|
+
sortedProfiles.map((profile) => {
|
|
154
|
+
const taken = profile.id === takenId;
|
|
155
|
+
const selected = selectedId === profile.id;
|
|
156
|
+
const rowColor = colorPreview ? colorPreview(profile.color) : profile.color;
|
|
157
|
+
return /* @__PURE__ */ jsx4(TouchableRipple, { disabled: taken, onPress: () => handleSelectExisting(profile), style: [styles2.row, selected && { backgroundColor: rowColor }], children: /* @__PURE__ */ jsxs(View2, { style: [styles2.rowInner, taken && styles2.rowDisabled], children: [
|
|
158
|
+
/* @__PURE__ */ jsx4(ProfileChip, { profile, filled: !selected }),
|
|
159
|
+
/* @__PURE__ */ jsx4(
|
|
160
|
+
Text2,
|
|
161
|
+
{
|
|
162
|
+
style: [
|
|
163
|
+
styles2.rowLabel,
|
|
164
|
+
{
|
|
165
|
+
color: selected ? getContrastColor2(rowColor) : fg
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
numberOfLines: 1,
|
|
169
|
+
children: profile.name
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
] }) }, profile.id);
|
|
173
|
+
})
|
|
174
|
+
] }) }, colorSection && colorPage ? "color" : "list"),
|
|
175
|
+
manageFooter && /* @__PURE__ */ jsxs(View2, { style: styles2.menuFooter, children: [
|
|
173
176
|
/* @__PURE__ */ jsx4(View2, { style: [styles2.divider, { backgroundColor: color }] }),
|
|
174
177
|
/* @__PURE__ */ jsx4(TouchableRipple, { onPress: handleManage, style: styles2.row, children: /* @__PURE__ */ jsxs(View2, { style: styles2.manageRowInner, children: [
|
|
175
178
|
/* @__PURE__ */ jsx4(Icon2, { source: "account-cog-outline", size: 16, color }),
|
|
176
179
|
/* @__PURE__ */ jsx4(Text2, { style: [styles2.manageLabel, { color: fg }], children: "Manage" })
|
|
177
180
|
] }) })
|
|
178
181
|
] })
|
|
179
|
-
]
|
|
182
|
+
]
|
|
180
183
|
}
|
|
181
184
|
) })
|
|
182
185
|
] });
|
|
@@ -302,6 +305,14 @@ var styles2 = StyleSheet2.create({
|
|
|
302
305
|
menuContent: {
|
|
303
306
|
padding: LIST_PADDING
|
|
304
307
|
},
|
|
308
|
+
// With Manage pinned below, its own padding takes the bottom edge (same total height as before).
|
|
309
|
+
menuContentAboveFooter: {
|
|
310
|
+
paddingBottom: 0
|
|
311
|
+
},
|
|
312
|
+
menuFooter: {
|
|
313
|
+
paddingBottom: LIST_PADDING,
|
|
314
|
+
paddingHorizontal: LIST_PADDING
|
|
315
|
+
},
|
|
305
316
|
// The selected profile's own color (see ColorSection).
|
|
306
317
|
profileDot: {
|
|
307
318
|
borderRadius: 4,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tastic/profile",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "Player profile identity for local-multiplayer React Native games: a saved name/color/tag a player selects per seat, with a picker, an inline-editable roster screen, and a reusable identity badge, deliberately blind to any app-specific fields (control scheme, stats) an app layers on top",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
package/src/ProfilePicker.tsx
CHANGED
|
@@ -245,6 +245,8 @@ export function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, sel
|
|
|
245
245
|
host.toggle(id)
|
|
246
246
|
}
|
|
247
247
|
const triggerLabel = (selectedProfile?.name ?? guestLabel).toUpperCase()
|
|
248
|
+
// Shown on the list page only (see the footer below).
|
|
249
|
+
const manageFooter = !!onManage && !(colorSection && colorPage)
|
|
248
250
|
|
|
249
251
|
return (
|
|
250
252
|
<View style={[styles.anchor, open && styles.anchorOpen]} onLayout={handleAnchorLayout}>
|
|
@@ -278,7 +280,7 @@ export function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, sel
|
|
|
278
280
|
]}
|
|
279
281
|
>
|
|
280
282
|
{/* Keyed by page, so swapping pages starts the new one scrolled to its top. */}
|
|
281
|
-
<FadingScrollView key={colorSection && colorPage ? 'color' : 'list'} contentContainerStyle={styles.menuContent} showsVerticalScrollIndicator={false}>
|
|
283
|
+
<FadingScrollView key={colorSection && colorPage ? 'color' : 'list'} contentContainerStyle={[styles.menuContent, manageFooter && styles.menuContentAboveFooter]} showsVerticalScrollIndicator={false}>
|
|
282
284
|
{colorSection && colorPage ? (
|
|
283
285
|
<ColorPage section={colorSection} profileColor={selectedProfile?.color} fg={fg} onBack={() => setColorPage(false)} />
|
|
284
286
|
) : (
|
|
@@ -327,25 +329,27 @@ export function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, sel
|
|
|
327
329
|
</TouchableRipple>
|
|
328
330
|
)
|
|
329
331
|
})}
|
|
330
|
-
|
|
331
|
-
{onManage && (
|
|
332
|
-
<>
|
|
333
|
-
<View style={[styles.divider, { backgroundColor: color }]} />
|
|
334
|
-
{/* Tertiary - a navigation action, not another selectable identity in the list above
|
|
335
|
-
it, so it reads more like @tastic/hud's SectionedDropdown All/Clear footer button
|
|
336
|
-
(centered, bold) than a normal row. The accent is on the icon only: a muted accent
|
|
337
|
-
label on the menu's black read dim, almost disabled (2026-10-16). */}
|
|
338
|
-
<TouchableRipple onPress={handleManage} style={styles.row}>
|
|
339
|
-
<View style={styles.manageRowInner}>
|
|
340
|
-
<Icon source='account-cog-outline' size={16} color={color} />
|
|
341
|
-
<Text style={[styles.manageLabel, { color: fg }]}>Manage</Text>
|
|
342
|
-
</View>
|
|
343
|
-
</TouchableRipple>
|
|
344
|
-
</>
|
|
345
|
-
)}
|
|
346
332
|
</>
|
|
347
333
|
)}
|
|
348
334
|
</FadingScrollView>
|
|
335
|
+
{/* Manage is pinned below the scrolling rows, the way a dialog's Done sits below its rows:
|
|
336
|
+
always reachable, with the rows fading out above its divider while there are more below
|
|
337
|
+
(2026-10-16; it used to be the list's last row and scrolled away with it). Tertiary - a
|
|
338
|
+
navigation action, not another selectable identity in the list above it, so it reads more
|
|
339
|
+
like @tastic/hud's SectionedDropdown All/Clear footer button (centered, bold) than a normal
|
|
340
|
+
row. The accent is on the icon only: a muted accent label on the menu's black read dim,
|
|
341
|
+
almost disabled. Not on the color page, which only has the back row and the swatches. */}
|
|
342
|
+
{manageFooter && (
|
|
343
|
+
<View style={styles.menuFooter}>
|
|
344
|
+
<View style={[styles.divider, { backgroundColor: color }]} />
|
|
345
|
+
<TouchableRipple onPress={handleManage} style={styles.row}>
|
|
346
|
+
<View style={styles.manageRowInner}>
|
|
347
|
+
<Icon source='account-cog-outline' size={16} color={color} />
|
|
348
|
+
<Text style={[styles.manageLabel, { color: fg }]}>Manage</Text>
|
|
349
|
+
</View>
|
|
350
|
+
</TouchableRipple>
|
|
351
|
+
</View>
|
|
352
|
+
)}
|
|
349
353
|
</View>
|
|
350
354
|
</PopoverBody>
|
|
351
355
|
</View>
|
|
@@ -509,6 +513,14 @@ const styles = StyleSheet.create({
|
|
|
509
513
|
menuContent: {
|
|
510
514
|
padding: LIST_PADDING
|
|
511
515
|
},
|
|
516
|
+
// With Manage pinned below, its own padding takes the bottom edge (same total height as before).
|
|
517
|
+
menuContentAboveFooter: {
|
|
518
|
+
paddingBottom: 0
|
|
519
|
+
},
|
|
520
|
+
menuFooter: {
|
|
521
|
+
paddingBottom: LIST_PADDING,
|
|
522
|
+
paddingHorizontal: LIST_PADDING
|
|
523
|
+
},
|
|
512
524
|
// The selected profile's own color (see ColorSection).
|
|
513
525
|
profileDot: {
|
|
514
526
|
borderRadius: 4,
|