@tastic/profile 0.14.1 → 0.15.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/dist/index.d.mts +59 -27
- package/dist/index.d.ts +59 -27
- package/dist/index.js +315 -227
- package/dist/index.mjs +272 -187
- package/package.json +8 -8
- package/src/OptionPicker.tsx +64 -0
- package/src/PickerMenu.tsx +481 -0
- package/src/ProfilePicker.tsx +54 -425
- package/src/ProfilesManager.tsx +7 -5
- package/src/index.ts +2 -1
- package/src/redux/seatColorsSlice.ts +79 -29
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
MAX_PROFILE_NAME_LENGTH: () => MAX_PROFILE_NAME_LENGTH,
|
|
24
24
|
MAX_TAG_LENGTH: () => MAX_TAG_LENGTH,
|
|
25
|
+
OptionPicker: () => OptionPicker,
|
|
25
26
|
ProfileChip: () => ProfileChip,
|
|
26
27
|
ProfileColorProvider: () => ProfileColorProvider,
|
|
27
28
|
ProfilePicker: () => ProfilePicker,
|
|
@@ -32,11 +33,13 @@ __export(index_exports, {
|
|
|
32
33
|
createProfileRecord: () => createProfileRecord,
|
|
33
34
|
createProfileSelectionSlice: () => createProfileSelectionSlice,
|
|
34
35
|
createSeatColorsSlice: () => createSeatColorsSlice,
|
|
36
|
+
getOptionPickerContentSize: () => getOptionPickerContentSize,
|
|
35
37
|
getProfilePickerContentSize: () => getProfilePickerContentSize,
|
|
36
38
|
isSharedProfileStoreAvailable: () => isSharedProfileStoreAvailable,
|
|
37
39
|
isValidProfile: () => isValidProfile,
|
|
38
40
|
isValidTag: () => isValidTag,
|
|
39
41
|
loadSharedProfiles: () => loadSharedProfiles,
|
|
42
|
+
profileSeatColor: () => profileSeatColor,
|
|
40
43
|
profilesActions: () => profilesActions,
|
|
41
44
|
profilesReducer: () => profilesReducer,
|
|
42
45
|
readSharedProfiles: () => readSharedProfiles,
|
|
@@ -48,6 +51,14 @@ __export(index_exports, {
|
|
|
48
51
|
});
|
|
49
52
|
module.exports = __toCommonJS(index_exports);
|
|
50
53
|
|
|
54
|
+
// src/PickerMenu.tsx
|
|
55
|
+
var import_auto_paper2 = require("@rific/auto-paper");
|
|
56
|
+
var import_feedback_press = require("@rific/feedback-press");
|
|
57
|
+
var import_hud = require("@tastic/hud");
|
|
58
|
+
var import_react = require("react");
|
|
59
|
+
var import_react_native2 = require("react-native");
|
|
60
|
+
var import_react_native_paper2 = require("react-native-paper");
|
|
61
|
+
|
|
51
62
|
// src/IdentityChip.tsx
|
|
52
63
|
var import_auto_paper = require("@rific/auto-paper");
|
|
53
64
|
var import_react_native = require("react-native");
|
|
@@ -70,36 +81,8 @@ var styles = import_react_native.StyleSheet.create({
|
|
|
70
81
|
}
|
|
71
82
|
});
|
|
72
83
|
|
|
73
|
-
// src/
|
|
74
|
-
var import_react = require("react");
|
|
84
|
+
// src/PickerMenu.tsx
|
|
75
85
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
76
|
-
var ProfileColorContext = (0, import_react.createContext)(void 0);
|
|
77
|
-
function ProfileColorProvider({ preview, children }) {
|
|
78
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ProfileColorContext.Provider, { value: preview, children });
|
|
79
|
-
}
|
|
80
|
-
function useProfileColorPreview() {
|
|
81
|
-
return (0, import_react.useContext)(ProfileColorContext);
|
|
82
|
-
}
|
|
83
|
-
function useProfileDisplayColor(hex) {
|
|
84
|
-
const preview = useProfileColorPreview();
|
|
85
|
-
return preview ? preview(hex) : hex;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// src/ProfileChip.tsx
|
|
89
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
90
|
-
function ProfileChip({ profile, size = 22, filled = true }) {
|
|
91
|
-
const color = useProfileDisplayColor(profile.color);
|
|
92
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(IdentityChip, { color, tag: profile.tag, icon: "account", size, filled });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// src/ProfilePicker.tsx
|
|
96
|
-
var import_auto_paper2 = require("@rific/auto-paper");
|
|
97
|
-
var import_feedback_press = require("@rific/feedback-press");
|
|
98
|
-
var import_hud = require("@tastic/hud");
|
|
99
|
-
var import_react2 = require("react");
|
|
100
|
-
var import_react_native2 = require("react-native");
|
|
101
|
-
var import_react_native_paper2 = require("react-native-paper");
|
|
102
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
103
86
|
var TRIGGER_HEIGHT = 28;
|
|
104
87
|
var POPOVER_WIDTH = 220;
|
|
105
88
|
var ROW_HEIGHT = 36;
|
|
@@ -126,55 +109,37 @@ function colorPageHeight(swatches) {
|
|
|
126
109
|
const rows = Math.ceil(swatches.length / GRID_COLUMNS);
|
|
127
110
|
return ROW_HEIGHT + GRID_TOP + rows * SWATCH_SIZE + (rows - 1) * GRID_GAP + GRID_BOTTOM;
|
|
128
111
|
}
|
|
129
|
-
function
|
|
130
|
-
const rowCount = profileCount + 1 + (hasManageRow ? 1 : 0);
|
|
112
|
+
function pickerContentSize(rowCount, colorSection) {
|
|
131
113
|
const list = rowCount * ROW_HEIGHT + (colorSection ? colorRowHeight(colorSection.caption) + COLOR_ROW_DIVIDER : 0);
|
|
132
114
|
const content = colorSection ? Math.max(list, colorPageHeight(colorSection.swatches ?? import_auto_paper2.defaultColors)) : list;
|
|
133
115
|
return { width: POPOVER_WIDTH, height: LIST_PADDING * 2 + content };
|
|
134
116
|
}
|
|
135
|
-
function
|
|
136
|
-
const id = `${idPrefix}-profile`;
|
|
137
|
-
const colorPreview = useProfileColorPreview();
|
|
117
|
+
function PickerMenu({ id, host, color, dark, label, chip, colorSection, homeColor, contentSize, align: forcedAlign, alignOverride, rotation, triggerStyle, footer, children }) {
|
|
138
118
|
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
139
119
|
const fg = dark ? "#FFFFFF" : "#000000";
|
|
140
120
|
const open = host.openId === id;
|
|
141
|
-
const
|
|
142
|
-
const sortedProfiles = (0, import_react2.useMemo)(() => [...profiles].sort((a, b) => a.name.localeCompare(b.name)), [profiles]);
|
|
143
|
-
const { width: contentWidth, height: contentHeight } = getProfilePickerContentSize(profiles.length, !!onManage, colorSection);
|
|
144
|
-
const auto = (0, import_hud.useAutoAlign)(open, contentWidth, contentHeight, rotation);
|
|
121
|
+
const auto = (0, import_hud.useAutoAlign)(open, contentSize.width, contentSize.height, rotation);
|
|
145
122
|
const placement = alignOverride ?? auto;
|
|
146
123
|
const { maxHeight, measured, triggerRef, verticalAlign } = placement;
|
|
147
124
|
const align = forcedAlign ?? placement.align;
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
host.close();
|
|
151
|
-
};
|
|
152
|
-
const handleSelectExisting = (profile) => {
|
|
153
|
-
if (profile.id === takenId) return;
|
|
154
|
-
onSelect(profile);
|
|
155
|
-
host.close();
|
|
156
|
-
};
|
|
157
|
-
const handleManage = () => {
|
|
158
|
-
host.close();
|
|
159
|
-
onManage?.();
|
|
160
|
-
};
|
|
161
|
-
const chipTrigger = !!colorSection;
|
|
162
|
-
const [triggerWidth, setTriggerWidth] = (0, import_react2.useState)(0);
|
|
125
|
+
const chipTrigger = !!chip;
|
|
126
|
+
const [triggerWidth, setTriggerWidth] = (0, import_react.useState)(0);
|
|
163
127
|
const handleAnchorLayout = chipTrigger ? (e) => setTriggerWidth(e.nativeEvent.layout.width) : void 0;
|
|
164
|
-
const [colorPage, setColorPage] = (0,
|
|
128
|
+
const [colorPage, setColorPage] = (0, import_react.useState)(false);
|
|
129
|
+
const showColorPage = !!colorSection && colorPage;
|
|
165
130
|
const handleTriggerPress = () => {
|
|
166
131
|
setColorPage(false);
|
|
167
132
|
host.toggle(id);
|
|
168
133
|
};
|
|
169
|
-
const triggerLabel =
|
|
170
|
-
const
|
|
171
|
-
return /* @__PURE__ */ (0,
|
|
172
|
-
/* @__PURE__ */ (0,
|
|
173
|
-
|
|
174
|
-
/* @__PURE__ */ (0,
|
|
175
|
-
/* @__PURE__ */ (0,
|
|
134
|
+
const triggerLabel = label.toUpperCase();
|
|
135
|
+
const showFooter = !!footer && !showColorPage;
|
|
136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: [styles2.anchor, open && styles2.anchorOpen], onLayout: handleAnchorLayout, children: [
|
|
137
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.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_runtime2.jsxs)(import_react_native2.View, { ref: triggerRef, collapsable: false, style: chipTrigger ? styles2.chipTriggerInner : styles2.triggerInner, children: [
|
|
138
|
+
chip && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IdentityChip, { color, tag: chip.tag, icon: chip.icon, size: CHIP_SIZE }),
|
|
139
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { style: [styles2.triggerLabel, { color: chipTrigger ? fg : color }], numberOfLines: 1, children: triggerLabel }),
|
|
140
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: "menu-down", size: 16, color: chipTrigger ? fg : color })
|
|
176
141
|
] }) }),
|
|
177
|
-
/* @__PURE__ */ (0,
|
|
142
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.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_runtime2.jsxs)(
|
|
178
143
|
import_react_native2.View,
|
|
179
144
|
{
|
|
180
145
|
style: [
|
|
@@ -187,77 +152,81 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
187
152
|
}
|
|
188
153
|
],
|
|
189
154
|
children: [
|
|
190
|
-
/* @__PURE__ */ (0,
|
|
191
|
-
colorSection && /* @__PURE__ */ (0,
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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: [
|
|
219
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, { style: [styles2.divider, { backgroundColor: color }] }),
|
|
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: [
|
|
221
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "account-cog-outline", size: 16, color }),
|
|
222
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles2.manageLabel, { color: fg }], children: "Manage" })
|
|
223
|
-
] }) })
|
|
155
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_auto_paper2.FadingScrollView, { contentContainerStyle: [styles2.menuContent, showFooter && styles2.menuContentAboveFooter], showsVerticalScrollIndicator: false, children: colorSection && colorPage ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ColorPage, { section: colorSection, homeColor, fg, onBack: () => setColorPage(false) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
156
|
+
colorSection && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ColorRow, { section: colorSection, fg, dividerColor: color, onPress: () => setColorPage(true) }),
|
|
157
|
+
children
|
|
158
|
+
] }) }, showColorPage ? "color" : "list"),
|
|
159
|
+
showFooter && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: styles2.menuFooter, children: [
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: [styles2.divider, { backgroundColor: color }] }),
|
|
161
|
+
footer
|
|
224
162
|
] })
|
|
225
163
|
]
|
|
226
164
|
}
|
|
227
165
|
) })
|
|
228
166
|
] });
|
|
229
167
|
}
|
|
168
|
+
function IconRow({ icon, label, selected, color, fg, disabled = false, onPress }) {
|
|
169
|
+
const textColor = selected ? (0, import_auto_paper2.getContrastColor)(color) : fg;
|
|
170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_feedback_press.TouchableRipple, { disabled, onPress, style: [pickerMenuStyles.row, selected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: [pickerMenuStyles.rowInner, disabled && pickerMenuStyles.rowDisabled], children: [
|
|
171
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.iconSlot, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: icon, size: 13, color: textColor }) }),
|
|
172
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { style: [pickerMenuStyles.rowLabel, { color: textColor }], numberOfLines: 1, children: label })
|
|
173
|
+
] }) });
|
|
174
|
+
}
|
|
230
175
|
function ColorRow({ section, fg, dividerColor, onPress }) {
|
|
231
176
|
const { value, previewValue, label = "Color", caption } = section;
|
|
232
177
|
const drawn = previewValue ? previewValue(value) : value;
|
|
233
|
-
return /* @__PURE__ */ (0,
|
|
234
|
-
/* @__PURE__ */ (0,
|
|
235
|
-
/* @__PURE__ */ (0,
|
|
236
|
-
/* @__PURE__ */ (0,
|
|
237
|
-
/* @__PURE__ */ (0,
|
|
238
|
-
caption ? /* @__PURE__ */ (0,
|
|
178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
179
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_feedback_press.TouchableRipple, { onPress, style: [pickerMenuStyles.row, { height: colorRowHeight(caption) }], accessibilityRole: "button", accessibilityLabel: caption ? `${label}, ${caption}` : label, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: pickerMenuStyles.rowInner, children: [
|
|
180
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: [styles2.colorRowSwatch, { backgroundColor: drawn }] }),
|
|
181
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: styles2.colorRowText, children: [
|
|
182
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { style: [styles2.colorRowLabel, { color: fg }], numberOfLines: 1, children: label }),
|
|
183
|
+
caption ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { style: [styles2.colorRowCaption, { color: fg }], numberOfLines: 1, children: caption }) : null
|
|
239
184
|
] }),
|
|
240
|
-
/* @__PURE__ */ (0,
|
|
185
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: "chevron-right", size: 18, color: fg })
|
|
241
186
|
] }) }),
|
|
242
|
-
/* @__PURE__ */ (0,
|
|
187
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: [styles2.divider, { backgroundColor: dividerColor }] })
|
|
243
188
|
] });
|
|
244
189
|
}
|
|
245
|
-
function ColorPage({ section,
|
|
246
|
-
const { value, onChange, previewValue, swatches = import_auto_paper2.defaultColors, label = "Color" } = section;
|
|
190
|
+
function ColorPage({ section, homeColor, fg, onBack }) {
|
|
191
|
+
const { value, onChange, previewValue, swatches = import_auto_paper2.defaultColors, label = "Color", takenValue, allowSwapTaken } = section;
|
|
247
192
|
const displayFor = previewValue ?? ((hex) => hex);
|
|
248
|
-
return /* @__PURE__ */ (0,
|
|
249
|
-
/* @__PURE__ */ (0,
|
|
250
|
-
/* @__PURE__ */ (0,
|
|
251
|
-
/* @__PURE__ */ (0,
|
|
193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
194
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_feedback_press.TouchableRipple, { onPress: onBack, style: pickerMenuStyles.row, accessibilityRole: "button", accessibilityLabel: "Back", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: pickerMenuStyles.rowInner, children: [
|
|
195
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.iconSlot, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: "chevron-left", size: 20, color: fg }) }),
|
|
196
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { style: [styles2.colorRowLabel, { color: fg }], numberOfLines: 1, children: label })
|
|
252
197
|
] }) }),
|
|
253
|
-
/* @__PURE__ */ (0,
|
|
198
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.swatches, children: swatches.map((swatch) => {
|
|
254
199
|
const selected = swatch.value.toLowerCase() === value.toLowerCase();
|
|
255
|
-
const
|
|
200
|
+
const isHomeColor = !!homeColor && swatch.value.toLowerCase() === homeColor.toLowerCase();
|
|
201
|
+
const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
|
|
202
|
+
const swappable = taken && !!allowSwapTaken;
|
|
256
203
|
const swatchDisplay = displayFor(swatch.value);
|
|
257
|
-
|
|
204
|
+
const contrast = (0, import_auto_paper2.getContrastColor)(swatchDisplay);
|
|
205
|
+
const accessibilityLabel = swappable ? `${swatch.label}, swap` : taken ? `${swatch.label}, taken` : isHomeColor ? `${swatch.label}, profile color` : swatch.label;
|
|
206
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_feedback_press.TouchableRipple, { disabled: taken && !swappable, onPress: () => onChange(swatch.value), borderless: true, style: [styles2.swatch, { backgroundColor: swatchDisplay }, selected && styles2.swatchSelected, taken && !swappable && styles2.swatchTaken], accessibilityRole: "button", accessibilityLabel, accessibilityState: { selected, disabled: taken && !swappable }, children: selected ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: "check", size: 16, color: contrast }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: "swap-horizontal", size: 16, color: contrast }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: "close", size: 16, color: contrast }) : isHomeColor ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: [styles2.homeDot, { backgroundColor: contrast }] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, {}) }, swatch.value);
|
|
258
207
|
}) })
|
|
259
208
|
] });
|
|
260
209
|
}
|
|
210
|
+
var pickerMenuStyles = import_react_native2.StyleSheet.create({
|
|
211
|
+
row: {
|
|
212
|
+
borderRadius: 8,
|
|
213
|
+
height: ROW_HEIGHT
|
|
214
|
+
},
|
|
215
|
+
rowDisabled: {
|
|
216
|
+
opacity: 0.35
|
|
217
|
+
},
|
|
218
|
+
rowInner: {
|
|
219
|
+
alignItems: "center",
|
|
220
|
+
flexDirection: "row",
|
|
221
|
+
flex: 1,
|
|
222
|
+
gap: 8,
|
|
223
|
+
paddingHorizontal: ROW_INSET
|
|
224
|
+
},
|
|
225
|
+
rowLabel: {
|
|
226
|
+
flex: 1,
|
|
227
|
+
fontSize: 14
|
|
228
|
+
}
|
|
229
|
+
});
|
|
261
230
|
var styles2 = import_react_native2.StyleSheet.create({
|
|
262
231
|
anchor: {
|
|
263
232
|
position: "relative"
|
|
@@ -301,38 +270,31 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
301
270
|
colorRowText: {
|
|
302
271
|
flex: 1
|
|
303
272
|
},
|
|
304
|
-
// Separates
|
|
305
|
-
// action, not just another row in the same list. Tinted with the seat's own color
|
|
306
|
-
// backgroundColor) rather than a flat gray, matching the border/caret's own
|
|
273
|
+
// Separates the footer (a navigation action) and the Color row from the selectable rows - a
|
|
274
|
+
// different kind of action, not just another row in the same list. Tinted with the seat's own color
|
|
275
|
+
// (passed in as backgroundColor) rather than a flat gray, matching the border/caret's own
|
|
276
|
+
// accent-tinted look.
|
|
307
277
|
divider: {
|
|
308
278
|
height: 1,
|
|
309
279
|
marginVertical: 4,
|
|
310
280
|
opacity: 0.25
|
|
311
281
|
},
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
282
|
+
// The selected profile's own color (see ColorPage).
|
|
283
|
+
homeDot: {
|
|
284
|
+
borderRadius: 4,
|
|
285
|
+
height: 8,
|
|
286
|
+
width: 8
|
|
287
|
+
},
|
|
288
|
+
// Matches ProfileChip's own default size/shape exactly (see IconRow's own render-site comment) -
|
|
289
|
+
// no backgroundColor, unlike ProfileChip's own default: an icon row has no identity color of its
|
|
290
|
+
// own to fill it with, and the render site colors the icon directly instead.
|
|
291
|
+
iconSlot: {
|
|
316
292
|
alignItems: "center",
|
|
317
293
|
borderRadius: 11,
|
|
318
294
|
height: 22,
|
|
319
295
|
justifyContent: "center",
|
|
320
296
|
width: 22
|
|
321
297
|
},
|
|
322
|
-
manageLabel: {
|
|
323
|
-
fontSize: 13,
|
|
324
|
-
fontWeight: "700",
|
|
325
|
-
letterSpacing: 0.5
|
|
326
|
-
},
|
|
327
|
-
// Centered rather than left-aligned like a normal row - see this row's own render-site comment
|
|
328
|
-
// for why (a footer action, not another selectable identity).
|
|
329
|
-
manageRowInner: {
|
|
330
|
-
alignItems: "center",
|
|
331
|
-
flexDirection: "row",
|
|
332
|
-
gap: 6,
|
|
333
|
-
height: "100%",
|
|
334
|
-
justifyContent: "center"
|
|
335
|
-
},
|
|
336
298
|
menu: {
|
|
337
299
|
borderRadius: 12,
|
|
338
300
|
borderWidth: MENU_BORDER_WIDTH,
|
|
@@ -348,7 +310,7 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
348
310
|
menuContent: {
|
|
349
311
|
padding: LIST_PADDING
|
|
350
312
|
},
|
|
351
|
-
// With
|
|
313
|
+
// With a footer pinned below, its own padding takes the bottom edge (same total height as before).
|
|
352
314
|
menuContentAboveFooter: {
|
|
353
315
|
paddingBottom: 0
|
|
354
316
|
},
|
|
@@ -356,30 +318,6 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
356
318
|
paddingBottom: LIST_PADDING,
|
|
357
319
|
paddingHorizontal: LIST_PADDING
|
|
358
320
|
},
|
|
359
|
-
// The selected profile's own color (see ColorSection).
|
|
360
|
-
profileDot: {
|
|
361
|
-
borderRadius: 4,
|
|
362
|
-
height: 8,
|
|
363
|
-
width: 8
|
|
364
|
-
},
|
|
365
|
-
row: {
|
|
366
|
-
borderRadius: 8,
|
|
367
|
-
height: ROW_HEIGHT
|
|
368
|
-
},
|
|
369
|
-
rowDisabled: {
|
|
370
|
-
opacity: 0.35
|
|
371
|
-
},
|
|
372
|
-
rowInner: {
|
|
373
|
-
alignItems: "center",
|
|
374
|
-
flexDirection: "row",
|
|
375
|
-
flex: 1,
|
|
376
|
-
gap: 8,
|
|
377
|
-
paddingHorizontal: ROW_INSET
|
|
378
|
-
},
|
|
379
|
-
rowLabel: {
|
|
380
|
-
flex: 1,
|
|
381
|
-
fontSize: 14
|
|
382
|
-
},
|
|
383
321
|
swatch: {
|
|
384
322
|
alignItems: "center",
|
|
385
323
|
borderRadius: SWATCH_SIZE / 2,
|
|
@@ -391,6 +329,9 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
391
329
|
borderColor: "#ffffff",
|
|
392
330
|
borderWidth: 2
|
|
393
331
|
},
|
|
332
|
+
swatchTaken: {
|
|
333
|
+
opacity: 0.35
|
|
334
|
+
},
|
|
394
335
|
swatches: {
|
|
395
336
|
columnGap: GRID_GAP,
|
|
396
337
|
flexDirection: "row",
|
|
@@ -417,15 +358,128 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
417
358
|
}
|
|
418
359
|
});
|
|
419
360
|
|
|
420
|
-
// src/
|
|
361
|
+
// src/OptionPicker.tsx
|
|
362
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
363
|
+
function getOptionPickerContentSize(optionCount, colorSection) {
|
|
364
|
+
return pickerContentSize(optionCount, colorSection);
|
|
365
|
+
}
|
|
366
|
+
function OptionPicker({ id, host, options, value, onChange, color, dark, icon, rowIcon = icon, colorSection, align, alignOverride, rotation = 0, triggerStyle }) {
|
|
367
|
+
const fg = dark ? "#FFFFFF" : "#000000";
|
|
368
|
+
const selected = options.find((option) => option.value === value);
|
|
369
|
+
const handleSelect = (option) => {
|
|
370
|
+
onChange(option.value);
|
|
371
|
+
host.close();
|
|
372
|
+
};
|
|
373
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PickerMenu, { id, host, color, dark, label: selected?.label ?? "", chip: { icon }, colorSection, contentSize: getOptionPickerContentSize(options.length, colorSection), align, alignOverride, rotation, triggerStyle, children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(IconRow, { icon: option.icon ?? rowIcon, label: option.label, selected: option.value === value, color, fg, onPress: () => handleSelect(option) }, option.value)) });
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// src/ProfileColorContext.tsx
|
|
377
|
+
var import_react2 = require("react");
|
|
378
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
379
|
+
var ProfileColorContext = (0, import_react2.createContext)(void 0);
|
|
380
|
+
function ProfileColorProvider({ preview, children }) {
|
|
381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ProfileColorContext.Provider, { value: preview, children });
|
|
382
|
+
}
|
|
383
|
+
function useProfileColorPreview() {
|
|
384
|
+
return (0, import_react2.useContext)(ProfileColorContext);
|
|
385
|
+
}
|
|
386
|
+
function useProfileDisplayColor(hex) {
|
|
387
|
+
const preview = useProfileColorPreview();
|
|
388
|
+
return preview ? preview(hex) : hex;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// src/ProfileChip.tsx
|
|
392
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
393
|
+
function ProfileChip({ profile, size = 22, filled = true }) {
|
|
394
|
+
const color = useProfileDisplayColor(profile.color);
|
|
395
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(IdentityChip, { color, tag: profile.tag, icon: "account", size, filled });
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// src/ProfilePicker.tsx
|
|
421
399
|
var import_auto_paper3 = require("@rific/auto-paper");
|
|
422
400
|
var import_feedback_press2 = require("@rific/feedback-press");
|
|
423
|
-
var import_focus_chain = require("@rific/focus-chain");
|
|
424
|
-
var import_toaster = require("@rific/toaster");
|
|
425
|
-
var import_hud2 = require("@tastic/hud");
|
|
426
401
|
var import_react3 = require("react");
|
|
427
402
|
var import_react_native3 = require("react-native");
|
|
428
403
|
var import_react_native_paper3 = require("react-native-paper");
|
|
404
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
405
|
+
function getProfilePickerContentSize(profileCount, hasManageRow = false, colorSection) {
|
|
406
|
+
return pickerContentSize(profileCount + 1 + (hasManageRow ? 1 : 0), colorSection);
|
|
407
|
+
}
|
|
408
|
+
function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, dark, align, alignOverride, rotation = 0, guestLabel, nullLabel = "Player", nullIcon = "account-off-outline", onSelect, onManage, colorSection, triggerStyle }) {
|
|
409
|
+
const id = `${idPrefix}-profile`;
|
|
410
|
+
const colorPreview = useProfileColorPreview();
|
|
411
|
+
const fg = dark ? "#FFFFFF" : "#000000";
|
|
412
|
+
const selectedProfile = profiles.find((p) => p.id === selectedId) ?? null;
|
|
413
|
+
const sortedProfiles = (0, import_react3.useMemo)(() => [...profiles].sort((a, b) => a.name.localeCompare(b.name)), [profiles]);
|
|
414
|
+
const contentSize = getProfilePickerContentSize(profiles.length, !!onManage, colorSection);
|
|
415
|
+
const handleSelectGuest = () => {
|
|
416
|
+
onSelect(null);
|
|
417
|
+
host.close();
|
|
418
|
+
};
|
|
419
|
+
const handleSelectExisting = (profile) => {
|
|
420
|
+
if (profile.id === takenId) return;
|
|
421
|
+
onSelect(profile);
|
|
422
|
+
host.close();
|
|
423
|
+
};
|
|
424
|
+
const handleManage = () => {
|
|
425
|
+
host.close();
|
|
426
|
+
onManage?.();
|
|
427
|
+
};
|
|
428
|
+
const manageFooter = onManage ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_feedback_press2.TouchableRipple, { onPress: handleManage, style: pickerMenuStyles.row, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native3.View, { style: styles3.manageRowInner, children: [
|
|
429
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper3.Icon, { source: "account-cog-outline", size: 16, color }),
|
|
430
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper3.Text, { style: [styles3.manageLabel, { color: fg }], children: "Manage" })
|
|
431
|
+
] }) }) : void 0;
|
|
432
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(PickerMenu, { id, host, color, dark, label: selectedProfile?.name ?? guestLabel, chip: colorSection ? { tag: selectedProfile?.tag, icon: selectedProfile ? "account" : nullIcon } : void 0, colorSection, homeColor: selectedProfile?.color, contentSize, align, alignOverride, rotation, triggerStyle, footer: manageFooter, children: [
|
|
433
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(IconRow, { icon: nullIcon, label: nullLabel, selected: selectedId === null, color, fg, onPress: handleSelectGuest }),
|
|
434
|
+
sortedProfiles.map((profile) => {
|
|
435
|
+
const taken = profile.id === takenId;
|
|
436
|
+
const selected = selectedId === profile.id;
|
|
437
|
+
const rowColor = colorPreview ? colorPreview(profile.color) : profile.color;
|
|
438
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_feedback_press2.TouchableRipple, { disabled: taken, onPress: () => handleSelectExisting(profile), style: [pickerMenuStyles.row, selected && { backgroundColor: rowColor }], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native3.View, { style: [pickerMenuStyles.rowInner, taken && pickerMenuStyles.rowDisabled], children: [
|
|
439
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProfileChip, { profile, filled: !selected }),
|
|
440
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
441
|
+
import_react_native_paper3.Text,
|
|
442
|
+
{
|
|
443
|
+
style: [
|
|
444
|
+
pickerMenuStyles.rowLabel,
|
|
445
|
+
{
|
|
446
|
+
color: selected ? (0, import_auto_paper3.getContrastColor)(rowColor) : fg
|
|
447
|
+
}
|
|
448
|
+
],
|
|
449
|
+
numberOfLines: 1,
|
|
450
|
+
children: profile.name
|
|
451
|
+
}
|
|
452
|
+
)
|
|
453
|
+
] }) }, profile.id);
|
|
454
|
+
})
|
|
455
|
+
] });
|
|
456
|
+
}
|
|
457
|
+
var styles3 = import_react_native3.StyleSheet.create({
|
|
458
|
+
manageLabel: {
|
|
459
|
+
fontSize: 13,
|
|
460
|
+
fontWeight: "700",
|
|
461
|
+
letterSpacing: 0.5
|
|
462
|
+
},
|
|
463
|
+
// Centered rather than left-aligned like a normal row - see the footer's own comment for why (a
|
|
464
|
+
// footer action, not another selectable identity).
|
|
465
|
+
manageRowInner: {
|
|
466
|
+
alignItems: "center",
|
|
467
|
+
flexDirection: "row",
|
|
468
|
+
gap: 6,
|
|
469
|
+
height: "100%",
|
|
470
|
+
justifyContent: "center"
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
// src/ProfilesManager.tsx
|
|
475
|
+
var import_auto_paper4 = require("@rific/auto-paper");
|
|
476
|
+
var import_feedback_press3 = require("@rific/feedback-press");
|
|
477
|
+
var import_focus_chain = require("@rific/focus-chain");
|
|
478
|
+
var import_toaster = require("@rific/toaster");
|
|
479
|
+
var import_hud2 = require("@tastic/hud");
|
|
480
|
+
var import_react4 = require("react");
|
|
481
|
+
var import_react_native4 = require("react-native");
|
|
482
|
+
var import_react_native_paper4 = require("react-native-paper");
|
|
429
483
|
var import_react_native_safe_area_context = require("react-native-safe-area-context");
|
|
430
484
|
|
|
431
485
|
// src/profilesValidation.ts
|
|
@@ -461,7 +515,7 @@ function isValidProfile(value) {
|
|
|
461
515
|
}
|
|
462
516
|
|
|
463
517
|
// src/ProfilesManager.tsx
|
|
464
|
-
var
|
|
518
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
465
519
|
var CHIP_SIZE2 = 40;
|
|
466
520
|
function deriveTag(name) {
|
|
467
521
|
const trimmed = name.trim();
|
|
@@ -470,19 +524,19 @@ function deriveTag(name) {
|
|
|
470
524
|
function ProfilesManager({ profiles, defaultColor, onCreate, onSave, onDelete, headerLeft, ref, fg: fgOverride, fgMuted: fgMutedOverride, titleVariant = "headlineSmall", colorPreview: colorPreviewProp, useColorPickerAlign }) {
|
|
471
525
|
const contextColorPreview = useProfileColorPreview();
|
|
472
526
|
const colorPreview = colorPreviewProp ?? contextColorPreview;
|
|
473
|
-
const { dark } = (0,
|
|
527
|
+
const { dark } = (0, import_auto_paper4.useAutoPaperTheme)();
|
|
474
528
|
const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
|
|
475
529
|
const { error: showErrorToast } = (0, import_toaster.useToast)();
|
|
476
530
|
const host = (0, import_hud2.usePopoverHost)();
|
|
477
531
|
const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
|
|
478
532
|
const fgMuted = fgMutedOverride ?? (dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)");
|
|
479
|
-
const [editingId, setEditingId] = (0,
|
|
480
|
-
const [draftName, setDraftName] = (0,
|
|
481
|
-
const [draftColor, setDraftColor] = (0,
|
|
482
|
-
const [draftTag, setDraftTag] = (0,
|
|
483
|
-
const [tagManuallySet, setTagManuallySet] = (0,
|
|
484
|
-
const [confirmDeleteId, setConfirmDeleteId] = (0,
|
|
485
|
-
const commitEdit = (0,
|
|
533
|
+
const [editingId, setEditingId] = (0, import_react4.useState)(null);
|
|
534
|
+
const [draftName, setDraftName] = (0, import_react4.useState)("");
|
|
535
|
+
const [draftColor, setDraftColor] = (0, import_react4.useState)(defaultColor);
|
|
536
|
+
const [draftTag, setDraftTag] = (0, import_react4.useState)("");
|
|
537
|
+
const [tagManuallySet, setTagManuallySet] = (0, import_react4.useState)(false);
|
|
538
|
+
const [confirmDeleteId, setConfirmDeleteId] = (0, import_react4.useState)(null);
|
|
539
|
+
const commitEdit = (0, import_react4.useCallback)(() => {
|
|
486
540
|
const name = draftName.trim();
|
|
487
541
|
if (editingId && name) {
|
|
488
542
|
const tagValid = isValidTag(draftTag);
|
|
@@ -493,13 +547,13 @@ function ProfilesManager({ profiles, defaultColor, onCreate, onSave, onDelete, h
|
|
|
493
547
|
}
|
|
494
548
|
setEditingId(null);
|
|
495
549
|
}, [editingId, draftName, draftColor, draftTag, onCreate, onSave, showErrorToast]);
|
|
496
|
-
const commitEditRef = (0,
|
|
497
|
-
(0,
|
|
550
|
+
const commitEditRef = (0, import_react4.useRef)(commitEdit);
|
|
551
|
+
(0, import_react4.useEffect)(() => {
|
|
498
552
|
commitEditRef.current = commitEdit;
|
|
499
553
|
});
|
|
500
|
-
(0,
|
|
501
|
-
(0,
|
|
502
|
-
const startEdit = (0,
|
|
554
|
+
(0, import_react4.useEffect)(() => () => commitEditRef.current(), []);
|
|
555
|
+
(0, import_react4.useImperativeHandle)(ref, () => ({ commitPendingEdit: () => commitEditRef.current() }), []);
|
|
556
|
+
const startEdit = (0, import_react4.useCallback)(
|
|
503
557
|
(target) => {
|
|
504
558
|
commitEdit();
|
|
505
559
|
if (target === "new") {
|
|
@@ -517,79 +571,79 @@ function ProfilesManager({ profiles, defaultColor, onCreate, onSave, onDelete, h
|
|
|
517
571
|
},
|
|
518
572
|
[commitEdit, defaultColor]
|
|
519
573
|
);
|
|
520
|
-
const handleNameChange = (0,
|
|
574
|
+
const handleNameChange = (0, import_react4.useCallback)(
|
|
521
575
|
(name) => {
|
|
522
576
|
setDraftName(name);
|
|
523
577
|
if (!tagManuallySet) setDraftTag(deriveTag(name));
|
|
524
578
|
},
|
|
525
579
|
[tagManuallySet]
|
|
526
580
|
);
|
|
527
|
-
const handleTagChange = (0,
|
|
581
|
+
const handleTagChange = (0, import_react4.useCallback)((tag) => {
|
|
528
582
|
setDraftTag((previous) => clampTag(previous, tag));
|
|
529
583
|
setTagManuallySet(true);
|
|
530
584
|
}, []);
|
|
531
585
|
const confirmDeleteProfile = profiles.find((p) => p.id === confirmDeleteId) ?? null;
|
|
532
|
-
const handleConfirmDelete = (0,
|
|
586
|
+
const handleConfirmDelete = (0, import_react4.useCallback)(() => {
|
|
533
587
|
if (confirmDeleteId) {
|
|
534
588
|
onDelete(confirmDeleteId);
|
|
535
589
|
if (editingId === confirmDeleteId) setEditingId(null);
|
|
536
590
|
}
|
|
537
591
|
setConfirmDeleteId(null);
|
|
538
592
|
}, [confirmDeleteId, editingId, onDelete]);
|
|
539
|
-
const sortedProfiles = (0,
|
|
593
|
+
const sortedProfiles = (0, import_react4.useMemo)(() => [...profiles].sort((a, b) => a.name.localeCompare(b.name)), [profiles]);
|
|
540
594
|
const rows = [...sortedProfiles.map((profile) => ({ kind: "profile", profile })), { kind: "new" }];
|
|
541
|
-
return /* @__PURE__ */ (0,
|
|
542
|
-
/* @__PURE__ */ (0,
|
|
595
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
596
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native4.View, { style: [styles4.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
|
|
543
597
|
headerLeft,
|
|
544
|
-
/* @__PURE__ */ (0,
|
|
598
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Text, { variant: titleVariant, style: [styles4.title, { color: fg }], children: "Profiles" })
|
|
545
599
|
] }),
|
|
546
|
-
/* @__PURE__ */ (0,
|
|
600
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native4.KeyboardAvoidingView, { behavior: import_react_native4.Platform.OS === "ios" ? "padding" : void 0, style: styles4.keyboardAvoiding, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_auto_paper4.FadingScrollView, { style: styles4.scrollView, contentContainerStyle: [styles4.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, keyboardShouldPersistTaps: "handled", children: rows.map((row) => {
|
|
547
601
|
if (row.kind === "new") {
|
|
548
602
|
if (editingId !== "new") {
|
|
549
|
-
return /* @__PURE__ */ (0,
|
|
550
|
-
/* @__PURE__ */ (0,
|
|
551
|
-
/* @__PURE__ */ (0,
|
|
603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.TouchableRipple, { onPress: () => startEdit("new"), style: styles4.row, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native4.View, { style: styles4.rowInner, children: [
|
|
604
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native4.View, { style: [styles4.rowChip, styles4.newChip, { borderColor: fg }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Icon, { source: "plus", size: 20, color: fg }) }),
|
|
605
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Text, { variant: "bodyLarge", style: { color: fg }, children: "New Profile" })
|
|
552
606
|
] }) }, "new");
|
|
553
607
|
}
|
|
554
|
-
return /* @__PURE__ */ (0,
|
|
608
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(EditRow, { draftName, onNameChange: handleNameChange, draftColor, onColorChange: setDraftColor, draftTag, onTagChange: handleTagChange, onSubmit: commitEdit, autoFocus: true, fgMuted, host, dark, colorPreview, useColorPickerAlign }, "new");
|
|
555
609
|
}
|
|
556
610
|
const { profile } = row;
|
|
557
611
|
if (editingId === profile.id) {
|
|
558
|
-
return /* @__PURE__ */ (0,
|
|
612
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(EditRow, { draftName, onNameChange: handleNameChange, draftColor, onColorChange: setDraftColor, draftTag, onTagChange: handleTagChange, onSubmit: commitEdit, onDelete: () => setConfirmDeleteId(profile.id), fgMuted, host, dark, colorPreview, useColorPickerAlign }, profile.id);
|
|
559
613
|
}
|
|
560
|
-
return /* @__PURE__ */ (0,
|
|
561
|
-
/* @__PURE__ */ (0,
|
|
562
|
-
/* @__PURE__ */ (0,
|
|
614
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.TouchableRipple, { onPress: () => startEdit(profile), style: styles4.row, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native4.View, { style: styles4.rowInner, children: [
|
|
615
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ProfileChip, { profile, size: CHIP_SIZE2 }),
|
|
616
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Text, { variant: "bodyLarge", style: [styles4.rowName, { color: fg }], numberOfLines: 1, children: profile.name })
|
|
563
617
|
] }) }, profile.id);
|
|
564
618
|
}) }) }),
|
|
565
|
-
/* @__PURE__ */ (0,
|
|
619
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.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) })
|
|
566
620
|
] });
|
|
567
621
|
}
|
|
568
622
|
function AlignedColorPicker({ useAlign, ...props }) {
|
|
569
|
-
const { width: windowWidth } = (0,
|
|
570
|
-
const { width, height } = (0, import_hud2.getInlineColorPickerContentSize)(
|
|
623
|
+
const { width: windowWidth } = (0, import_react_native4.useWindowDimensions)();
|
|
624
|
+
const { width, height } = (0, import_hud2.getInlineColorPickerContentSize)(import_auto_paper4.defaultColors.length, windowWidth);
|
|
571
625
|
const alignOverride = useAlign(props.host.openId === props.id, width, height);
|
|
572
|
-
return /* @__PURE__ */ (0,
|
|
626
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_hud2.InlineColorPicker, { ...props, alignOverride });
|
|
573
627
|
}
|
|
574
628
|
function EditRow({ draftName, onNameChange, draftColor, onColorChange, draftTag, onTagChange, onSubmit, onDelete, autoFocus, fgMuted, host, dark, colorPreview, useColorPickerAlign }) {
|
|
575
629
|
const register = (0, import_focus_chain.useFocusChain)();
|
|
576
630
|
const tag = register();
|
|
577
631
|
const name = register();
|
|
578
|
-
const tagFocusRef = (0,
|
|
579
|
-
(0,
|
|
632
|
+
const tagFocusRef = (0, import_react4.useRef)(tag.props.focus);
|
|
633
|
+
(0, import_react4.useEffect)(() => {
|
|
580
634
|
tagFocusRef.current = tag.props.focus;
|
|
581
635
|
});
|
|
582
|
-
(0,
|
|
636
|
+
(0, import_react4.useEffect)(() => {
|
|
583
637
|
if (host.openId === "color") tagFocusRef.current();
|
|
584
638
|
}, [host.openId]);
|
|
585
|
-
return /* @__PURE__ */ (0,
|
|
586
|
-
useColorPickerAlign ? /* @__PURE__ */ (0,
|
|
587
|
-
/* @__PURE__ */ (0,
|
|
588
|
-
/* @__PURE__ */ (0,
|
|
589
|
-
onDelete && /* @__PURE__ */ (0,
|
|
639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native4.View, { style: styles4.editRow, children: [
|
|
640
|
+
useColorPickerAlign ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AlignedColorPicker, { useAlign: useColorPickerAlign, id: "color", host, value: draftColor, onChange: onColorChange, previewValue: colorPreview, tag: draftTag, dark }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_hud2.InlineColorPicker, { id: "color", host, value: draftColor, onChange: onColorChange, previewValue: colorPreview, tag: draftTag, dark }),
|
|
641
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.TextInput, { ref: tag.ref, ...tag.props, value: draftTag, onChangeText: onTagChange, accessibilityLabel: "Tag", autoCapitalize: "characters", selectTextOnFocus: true, returnKeyType: "next", style: styles4.hiddenTagInput, pointerEvents: "none" }),
|
|
642
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.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: styles4.nameInput }),
|
|
643
|
+
onDelete && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.TouchableRipple, { onPress: onDelete, style: styles4.iconButton, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Icon, { source: "trash-can-outline", size: 18, color: fgMuted }) })
|
|
590
644
|
] });
|
|
591
645
|
}
|
|
592
|
-
var
|
|
646
|
+
var styles4 = import_react_native4.StyleSheet.create({
|
|
593
647
|
content: {
|
|
594
648
|
gap: 4,
|
|
595
649
|
paddingHorizontal: 20
|
|
@@ -668,23 +722,23 @@ var styles3 = import_react_native3.StyleSheet.create({
|
|
|
668
722
|
});
|
|
669
723
|
|
|
670
724
|
// src/ProfilesScreen.tsx
|
|
671
|
-
var
|
|
672
|
-
var
|
|
673
|
-
var
|
|
674
|
-
var
|
|
675
|
-
var
|
|
725
|
+
var import_auto_paper5 = require("@rific/auto-paper");
|
|
726
|
+
var import_feedback_press4 = require("@rific/feedback-press");
|
|
727
|
+
var import_react5 = require("react");
|
|
728
|
+
var import_react_native5 = require("react-native");
|
|
729
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
676
730
|
function ProfilesScreen({ profiles, defaultColor, onCreate, onSave, onDelete, onBack, fg: fgOverride, fgMuted, bg: bgOverride, titleVariant, colorPreview, useColorPickerAlign }) {
|
|
677
|
-
const { dark } = (0,
|
|
678
|
-
const managerRef = (0,
|
|
731
|
+
const { dark } = (0, import_auto_paper5.useAutoPaperTheme)();
|
|
732
|
+
const managerRef = (0, import_react5.useRef)(null);
|
|
679
733
|
const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
|
|
680
734
|
const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
|
|
681
735
|
const handleBack = () => {
|
|
682
736
|
managerRef.current?.commitPendingEdit();
|
|
683
737
|
onBack();
|
|
684
738
|
};
|
|
685
|
-
return /* @__PURE__ */ (0,
|
|
739
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native5.View, { style: [styles5.container, { backgroundColor: bg }], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ProfilesManager, { ref: managerRef, profiles, defaultColor, onCreate, onSave, onDelete, fg, fgMuted, titleVariant, colorPreview, useColorPickerAlign, headerLeft: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press4.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: handleBack, accessibilityLabel: "Back" }) }) });
|
|
686
740
|
}
|
|
687
|
-
var
|
|
741
|
+
var styles5 = import_react_native5.StyleSheet.create({
|
|
688
742
|
container: {
|
|
689
743
|
flex: 1
|
|
690
744
|
}
|
|
@@ -848,36 +902,67 @@ async function resolveInitialProfiles(groupId, localFallback) {
|
|
|
848
902
|
|
|
849
903
|
// src/redux/seatColorsSlice.ts
|
|
850
904
|
var REHYDRATE2 = "persist/REHYDRATE";
|
|
905
|
+
function sameColor(a, b) {
|
|
906
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
907
|
+
}
|
|
908
|
+
function profileSeatColor(profile, profileColors) {
|
|
909
|
+
const pick = profileColors[profile.id];
|
|
910
|
+
return pick && sameColor(pick.profileColor, profile.color) ? pick.color : profile.color;
|
|
911
|
+
}
|
|
851
912
|
function createSeatColorsSlice(namespace, defaultState, mountKey = "seatColors") {
|
|
852
913
|
const setLastCpuColor = createActionCreator(`seatColors/${namespace}/setLastCpuColor`);
|
|
853
914
|
const setLastGuestColor = createActionCreator(`seatColors/${namespace}/setLastGuestColor`);
|
|
854
|
-
const
|
|
915
|
+
const setProfileColor = createActionCreator(`seatColors/${namespace}/setProfileColor`);
|
|
916
|
+
function withoutPick(state, id) {
|
|
917
|
+
if (!state.profileColors[id]) return state;
|
|
918
|
+
const profileColors = { ...state.profileColors };
|
|
919
|
+
delete profileColors[id];
|
|
920
|
+
return { ...state, profileColors };
|
|
921
|
+
}
|
|
855
922
|
function reducer(state = defaultState, action) {
|
|
856
923
|
if (action.type === REHYDRATE2) {
|
|
857
924
|
const persisted = action.payload?.[mountKey];
|
|
858
|
-
|
|
925
|
+
const next = { ...defaultState, ...state, ...persisted };
|
|
926
|
+
delete next.profileOverride;
|
|
927
|
+
return next;
|
|
859
928
|
}
|
|
860
929
|
if (setLastCpuColor.match(action)) return { ...state, lastCpuColor: action.payload };
|
|
861
930
|
if (setLastGuestColor.match(action)) return { ...state, lastGuestColor: { ...state.lastGuestColor, [action.payload.seat]: action.payload.color } };
|
|
862
|
-
if (
|
|
931
|
+
if (setProfileColor.match(action)) {
|
|
932
|
+
const { profile, color } = action.payload;
|
|
933
|
+
if (color === null || sameColor(color, profile.color)) return withoutPick(state, profile.id);
|
|
934
|
+
return { ...state, profileColors: { ...state.profileColors, [profile.id]: { color, profileColor: profile.color } } };
|
|
935
|
+
}
|
|
936
|
+
if (profilesActions.remove.match(action)) return withoutPick(state, action.payload);
|
|
937
|
+
if (profilesActions.update.match(action)) {
|
|
938
|
+
const { id, patch } = action.payload;
|
|
939
|
+
const pick = state.profileColors[id];
|
|
940
|
+
return pick && patch.color !== void 0 && !sameColor(patch.color, pick.profileColor) ? withoutPick(state, id) : state;
|
|
941
|
+
}
|
|
942
|
+
if (profilesActions.setAll.match(action)) {
|
|
943
|
+
return action.payload.reduce((next, profile) => {
|
|
944
|
+
const pick = next.profileColors[profile.id];
|
|
945
|
+
return pick && !sameColor(profile.color, pick.profileColor) ? withoutPick(next, profile.id) : next;
|
|
946
|
+
}, state);
|
|
947
|
+
}
|
|
863
948
|
return state;
|
|
864
949
|
}
|
|
865
|
-
return { actions: { setLastCpuColor, setLastGuestColor,
|
|
950
|
+
return { actions: { setLastCpuColor, setLastGuestColor, setProfileColor }, reducer };
|
|
866
951
|
}
|
|
867
952
|
|
|
868
953
|
// src/redux/useSharedProfilesSync.ts
|
|
869
|
-
var
|
|
870
|
-
var
|
|
954
|
+
var import_react6 = require("react");
|
|
955
|
+
var import_react_native6 = require("react-native");
|
|
871
956
|
function useSharedProfilesSync({ groupId, onRemoteChange }) {
|
|
872
|
-
const pendingWriteRef = (0,
|
|
873
|
-
const onRemoteChangeRef = (0,
|
|
874
|
-
(0,
|
|
957
|
+
const pendingWriteRef = (0, import_react6.useRef)(false);
|
|
958
|
+
const onRemoteChangeRef = (0, import_react6.useRef)(onRemoteChange);
|
|
959
|
+
(0, import_react6.useEffect)(() => {
|
|
875
960
|
onRemoteChangeRef.current = onRemoteChange;
|
|
876
961
|
}, [onRemoteChange]);
|
|
877
|
-
(0,
|
|
962
|
+
(0, import_react6.useEffect)(() => {
|
|
878
963
|
if (!isSharedProfileStoreAvailable) return;
|
|
879
964
|
let cancelled = false;
|
|
880
|
-
const sub =
|
|
965
|
+
const sub = import_react_native6.AppState.addEventListener("change", (next) => {
|
|
881
966
|
if (next !== "active" || pendingWriteRef.current) return;
|
|
882
967
|
readSharedProfiles(groupId).then((shared) => {
|
|
883
968
|
if (!cancelled && shared !== null) onRemoteChangeRef.current(shared);
|
|
@@ -888,7 +973,7 @@ function useSharedProfilesSync({ groupId, onRemoteChange }) {
|
|
|
888
973
|
sub.remove();
|
|
889
974
|
};
|
|
890
975
|
}, [groupId]);
|
|
891
|
-
const syncToShared = (0,
|
|
976
|
+
const syncToShared = (0, import_react6.useCallback)(
|
|
892
977
|
(next) => {
|
|
893
978
|
if (!isSharedProfileStoreAvailable) return;
|
|
894
979
|
pendingWriteRef.current = true;
|
|
@@ -912,6 +997,7 @@ function avoidSeatColorClash(p1Color, p2Color, defaults) {
|
|
|
912
997
|
0 && (module.exports = {
|
|
913
998
|
MAX_PROFILE_NAME_LENGTH,
|
|
914
999
|
MAX_TAG_LENGTH,
|
|
1000
|
+
OptionPicker,
|
|
915
1001
|
ProfileChip,
|
|
916
1002
|
ProfileColorProvider,
|
|
917
1003
|
ProfilePicker,
|
|
@@ -922,11 +1008,13 @@ function avoidSeatColorClash(p1Color, p2Color, defaults) {
|
|
|
922
1008
|
createProfileRecord,
|
|
923
1009
|
createProfileSelectionSlice,
|
|
924
1010
|
createSeatColorsSlice,
|
|
1011
|
+
getOptionPickerContentSize,
|
|
925
1012
|
getProfilePickerContentSize,
|
|
926
1013
|
isSharedProfileStoreAvailable,
|
|
927
1014
|
isValidProfile,
|
|
928
1015
|
isValidTag,
|
|
929
1016
|
loadSharedProfiles,
|
|
1017
|
+
profileSeatColor,
|
|
930
1018
|
profilesActions,
|
|
931
1019
|
profilesReducer,
|
|
932
1020
|
readSharedProfiles,
|