@tastic/profile 0.13.0 → 0.14.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 +10 -3
- package/dist/index.d.mts +15 -4
- package/dist/index.d.ts +15 -4
- package/dist/index.js +208 -73
- package/dist/index.mjs +217 -82
- package/package.json +2 -2
- package/src/IdentityChip.tsx +58 -0
- package/src/ProfileChip.tsx +2 -37
- package/src/ProfilePicker.tsx +309 -77
- package/src/ProfilesManager.tsx +7 -1
- package/src/index.ts +1 -1
package/README.md
CHANGED
|
@@ -51,8 +51,12 @@ see its own doc comment for why that component is generic over your own `Profile
|
|
|
51
51
|
only - creating, renaming, and deleting all live in `ProfilesManager`. Generic over your own
|
|
52
52
|
`Profile` type (see above). Placement props (all optional, see "Fake-rotated frames" below):
|
|
53
53
|
`align` (force a horizontal side), `alignOverride` (substitute the whole placement result), and
|
|
54
|
-
`rotation` (forwarded to the automatic measurement).
|
|
55
|
-
`
|
|
54
|
+
`rotation` (forwarded to the automatic measurement). `colorSection`
|
|
55
|
+
(`{ value, onChange, previewValue?, swatches?, label?, caption? }`) puts a Color row at the top of
|
|
56
|
+
the popover that opens a page of swatches (with a back row), and turns the trigger into one
|
|
57
|
+
button that leads with a chip in `color` with the selected profile's tag; `triggerStyle` styles
|
|
58
|
+
that button. Also exports
|
|
59
|
+
`getProfilePickerContentSize(profileCount, hasManageRow?, colorSection?)` - the popover's
|
|
56
60
|
`{ width, height }`, for sizing your own placement hook.
|
|
57
61
|
- **`ProfilesManager`**: the roster screen itself: create/rename/recolor/retag/delete, editing
|
|
58
62
|
inline in the row you tap, with a destructive-delete confirmation. No navigation of its own (no
|
|
@@ -142,7 +146,10 @@ const placement = useMyRotatedAlign(open, width, height) // returns a ProfilePic
|
|
|
142
146
|
|
|
143
147
|
`getProfilePickerContentSize(profileCount, hasManageRow = false)` returns `{ width, height }`: 220
|
|
144
148
|
wide, and `8 * 2 + (profileCount + 1 + (hasManageRow ? 1 : 0)) * 36` tall (the null/"guest" row, one
|
|
145
|
-
row per profile, and the Manage row when `onManage` is passed)
|
|
149
|
+
row per profile, and the Manage row when `onManage` is passed), or with a color section (pass the same
|
|
150
|
+
object the picker gets) the taller of its two pages: that list plus the Color row (48 with a
|
|
151
|
+
caption, 36 without) and its 9pt divider, or the color page (a 36pt back row and the swatches, 187
|
|
152
|
+
for 20 colors), plus the padding.
|
|
146
153
|
|
|
147
154
|
|
|
148
155
|
#### The Profiles screen's color swatch: `useColorPickerAlign`
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, RefObject, Ref } from 'react';
|
|
3
|
+
import { SeedColor } from '@rific/auto-paper';
|
|
3
4
|
import { PopoverHost, PopoverRotation } from '@tastic/hud';
|
|
4
|
-
import { View } from 'react-native';
|
|
5
|
+
import { View, StyleProp, ViewStyle } from 'react-native';
|
|
5
6
|
|
|
6
7
|
interface Profile {
|
|
7
8
|
id: string;
|
|
@@ -27,6 +28,14 @@ declare function ProfileColorProvider({ preview, children }: ProfileColorProvide
|
|
|
27
28
|
declare function useProfileColorPreview(): ((hex: string) => string) | undefined;
|
|
28
29
|
declare function useProfileDisplayColor(hex: string): string;
|
|
29
30
|
|
|
31
|
+
interface ProfilePickerColorSection {
|
|
32
|
+
value: string;
|
|
33
|
+
onChange: (hex: string) => void;
|
|
34
|
+
previewValue?: (hex: string) => string;
|
|
35
|
+
swatches?: SeedColor[];
|
|
36
|
+
label?: string;
|
|
37
|
+
caption?: string;
|
|
38
|
+
}
|
|
30
39
|
interface ProfilePickerAlignResult {
|
|
31
40
|
align: 'left' | 'right' | 'center';
|
|
32
41
|
verticalAlign: 'below' | 'above';
|
|
@@ -38,7 +47,7 @@ interface ProfilePickerContentSize {
|
|
|
38
47
|
width: number;
|
|
39
48
|
height: number;
|
|
40
49
|
}
|
|
41
|
-
declare function getProfilePickerContentSize(profileCount: number, hasManageRow?: boolean): ProfilePickerContentSize;
|
|
50
|
+
declare function getProfilePickerContentSize(profileCount: number, hasManageRow?: boolean, colorSection?: Pick<ProfilePickerColorSection, 'swatches' | 'caption'>): ProfilePickerContentSize;
|
|
42
51
|
interface ProfilePickerProps<P extends Profile> {
|
|
43
52
|
idPrefix: string;
|
|
44
53
|
host: PopoverHost;
|
|
@@ -55,8 +64,10 @@ interface ProfilePickerProps<P extends Profile> {
|
|
|
55
64
|
nullIcon?: string;
|
|
56
65
|
onSelect: (profile: P | null) => void;
|
|
57
66
|
onManage?: () => void;
|
|
67
|
+
colorSection?: ProfilePickerColorSection;
|
|
68
|
+
triggerStyle?: StyleProp<ViewStyle>;
|
|
58
69
|
}
|
|
59
|
-
declare function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, selectedId, takenId, color, dark, align: forcedAlign, alignOverride, rotation, guestLabel, nullLabel, nullIcon, onSelect, onManage }: ProfilePickerProps<P>): react.JSX.Element;
|
|
70
|
+
declare function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, selectedId, takenId, color, dark, align: forcedAlign, alignOverride, rotation, guestLabel, nullLabel, nullIcon, onSelect, onManage, colorSection, triggerStyle }: ProfilePickerProps<P>): react.JSX.Element;
|
|
60
71
|
|
|
61
72
|
type MD3TextVariant$1 = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'labelLarge' | 'labelMedium' | 'labelSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall';
|
|
62
73
|
interface ProfileEditPatch {
|
|
@@ -217,4 +228,4 @@ declare function readSharedProfiles(groupId: string): Promise<Profile[] | null>;
|
|
|
217
228
|
declare function loadSharedProfiles(groupId: string): Promise<Profile[]>;
|
|
218
229
|
declare function saveSharedProfiles(groupId: string, profiles: Profile[]): Promise<void>;
|
|
219
230
|
|
|
220
|
-
export { type CreateProfileInput, MAX_PROFILE_NAME_LENGTH, MAX_TAG_LENGTH, type Profile, ProfileChip, ProfileColorProvider, type ProfileEditPatch, type ProfileExtensionActions, type ProfileExtensionSlice, type ProfileExtensionState, ProfilePicker, type ProfilePickerAlignResult, type ProfilePickerContentSize, type ProfileSelectionActions, type ProfileSelectionSlice, type ProfileSelectionState, ProfilesManager, type ProfilesManagerHandle, type ProfilesManagerProps, ProfilesScreen, type ProfilesScreenProps, type SeatColorsActions, type SeatColorsSlice, type SeatColorsState, type SelectProfilePayload, type SetLastGuestColorPayload, type SetProfileExtensionPayload, type SetProfileOverridePayload, type UpdateProfilePayload, type UseSharedProfilesSyncOptions, type UseSharedProfilesSyncResult, avoidSeatColorClash, createProfileExtensionSlice, createProfileRecord, createProfileSelectionSlice, createSeatColorsSlice, getProfilePickerContentSize, isSharedProfileStoreAvailable, isValidProfile, isValidTag, loadSharedProfiles, profilesActions, profilesReducer, readSharedProfiles, resolveInitialProfiles, saveSharedProfiles, useProfileColorPreview, useProfileDisplayColor, useSharedProfilesSync };
|
|
231
|
+
export { type CreateProfileInput, MAX_PROFILE_NAME_LENGTH, MAX_TAG_LENGTH, type Profile, ProfileChip, ProfileColorProvider, type ProfileEditPatch, type ProfileExtensionActions, type ProfileExtensionSlice, type ProfileExtensionState, ProfilePicker, type ProfilePickerAlignResult, type ProfilePickerColorSection, type ProfilePickerContentSize, type ProfileSelectionActions, type ProfileSelectionSlice, type ProfileSelectionState, ProfilesManager, type ProfilesManagerHandle, type ProfilesManagerProps, ProfilesScreen, type ProfilesScreenProps, type SeatColorsActions, type SeatColorsSlice, type SeatColorsState, type SelectProfilePayload, type SetLastGuestColorPayload, type SetProfileExtensionPayload, type SetProfileOverridePayload, type UpdateProfilePayload, type UseSharedProfilesSyncOptions, type UseSharedProfilesSyncResult, avoidSeatColorClash, createProfileExtensionSlice, createProfileRecord, createProfileSelectionSlice, createSeatColorsSlice, getProfilePickerContentSize, isSharedProfileStoreAvailable, isValidProfile, isValidTag, loadSharedProfiles, profilesActions, profilesReducer, readSharedProfiles, resolveInitialProfiles, saveSharedProfiles, useProfileColorPreview, useProfileDisplayColor, useSharedProfilesSync };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, RefObject, Ref } from 'react';
|
|
3
|
+
import { SeedColor } from '@rific/auto-paper';
|
|
3
4
|
import { PopoverHost, PopoverRotation } from '@tastic/hud';
|
|
4
|
-
import { View } from 'react-native';
|
|
5
|
+
import { View, StyleProp, ViewStyle } from 'react-native';
|
|
5
6
|
|
|
6
7
|
interface Profile {
|
|
7
8
|
id: string;
|
|
@@ -27,6 +28,14 @@ declare function ProfileColorProvider({ preview, children }: ProfileColorProvide
|
|
|
27
28
|
declare function useProfileColorPreview(): ((hex: string) => string) | undefined;
|
|
28
29
|
declare function useProfileDisplayColor(hex: string): string;
|
|
29
30
|
|
|
31
|
+
interface ProfilePickerColorSection {
|
|
32
|
+
value: string;
|
|
33
|
+
onChange: (hex: string) => void;
|
|
34
|
+
previewValue?: (hex: string) => string;
|
|
35
|
+
swatches?: SeedColor[];
|
|
36
|
+
label?: string;
|
|
37
|
+
caption?: string;
|
|
38
|
+
}
|
|
30
39
|
interface ProfilePickerAlignResult {
|
|
31
40
|
align: 'left' | 'right' | 'center';
|
|
32
41
|
verticalAlign: 'below' | 'above';
|
|
@@ -38,7 +47,7 @@ interface ProfilePickerContentSize {
|
|
|
38
47
|
width: number;
|
|
39
48
|
height: number;
|
|
40
49
|
}
|
|
41
|
-
declare function getProfilePickerContentSize(profileCount: number, hasManageRow?: boolean): ProfilePickerContentSize;
|
|
50
|
+
declare function getProfilePickerContentSize(profileCount: number, hasManageRow?: boolean, colorSection?: Pick<ProfilePickerColorSection, 'swatches' | 'caption'>): ProfilePickerContentSize;
|
|
42
51
|
interface ProfilePickerProps<P extends Profile> {
|
|
43
52
|
idPrefix: string;
|
|
44
53
|
host: PopoverHost;
|
|
@@ -55,8 +64,10 @@ interface ProfilePickerProps<P extends Profile> {
|
|
|
55
64
|
nullIcon?: string;
|
|
56
65
|
onSelect: (profile: P | null) => void;
|
|
57
66
|
onManage?: () => void;
|
|
67
|
+
colorSection?: ProfilePickerColorSection;
|
|
68
|
+
triggerStyle?: StyleProp<ViewStyle>;
|
|
58
69
|
}
|
|
59
|
-
declare function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, selectedId, takenId, color, dark, align: forcedAlign, alignOverride, rotation, guestLabel, nullLabel, nullIcon, onSelect, onManage }: ProfilePickerProps<P>): react.JSX.Element;
|
|
70
|
+
declare function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, selectedId, takenId, color, dark, align: forcedAlign, alignOverride, rotation, guestLabel, nullLabel, nullIcon, onSelect, onManage, colorSection, triggerStyle }: ProfilePickerProps<P>): react.JSX.Element;
|
|
60
71
|
|
|
61
72
|
type MD3TextVariant$1 = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'labelLarge' | 'labelMedium' | 'labelSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall';
|
|
62
73
|
interface ProfileEditPatch {
|
|
@@ -217,4 +228,4 @@ declare function readSharedProfiles(groupId: string): Promise<Profile[] | null>;
|
|
|
217
228
|
declare function loadSharedProfiles(groupId: string): Promise<Profile[]>;
|
|
218
229
|
declare function saveSharedProfiles(groupId: string, profiles: Profile[]): Promise<void>;
|
|
219
230
|
|
|
220
|
-
export { type CreateProfileInput, MAX_PROFILE_NAME_LENGTH, MAX_TAG_LENGTH, type Profile, ProfileChip, ProfileColorProvider, type ProfileEditPatch, type ProfileExtensionActions, type ProfileExtensionSlice, type ProfileExtensionState, ProfilePicker, type ProfilePickerAlignResult, type ProfilePickerContentSize, type ProfileSelectionActions, type ProfileSelectionSlice, type ProfileSelectionState, ProfilesManager, type ProfilesManagerHandle, type ProfilesManagerProps, ProfilesScreen, type ProfilesScreenProps, type SeatColorsActions, type SeatColorsSlice, type SeatColorsState, type SelectProfilePayload, type SetLastGuestColorPayload, type SetProfileExtensionPayload, type SetProfileOverridePayload, type UpdateProfilePayload, type UseSharedProfilesSyncOptions, type UseSharedProfilesSyncResult, avoidSeatColorClash, createProfileExtensionSlice, createProfileRecord, createProfileSelectionSlice, createSeatColorsSlice, getProfilePickerContentSize, isSharedProfileStoreAvailable, isValidProfile, isValidTag, loadSharedProfiles, profilesActions, profilesReducer, readSharedProfiles, resolveInitialProfiles, saveSharedProfiles, useProfileColorPreview, useProfileDisplayColor, useSharedProfilesSync };
|
|
231
|
+
export { type CreateProfileInput, MAX_PROFILE_NAME_LENGTH, MAX_TAG_LENGTH, type Profile, ProfileChip, ProfileColorProvider, type ProfileEditPatch, type ProfileExtensionActions, type ProfileExtensionSlice, type ProfileExtensionState, ProfilePicker, type ProfilePickerAlignResult, type ProfilePickerColorSection, type ProfilePickerContentSize, type ProfileSelectionActions, type ProfileSelectionSlice, type ProfileSelectionState, ProfilesManager, type ProfilesManagerHandle, type ProfilesManagerProps, ProfilesScreen, type ProfilesScreenProps, type SeatColorsActions, type SeatColorsSlice, type SeatColorsState, type SelectProfilePayload, type SetLastGuestColorPayload, type SetProfileExtensionPayload, type SetProfileOverridePayload, type UpdateProfilePayload, type UseSharedProfilesSyncOptions, type UseSharedProfilesSyncResult, avoidSeatColorClash, createProfileExtensionSlice, createProfileRecord, createProfileSelectionSlice, createSeatColorsSlice, getProfilePickerContentSize, isSharedProfileStoreAvailable, isValidProfile, isValidTag, loadSharedProfiles, profilesActions, profilesReducer, readSharedProfiles, resolveInitialProfiles, saveSharedProfiles, useProfileColorPreview, useProfileDisplayColor, useSharedProfilesSync };
|
package/dist/index.js
CHANGED
|
@@ -48,17 +48,34 @@ __export(index_exports, {
|
|
|
48
48
|
});
|
|
49
49
|
module.exports = __toCommonJS(index_exports);
|
|
50
50
|
|
|
51
|
-
// src/
|
|
51
|
+
// src/IdentityChip.tsx
|
|
52
52
|
var import_auto_paper = require("@rific/auto-paper");
|
|
53
53
|
var import_react_native = require("react-native");
|
|
54
54
|
var import_react_native_paper = require("react-native-paper");
|
|
55
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
56
|
+
var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
|
|
57
|
+
function IdentityChip({ color, tag, icon, size, filled = true }) {
|
|
58
|
+
const contrastColor = (0, import_auto_paper.getContrastColor)(color);
|
|
59
|
+
const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : tag && Array.from(tag).length >= 3 ? 0.32 : 0.4);
|
|
60
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: [styles.chip, { borderRadius: size / 2, height: size, width: size }, filled && { backgroundColor: color }], children: tag ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { style: [styles.tag, { color: contrastColor, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Icon, { source: icon, size: size * 0.6, color: contrastColor }) });
|
|
61
|
+
}
|
|
62
|
+
var styles = import_react_native.StyleSheet.create({
|
|
63
|
+
chip: {
|
|
64
|
+
alignItems: "center",
|
|
65
|
+
justifyContent: "center"
|
|
66
|
+
},
|
|
67
|
+
tag: {
|
|
68
|
+
fontWeight: "700",
|
|
69
|
+
paddingHorizontal: 2
|
|
70
|
+
}
|
|
71
|
+
});
|
|
55
72
|
|
|
56
73
|
// src/ProfileColorContext.tsx
|
|
57
74
|
var import_react = require("react");
|
|
58
|
-
var
|
|
75
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
59
76
|
var ProfileColorContext = (0, import_react.createContext)(void 0);
|
|
60
77
|
function ProfileColorProvider({ preview, children }) {
|
|
61
|
-
return /* @__PURE__ */ (0,
|
|
78
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ProfileColorContext.Provider, { value: preview, children });
|
|
62
79
|
}
|
|
63
80
|
function useProfileColorPreview() {
|
|
64
81
|
return (0, import_react.useContext)(ProfileColorContext);
|
|
@@ -69,24 +86,11 @@ function useProfileDisplayColor(hex) {
|
|
|
69
86
|
}
|
|
70
87
|
|
|
71
88
|
// src/ProfileChip.tsx
|
|
72
|
-
var
|
|
73
|
-
var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
|
|
89
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
74
90
|
function ProfileChip({ profile, size = 22, filled = true }) {
|
|
75
91
|
const color = useProfileDisplayColor(profile.color);
|
|
76
|
-
|
|
77
|
-
const tagFontSize = size * (profile.tag && EMOJI_PATTERN.test(profile.tag) ? 0.6 : 0.4);
|
|
78
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native.View, { style: [styles.chip, { borderRadius: size / 2, height: size, width: size }, filled && { backgroundColor: color }], children: profile.tag ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper.Text, { style: [styles.tag, { color: contrastColor, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: profile.tag }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper.Icon, { source: "account", size: size * 0.6, color: contrastColor }) });
|
|
92
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(IdentityChip, { color, tag: profile.tag, icon: "account", size, filled });
|
|
79
93
|
}
|
|
80
|
-
var styles = import_react_native.StyleSheet.create({
|
|
81
|
-
chip: {
|
|
82
|
-
alignItems: "center",
|
|
83
|
-
justifyContent: "center"
|
|
84
|
-
},
|
|
85
|
-
tag: {
|
|
86
|
-
fontWeight: "700",
|
|
87
|
-
paddingHorizontal: 2
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
94
|
|
|
91
95
|
// src/ProfilePicker.tsx
|
|
92
96
|
var import_auto_paper2 = require("@rific/auto-paper");
|
|
@@ -95,16 +99,40 @@ var import_hud = require("@tastic/hud");
|
|
|
95
99
|
var import_react2 = require("react");
|
|
96
100
|
var import_react_native2 = require("react-native");
|
|
97
101
|
var import_react_native_paper2 = require("react-native-paper");
|
|
98
|
-
var
|
|
102
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
99
103
|
var TRIGGER_HEIGHT = 28;
|
|
100
104
|
var POPOVER_WIDTH = 220;
|
|
101
105
|
var ROW_HEIGHT = 36;
|
|
102
106
|
var LIST_PADDING = 8;
|
|
103
|
-
|
|
107
|
+
var MENU_BORDER_WIDTH = 2;
|
|
108
|
+
var ROW_INSET = 12;
|
|
109
|
+
var CHIP_SIZE = 32;
|
|
110
|
+
var CHIP_TRIGGER_PADDING = 6;
|
|
111
|
+
var SWATCH_SIZE = 28;
|
|
112
|
+
var SWATCH_MIN_GAP = 6;
|
|
113
|
+
var COLOR_ROW_CAPTIONED_HEIGHT = 48;
|
|
114
|
+
var COLOR_LABEL_LINE = 18;
|
|
115
|
+
var COLOR_CAPTION_LINE = 16;
|
|
116
|
+
var COLOR_ROW_DIVIDER = 9;
|
|
117
|
+
var GRID_TOP = 4;
|
|
118
|
+
var GRID_BOTTOM = 8;
|
|
119
|
+
var GRID_WIDTH = POPOVER_WIDTH - 2 * MENU_BORDER_WIDTH - 2 * LIST_PADDING - 2 * ROW_INSET;
|
|
120
|
+
var GRID_COLUMNS = Math.floor((GRID_WIDTH + SWATCH_MIN_GAP) / (SWATCH_SIZE + SWATCH_MIN_GAP));
|
|
121
|
+
var GRID_GAP = (GRID_WIDTH - GRID_COLUMNS * SWATCH_SIZE) / (GRID_COLUMNS - 1);
|
|
122
|
+
function colorRowHeight(caption) {
|
|
123
|
+
return caption ? COLOR_ROW_CAPTIONED_HEIGHT : ROW_HEIGHT;
|
|
124
|
+
}
|
|
125
|
+
function colorPageHeight(swatches) {
|
|
126
|
+
const rows = Math.ceil(swatches.length / GRID_COLUMNS);
|
|
127
|
+
return ROW_HEIGHT + GRID_TOP + rows * SWATCH_SIZE + (rows - 1) * GRID_GAP + GRID_BOTTOM;
|
|
128
|
+
}
|
|
129
|
+
function getProfilePickerContentSize(profileCount, hasManageRow = false, colorSection) {
|
|
104
130
|
const rowCount = profileCount + 1 + (hasManageRow ? 1 : 0);
|
|
105
|
-
|
|
131
|
+
const list = rowCount * ROW_HEIGHT + (colorSection ? colorRowHeight(colorSection.caption) + COLOR_ROW_DIVIDER : 0);
|
|
132
|
+
const content = colorSection ? Math.max(list, colorPageHeight(colorSection.swatches ?? import_auto_paper2.defaultColors)) : list;
|
|
133
|
+
return { width: POPOVER_WIDTH, height: LIST_PADDING * 2 + content };
|
|
106
134
|
}
|
|
107
|
-
function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, dark, align: forcedAlign, alignOverride, rotation = 0, guestLabel, nullLabel = "Player", nullIcon = "account-off-outline", onSelect, onManage }) {
|
|
135
|
+
function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, dark, align: forcedAlign, alignOverride, rotation = 0, guestLabel, nullLabel = "Player", nullIcon = "account-off-outline", onSelect, onManage, colorSection, triggerStyle }) {
|
|
108
136
|
const id = `${idPrefix}-profile`;
|
|
109
137
|
const colorPreview = useProfileColorPreview();
|
|
110
138
|
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
@@ -112,7 +140,7 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
112
140
|
const open = host.openId === id;
|
|
113
141
|
const selectedProfile = profiles.find((p) => p.id === selectedId) ?? null;
|
|
114
142
|
const sortedProfiles = (0, import_react2.useMemo)(() => [...profiles].sort((a, b) => a.name.localeCompare(b.name)), [profiles]);
|
|
115
|
-
const { width: contentWidth, height: contentHeight } = getProfilePickerContentSize(profiles.length, !!onManage);
|
|
143
|
+
const { width: contentWidth, height: contentHeight } = getProfilePickerContentSize(profiles.length, !!onManage, colorSection);
|
|
116
144
|
const auto = (0, import_hud.useAutoAlign)(open, contentWidth, contentHeight, rotation);
|
|
117
145
|
const placement = alignOverride ?? auto;
|
|
118
146
|
const { maxHeight, measured, triggerRef, verticalAlign } = placement;
|
|
@@ -130,13 +158,23 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
130
158
|
host.close();
|
|
131
159
|
onManage?.();
|
|
132
160
|
};
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
161
|
+
const chipTrigger = !!colorSection;
|
|
162
|
+
const [triggerWidth, setTriggerWidth] = (0, import_react2.useState)(0);
|
|
163
|
+
const handleAnchorLayout = chipTrigger ? (e) => setTriggerWidth(e.nativeEvent.layout.width) : void 0;
|
|
164
|
+
const [colorPage, setColorPage] = (0, import_react2.useState)(false);
|
|
165
|
+
const handleTriggerPress = () => {
|
|
166
|
+
setColorPage(false);
|
|
167
|
+
host.toggle(id);
|
|
168
|
+
};
|
|
169
|
+
const triggerLabel = (selectedProfile?.name ?? guestLabel).toUpperCase();
|
|
170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: [styles2.anchor, open && styles2.anchorOpen], onLayout: handleAnchorLayout, children: [
|
|
171
|
+
/* @__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
|
+
chipTrigger && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(IdentityChip, { color, tag: selectedProfile?.tag, icon: selectedProfile ? "account" : nullIcon, size: CHIP_SIZE }),
|
|
173
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles2.triggerLabel, { color: chipTrigger ? fg : color }], numberOfLines: 1, children: triggerLabel }),
|
|
174
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "menu-down", size: 16, color: chipTrigger ? fg : color })
|
|
137
175
|
] }) }),
|
|
138
|
-
/* @__PURE__ */ (0,
|
|
139
|
-
import_react_native2.
|
|
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.jsx)(
|
|
177
|
+
import_react_native2.View,
|
|
140
178
|
{
|
|
141
179
|
style: [
|
|
142
180
|
styles2.menu,
|
|
@@ -147,20 +185,19 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
147
185
|
maxHeight
|
|
148
186
|
}
|
|
149
187
|
],
|
|
150
|
-
contentContainerStyle: styles2.menuContent,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
/* @__PURE__ */ (0,
|
|
155
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper2.Text, { style: [styles2.rowLabel, { color: selectedId === null ? (0, import_auto_paper2.getContrastColor)(color) : fg }], children: nullLabel })
|
|
188
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_auto_paper2.FadingScrollView, { contentContainerStyle: styles2.menuContent, 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: [
|
|
189
|
+
colorSection && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ColorRow, { section: colorSection, fg, dividerColor: color, onPress: () => setColorPage(true) }),
|
|
190
|
+
/* @__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: [
|
|
191
|
+
/* @__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 }) }),
|
|
192
|
+
/* @__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 })
|
|
156
193
|
] }) }),
|
|
157
194
|
sortedProfiles.map((profile) => {
|
|
158
195
|
const taken = profile.id === takenId;
|
|
159
196
|
const selected = selectedId === profile.id;
|
|
160
197
|
const rowColor = colorPreview ? colorPreview(profile.color) : profile.color;
|
|
161
|
-
return /* @__PURE__ */ (0,
|
|
162
|
-
/* @__PURE__ */ (0,
|
|
163
|
-
/* @__PURE__ */ (0,
|
|
198
|
+
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: [
|
|
199
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ProfileChip, { profile, filled: !selected }),
|
|
200
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
164
201
|
import_react_native_paper2.Text,
|
|
165
202
|
{
|
|
166
203
|
style: [
|
|
@@ -175,18 +212,49 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
175
212
|
)
|
|
176
213
|
] }) }, profile.id);
|
|
177
214
|
}),
|
|
178
|
-
onManage && /* @__PURE__ */ (0,
|
|
179
|
-
/* @__PURE__ */ (0,
|
|
180
|
-
/* @__PURE__ */ (0,
|
|
181
|
-
/* @__PURE__ */ (0,
|
|
182
|
-
/* @__PURE__ */ (0,
|
|
215
|
+
onManage && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
216
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, { style: [styles2.divider, { backgroundColor: color }] }),
|
|
217
|
+
/* @__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
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "account-cog-outline", size: 16, color }),
|
|
219
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles2.manageLabel, { color: fg }], children: "Manage" })
|
|
183
220
|
] }) })
|
|
184
221
|
] })
|
|
185
|
-
]
|
|
222
|
+
] }) }, colorSection && colorPage ? "color" : "list")
|
|
186
223
|
}
|
|
187
224
|
) })
|
|
188
225
|
] });
|
|
189
226
|
}
|
|
227
|
+
function ColorRow({ section, fg, dividerColor, onPress }) {
|
|
228
|
+
const { value, previewValue, label = "Color", caption } = section;
|
|
229
|
+
const drawn = previewValue ? previewValue(value) : value;
|
|
230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
231
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.TouchableRipple, { onPress, style: [styles2.row, { height: colorRowHeight(caption) }], accessibilityRole: "button", accessibilityLabel: caption ? `${label}, ${caption}` : label, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: styles2.rowInner, children: [
|
|
232
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, { style: [styles2.colorRowSwatch, { backgroundColor: drawn }] }),
|
|
233
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: styles2.colorRowText, children: [
|
|
234
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles2.colorRowLabel, { color: fg }], numberOfLines: 1, children: label }),
|
|
235
|
+
caption ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles2.colorRowCaption, { color: fg }], numberOfLines: 1, children: caption }) : null
|
|
236
|
+
] }),
|
|
237
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "chevron-right", size: 18, color: fg })
|
|
238
|
+
] }) }),
|
|
239
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, { style: [styles2.divider, { backgroundColor: dividerColor }] })
|
|
240
|
+
] });
|
|
241
|
+
}
|
|
242
|
+
function ColorPage({ section, profileColor, fg, onBack }) {
|
|
243
|
+
const { value, onChange, previewValue, swatches = import_auto_paper2.defaultColors, label = "Color" } = section;
|
|
244
|
+
const displayFor = previewValue ?? ((hex) => hex);
|
|
245
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.TouchableRipple, { onPress: onBack, style: styles2.row, accessibilityRole: "button", accessibilityLabel: "Back", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: styles2.rowInner, children: [
|
|
247
|
+
/* @__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: "chevron-left", size: 20, color: fg }) }),
|
|
248
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles2.colorRowLabel, { color: fg }], numberOfLines: 1, children: label })
|
|
249
|
+
] }) }),
|
|
250
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, { style: styles2.swatches, children: swatches.map((swatch) => {
|
|
251
|
+
const selected = swatch.value.toLowerCase() === value.toLowerCase();
|
|
252
|
+
const isProfileColor = !!profileColor && swatch.value.toLowerCase() === profileColor.toLowerCase();
|
|
253
|
+
const swatchDisplay = displayFor(swatch.value);
|
|
254
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.TouchableRipple, { onPress: () => onChange(swatch.value), borderless: true, style: [styles2.swatch, { backgroundColor: swatchDisplay }, selected && styles2.swatchSelected], accessibilityRole: "button", accessibilityLabel: isProfileColor ? `${swatch.label}, profile color` : swatch.label, accessibilityState: { selected }, children: selected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "check", size: 16, color: (0, import_auto_paper2.getContrastColor)(swatchDisplay) }) : isProfileColor ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, { style: [styles2.profileDot, { backgroundColor: (0, import_auto_paper2.getContrastColor)(swatchDisplay) }] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, {}) }, swatch.value);
|
|
255
|
+
}) })
|
|
256
|
+
] });
|
|
257
|
+
}
|
|
190
258
|
var styles2 = import_react_native2.StyleSheet.create({
|
|
191
259
|
anchor: {
|
|
192
260
|
position: "relative"
|
|
@@ -196,6 +264,40 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
196
264
|
anchorOpen: {
|
|
197
265
|
zIndex: 100
|
|
198
266
|
},
|
|
267
|
+
// The pill, rounded at both ends. The host adds its own background through `triggerStyle`.
|
|
268
|
+
chipTrigger: {
|
|
269
|
+
borderRadius: (CHIP_SIZE + 2 * CHIP_TRIGGER_PADDING) / 2
|
|
270
|
+
},
|
|
271
|
+
// The padding lives on the measured view, not the pressable around it, so the placement measures
|
|
272
|
+
// the pill's real edge: measured from inside the padding, a popover opening toward a screen edge
|
|
273
|
+
// was sized as if the pill were 6pt further from it, and ran 2pt past that edge.
|
|
274
|
+
chipTriggerInner: {
|
|
275
|
+
alignItems: "center",
|
|
276
|
+
flexDirection: "row",
|
|
277
|
+
gap: 8,
|
|
278
|
+
height: CHIP_SIZE + 2 * CHIP_TRIGGER_PADDING,
|
|
279
|
+
paddingLeft: CHIP_TRIGGER_PADDING,
|
|
280
|
+
paddingRight: CHIP_TRIGGER_PADDING + 8
|
|
281
|
+
},
|
|
282
|
+
colorRowCaption: {
|
|
283
|
+
fontSize: 12,
|
|
284
|
+
lineHeight: COLOR_CAPTION_LINE,
|
|
285
|
+
opacity: 0.6
|
|
286
|
+
},
|
|
287
|
+
// A row's label, with a line height so the captioned Color row's height is exact.
|
|
288
|
+
colorRowLabel: {
|
|
289
|
+
fontSize: 14,
|
|
290
|
+
lineHeight: COLOR_LABEL_LINE
|
|
291
|
+
},
|
|
292
|
+
// The color in effect, in the same 22pt slot as every row's chip.
|
|
293
|
+
colorRowSwatch: {
|
|
294
|
+
borderRadius: 11,
|
|
295
|
+
height: 22,
|
|
296
|
+
width: 22
|
|
297
|
+
},
|
|
298
|
+
colorRowText: {
|
|
299
|
+
flex: 1
|
|
300
|
+
},
|
|
199
301
|
// Separates Manage (a navigation action) from the selectable rows above it - different kind of
|
|
200
302
|
// action, not just another row in the same list. Tinted with the seat's own color (passed in as
|
|
201
303
|
// backgroundColor) rather than a flat gray, matching the border/caret's own accent-tinted look.
|
|
@@ -230,7 +332,7 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
230
332
|
},
|
|
231
333
|
menu: {
|
|
232
334
|
borderRadius: 12,
|
|
233
|
-
borderWidth:
|
|
335
|
+
borderWidth: MENU_BORDER_WIDTH,
|
|
234
336
|
elevation: 8,
|
|
235
337
|
shadowColor: "#000000",
|
|
236
338
|
shadowOffset: { height: 2, width: 0 },
|
|
@@ -243,6 +345,12 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
243
345
|
menuContent: {
|
|
244
346
|
padding: LIST_PADDING
|
|
245
347
|
},
|
|
348
|
+
// The selected profile's own color (see ColorSection).
|
|
349
|
+
profileDot: {
|
|
350
|
+
borderRadius: 4,
|
|
351
|
+
height: 8,
|
|
352
|
+
width: 8
|
|
353
|
+
},
|
|
246
354
|
row: {
|
|
247
355
|
borderRadius: 8,
|
|
248
356
|
height: ROW_HEIGHT
|
|
@@ -255,12 +363,33 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
255
363
|
flexDirection: "row",
|
|
256
364
|
flex: 1,
|
|
257
365
|
gap: 8,
|
|
258
|
-
paddingHorizontal:
|
|
366
|
+
paddingHorizontal: ROW_INSET
|
|
259
367
|
},
|
|
260
368
|
rowLabel: {
|
|
261
369
|
flex: 1,
|
|
262
370
|
fontSize: 14
|
|
263
371
|
},
|
|
372
|
+
swatch: {
|
|
373
|
+
alignItems: "center",
|
|
374
|
+
borderRadius: SWATCH_SIZE / 2,
|
|
375
|
+
height: SWATCH_SIZE,
|
|
376
|
+
justifyContent: "center",
|
|
377
|
+
width: SWATCH_SIZE
|
|
378
|
+
},
|
|
379
|
+
swatchSelected: {
|
|
380
|
+
borderColor: "#ffffff",
|
|
381
|
+
borderWidth: 2
|
|
382
|
+
},
|
|
383
|
+
swatches: {
|
|
384
|
+
columnGap: GRID_GAP,
|
|
385
|
+
flexDirection: "row",
|
|
386
|
+
flexWrap: "wrap",
|
|
387
|
+
marginBottom: GRID_BOTTOM,
|
|
388
|
+
marginHorizontal: ROW_INSET,
|
|
389
|
+
marginTop: GRID_TOP,
|
|
390
|
+
rowGap: GRID_GAP,
|
|
391
|
+
width: GRID_WIDTH
|
|
392
|
+
},
|
|
264
393
|
trigger: {
|
|
265
394
|
alignSelf: "flex-start"
|
|
266
395
|
},
|
|
@@ -321,8 +450,8 @@ function isValidProfile(value) {
|
|
|
321
450
|
}
|
|
322
451
|
|
|
323
452
|
// src/ProfilesManager.tsx
|
|
324
|
-
var
|
|
325
|
-
var
|
|
453
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
454
|
+
var CHIP_SIZE2 = 40;
|
|
326
455
|
function deriveTag(name) {
|
|
327
456
|
const trimmed = name.trim();
|
|
328
457
|
return trimmed ? trimmed[0].toUpperCase() : "";
|
|
@@ -398,38 +527,38 @@ function ProfilesManager({ profiles, defaultColor, onCreate, onSave, onDelete, h
|
|
|
398
527
|
}, [confirmDeleteId, editingId, onDelete]);
|
|
399
528
|
const sortedProfiles = (0, import_react3.useMemo)(() => [...profiles].sort((a, b) => a.name.localeCompare(b.name)), [profiles]);
|
|
400
529
|
const rows = [...sortedProfiles.map((profile) => ({ kind: "profile", profile })), { kind: "new" }];
|
|
401
|
-
return /* @__PURE__ */ (0,
|
|
402
|
-
/* @__PURE__ */ (0,
|
|
530
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
531
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native3.View, { style: [styles3.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
|
|
403
532
|
headerLeft,
|
|
404
|
-
/* @__PURE__ */ (0,
|
|
533
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Text, { variant: titleVariant, style: [styles3.title, { color: fg }], children: "Profiles" })
|
|
405
534
|
] }),
|
|
406
|
-
/* @__PURE__ */ (0,
|
|
535
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.KeyboardAvoidingView, { behavior: import_react_native3.Platform.OS === "ios" ? "padding" : void 0, style: styles3.keyboardAvoiding, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.ScrollView, { style: styles3.scrollView, contentContainerStyle: [styles3.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "handled", children: rows.map((row) => {
|
|
407
536
|
if (row.kind === "new") {
|
|
408
537
|
if (editingId !== "new") {
|
|
409
|
-
return /* @__PURE__ */ (0,
|
|
410
|
-
/* @__PURE__ */ (0,
|
|
411
|
-
/* @__PURE__ */ (0,
|
|
538
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => startEdit("new"), style: styles3.row, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native3.View, { style: styles3.rowInner, children: [
|
|
539
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.View, { style: [styles3.rowChip, styles3.newChip, { borderColor: fg }], children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Icon, { source: "plus", size: 20, color: fg }) }),
|
|
540
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Text, { variant: "bodyLarge", style: { color: fg }, children: "New Profile" })
|
|
412
541
|
] }) }, "new");
|
|
413
542
|
}
|
|
414
|
-
return /* @__PURE__ */ (0,
|
|
543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EditRow, { draftName, onNameChange: handleNameChange, draftColor, onColorChange: setDraftColor, draftTag, onTagChange: handleTagChange, onSubmit: commitEdit, autoFocus: true, fgMuted, host, dark, colorPreview, useColorPickerAlign }, "new");
|
|
415
544
|
}
|
|
416
545
|
const { profile } = row;
|
|
417
546
|
if (editingId === profile.id) {
|
|
418
|
-
return /* @__PURE__ */ (0,
|
|
547
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EditRow, { draftName, onNameChange: handleNameChange, draftColor, onColorChange: setDraftColor, draftTag, onTagChange: handleTagChange, onSubmit: commitEdit, onDelete: () => setConfirmDeleteId(profile.id), fgMuted, host, dark, colorPreview, useColorPickerAlign }, profile.id);
|
|
419
548
|
}
|
|
420
|
-
return /* @__PURE__ */ (0,
|
|
421
|
-
/* @__PURE__ */ (0,
|
|
422
|
-
/* @__PURE__ */ (0,
|
|
549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => startEdit(profile), style: styles3.row, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native3.View, { style: styles3.rowInner, children: [
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProfileChip, { profile, size: CHIP_SIZE2 }),
|
|
551
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Text, { variant: "bodyLarge", style: [styles3.rowName, { color: fg }], numberOfLines: 1, children: profile.name })
|
|
423
552
|
] }) }, profile.id);
|
|
424
553
|
}) }) }),
|
|
425
|
-
/* @__PURE__ */ (0,
|
|
554
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_hud2.ConfirmDialog, { visible: confirmDeleteProfile !== null, title: "Delete Profile?", message: confirmDeleteProfile ? `This permanently deletes ${confirmDeleteProfile.name}\u2019s profile. This cannot be undone.` : "", confirmLabel: "Delete", cancelLabel: "Cancel", icon: "alert-outline", destructive: true, onConfirm: handleConfirmDelete, onCancel: () => setConfirmDeleteId(null) })
|
|
426
555
|
] });
|
|
427
556
|
}
|
|
428
557
|
function AlignedColorPicker({ useAlign, ...props }) {
|
|
429
558
|
const { width: windowWidth } = (0, import_react_native3.useWindowDimensions)();
|
|
430
559
|
const { width, height } = (0, import_hud2.getInlineColorPickerContentSize)(import_auto_paper3.defaultColors.length, windowWidth);
|
|
431
560
|
const alignOverride = useAlign(props.host.openId === props.id, width, height);
|
|
432
|
-
return /* @__PURE__ */ (0,
|
|
561
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_hud2.InlineColorPicker, { ...props, alignOverride });
|
|
433
562
|
}
|
|
434
563
|
function EditRow({ draftName, onNameChange, draftColor, onColorChange, draftTag, onTagChange, onSubmit, onDelete, autoFocus, fgMuted, host, dark, colorPreview, useColorPickerAlign }) {
|
|
435
564
|
const register = (0, import_focus_chain.useFocusChain)();
|
|
@@ -442,11 +571,11 @@ function EditRow({ draftName, onNameChange, draftColor, onColorChange, draftTag,
|
|
|
442
571
|
(0, import_react3.useEffect)(() => {
|
|
443
572
|
if (host.openId === "color") tagFocusRef.current();
|
|
444
573
|
}, [host.openId]);
|
|
445
|
-
return /* @__PURE__ */ (0,
|
|
446
|
-
useColorPickerAlign ? /* @__PURE__ */ (0,
|
|
447
|
-
/* @__PURE__ */ (0,
|
|
448
|
-
/* @__PURE__ */ (0,
|
|
449
|
-
onDelete && /* @__PURE__ */ (0,
|
|
574
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native3.View, { style: styles3.editRow, children: [
|
|
575
|
+
useColorPickerAlign ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AlignedColorPicker, { useAlign: useColorPickerAlign, id: "color", host, value: draftColor, onChange: onColorChange, previewValue: colorPreview, tag: draftTag, dark }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_hud2.InlineColorPicker, { id: "color", host, value: draftColor, onChange: onColorChange, previewValue: colorPreview, tag: draftTag, dark }),
|
|
576
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.TextInput, { ref: tag.ref, ...tag.props, value: draftTag, onChangeText: onTagChange, accessibilityLabel: "Tag", autoCapitalize: "characters", selectTextOnFocus: true, returnKeyType: "next", style: styles3.hiddenTagInput, pointerEvents: "none" }),
|
|
577
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.TextInput, { ref: name.ref, ...name.props, onSubmitEditing: onSubmit, mode: "outlined", dense: true, value: draftName, onChangeText: onNameChange, maxLength: MAX_PROFILE_NAME_LENGTH, placeholder: "Name", autoFocus, returnKeyType: "done", style: styles3.nameInput }),
|
|
578
|
+
onDelete && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_feedback_press2.TouchableRipple, { onPress: onDelete, style: styles3.iconButton, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Icon, { source: "trash-can-outline", size: 18, color: fgMuted }) })
|
|
450
579
|
] });
|
|
451
580
|
}
|
|
452
581
|
var styles3 = import_react_native3.StyleSheet.create({
|
|
@@ -454,11 +583,17 @@ var styles3 = import_react_native3.StyleSheet.create({
|
|
|
454
583
|
gap: 4,
|
|
455
584
|
paddingHorizontal: 20
|
|
456
585
|
},
|
|
586
|
+
// zIndex: the color popover lives inside this row, and a zIndex only orders siblings of one parent
|
|
587
|
+
// (React Native Web also gives every positioned view its own stacking context), so the popover's
|
|
588
|
+
// own zIndex never reached the rows after this one: they were drawn over it (a Kid row and the New
|
|
589
|
+
// Profile row across the swatches, 2026-10-16). Raising the row lifts the popover with it. There
|
|
590
|
+
// is only ever one edit row.
|
|
457
591
|
editRow: {
|
|
458
592
|
alignItems: "center",
|
|
459
593
|
flexDirection: "row",
|
|
460
594
|
gap: 8,
|
|
461
|
-
paddingVertical: 6
|
|
595
|
+
paddingVertical: 6,
|
|
596
|
+
zIndex: 1
|
|
462
597
|
},
|
|
463
598
|
header: {
|
|
464
599
|
alignItems: "center",
|
|
@@ -499,10 +634,10 @@ var styles3 = import_react_native3.StyleSheet.create({
|
|
|
499
634
|
},
|
|
500
635
|
rowChip: {
|
|
501
636
|
alignItems: "center",
|
|
502
|
-
borderRadius:
|
|
503
|
-
height:
|
|
637
|
+
borderRadius: CHIP_SIZE2 / 2,
|
|
638
|
+
height: CHIP_SIZE2,
|
|
504
639
|
justifyContent: "center",
|
|
505
|
-
width:
|
|
640
|
+
width: CHIP_SIZE2
|
|
506
641
|
},
|
|
507
642
|
rowInner: {
|
|
508
643
|
alignItems: "center",
|
|
@@ -526,7 +661,7 @@ var import_auto_paper4 = require("@rific/auto-paper");
|
|
|
526
661
|
var import_feedback_press3 = require("@rific/feedback-press");
|
|
527
662
|
var import_react4 = require("react");
|
|
528
663
|
var import_react_native4 = require("react-native");
|
|
529
|
-
var
|
|
664
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
530
665
|
function ProfilesScreen({ profiles, defaultColor, onCreate, onSave, onDelete, onBack, fg: fgOverride, fgMuted, bg: bgOverride, titleVariant, colorPreview, useColorPickerAlign }) {
|
|
531
666
|
const { dark } = (0, import_auto_paper4.useAutoPaperTheme)();
|
|
532
667
|
const managerRef = (0, import_react4.useRef)(null);
|
|
@@ -536,7 +671,7 @@ function ProfilesScreen({ profiles, defaultColor, onCreate, onSave, onDelete, on
|
|
|
536
671
|
managerRef.current?.commitPendingEdit();
|
|
537
672
|
onBack();
|
|
538
673
|
};
|
|
539
|
-
return /* @__PURE__ */ (0,
|
|
674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native4.View, { style: [styles4.container, { backgroundColor: bg }], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProfilesManager, { ref: managerRef, profiles, defaultColor, onCreate, onSave, onDelete, fg, fgMuted, titleVariant, colorPreview, useColorPickerAlign, headerLeft: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: handleBack, accessibilityLabel: "Back" }) }) });
|
|
540
675
|
}
|
|
541
676
|
var styles4 = import_react_native4.StyleSheet.create({
|
|
542
677
|
container: {
|