@tastic/profile 0.14.0 → 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 +322 -223
- package/dist/index.mjs +279 -183
- package/package.json +8 -8
- package/src/OptionPicker.tsx +64 -0
- package/src/PickerMenu.tsx +481 -0
- package/src/ProfilePicker.tsx +54 -413
- 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,54 +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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
/* @__PURE__ */ (0,
|
|
174
|
-
/* @__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 })
|
|
175
141
|
] }) }),
|
|
176
|
-
/* @__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)(
|
|
177
143
|
import_react_native2.View,
|
|
178
144
|
{
|
|
179
145
|
style: [
|
|
@@ -185,76 +151,82 @@ function ProfilePicker({ idPrefix, host, profiles, selectedId, takenId, color, d
|
|
|
185
151
|
maxHeight
|
|
186
152
|
}
|
|
187
153
|
],
|
|
188
|
-
children:
|
|
189
|
-
colorSection && /* @__PURE__ */ (0,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const selected = selectedId === profile.id;
|
|
197
|
-
const rowColor = colorPreview ? colorPreview(profile.color) : profile.color;
|
|
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)(
|
|
201
|
-
import_react_native_paper2.Text,
|
|
202
|
-
{
|
|
203
|
-
style: [
|
|
204
|
-
styles2.rowLabel,
|
|
205
|
-
{
|
|
206
|
-
color: selected ? (0, import_auto_paper2.getContrastColor)(rowColor) : fg
|
|
207
|
-
}
|
|
208
|
-
],
|
|
209
|
-
numberOfLines: 1,
|
|
210
|
-
children: profile.name
|
|
211
|
-
}
|
|
212
|
-
)
|
|
213
|
-
] }) }, profile.id);
|
|
214
|
-
}),
|
|
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" })
|
|
220
|
-
] }) })
|
|
154
|
+
children: [
|
|
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
|
|
221
162
|
] })
|
|
222
|
-
]
|
|
163
|
+
]
|
|
223
164
|
}
|
|
224
165
|
) })
|
|
225
166
|
] });
|
|
226
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
|
+
}
|
|
227
175
|
function ColorRow({ section, fg, dividerColor, onPress }) {
|
|
228
176
|
const { value, previewValue, label = "Color", caption } = section;
|
|
229
177
|
const drawn = previewValue ? previewValue(value) : value;
|
|
230
|
-
return /* @__PURE__ */ (0,
|
|
231
|
-
/* @__PURE__ */ (0,
|
|
232
|
-
/* @__PURE__ */ (0,
|
|
233
|
-
/* @__PURE__ */ (0,
|
|
234
|
-
/* @__PURE__ */ (0,
|
|
235
|
-
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
|
|
236
184
|
] }),
|
|
237
|
-
/* @__PURE__ */ (0,
|
|
185
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: "chevron-right", size: 18, color: fg })
|
|
238
186
|
] }) }),
|
|
239
|
-
/* @__PURE__ */ (0,
|
|
187
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: [styles2.divider, { backgroundColor: dividerColor }] })
|
|
240
188
|
] });
|
|
241
189
|
}
|
|
242
|
-
function ColorPage({ section,
|
|
243
|
-
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;
|
|
244
192
|
const displayFor = previewValue ?? ((hex) => hex);
|
|
245
|
-
return /* @__PURE__ */ (0,
|
|
246
|
-
/* @__PURE__ */ (0,
|
|
247
|
-
/* @__PURE__ */ (0,
|
|
248
|
-
/* @__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 })
|
|
249
197
|
] }) }),
|
|
250
|
-
/* @__PURE__ */ (0,
|
|
198
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.swatches, children: swatches.map((swatch) => {
|
|
251
199
|
const selected = swatch.value.toLowerCase() === value.toLowerCase();
|
|
252
|
-
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;
|
|
253
203
|
const swatchDisplay = displayFor(swatch.value);
|
|
254
|
-
|
|
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);
|
|
255
207
|
}) })
|
|
256
208
|
] });
|
|
257
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
|
+
});
|
|
258
230
|
var styles2 = import_react_native2.StyleSheet.create({
|
|
259
231
|
anchor: {
|
|
260
232
|
position: "relative"
|
|
@@ -298,38 +270,31 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
298
270
|
colorRowText: {
|
|
299
271
|
flex: 1
|
|
300
272
|
},
|
|
301
|
-
// Separates
|
|
302
|
-
// action, not just another row in the same list. Tinted with the seat's own color
|
|
303
|
-
// 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.
|
|
304
277
|
divider: {
|
|
305
278
|
height: 1,
|
|
306
279
|
marginVertical: 4,
|
|
307
280
|
opacity: 0.25
|
|
308
281
|
},
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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: {
|
|
313
292
|
alignItems: "center",
|
|
314
293
|
borderRadius: 11,
|
|
315
294
|
height: 22,
|
|
316
295
|
justifyContent: "center",
|
|
317
296
|
width: 22
|
|
318
297
|
},
|
|
319
|
-
manageLabel: {
|
|
320
|
-
fontSize: 13,
|
|
321
|
-
fontWeight: "700",
|
|
322
|
-
letterSpacing: 0.5
|
|
323
|
-
},
|
|
324
|
-
// Centered rather than left-aligned like a normal row - see this row's own render-site comment
|
|
325
|
-
// for why (a footer action, not another selectable identity).
|
|
326
|
-
manageRowInner: {
|
|
327
|
-
alignItems: "center",
|
|
328
|
-
flexDirection: "row",
|
|
329
|
-
gap: 6,
|
|
330
|
-
height: "100%",
|
|
331
|
-
justifyContent: "center"
|
|
332
|
-
},
|
|
333
298
|
menu: {
|
|
334
299
|
borderRadius: 12,
|
|
335
300
|
borderWidth: MENU_BORDER_WIDTH,
|
|
@@ -345,29 +310,13 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
345
310
|
menuContent: {
|
|
346
311
|
padding: LIST_PADDING
|
|
347
312
|
},
|
|
348
|
-
//
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
height: 8,
|
|
352
|
-
width: 8
|
|
353
|
-
},
|
|
354
|
-
row: {
|
|
355
|
-
borderRadius: 8,
|
|
356
|
-
height: ROW_HEIGHT
|
|
357
|
-
},
|
|
358
|
-
rowDisabled: {
|
|
359
|
-
opacity: 0.35
|
|
313
|
+
// With a footer pinned below, its own padding takes the bottom edge (same total height as before).
|
|
314
|
+
menuContentAboveFooter: {
|
|
315
|
+
paddingBottom: 0
|
|
360
316
|
},
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
flex: 1,
|
|
365
|
-
gap: 8,
|
|
366
|
-
paddingHorizontal: ROW_INSET
|
|
367
|
-
},
|
|
368
|
-
rowLabel: {
|
|
369
|
-
flex: 1,
|
|
370
|
-
fontSize: 14
|
|
317
|
+
menuFooter: {
|
|
318
|
+
paddingBottom: LIST_PADDING,
|
|
319
|
+
paddingHorizontal: LIST_PADDING
|
|
371
320
|
},
|
|
372
321
|
swatch: {
|
|
373
322
|
alignItems: "center",
|
|
@@ -380,6 +329,9 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
380
329
|
borderColor: "#ffffff",
|
|
381
330
|
borderWidth: 2
|
|
382
331
|
},
|
|
332
|
+
swatchTaken: {
|
|
333
|
+
opacity: 0.35
|
|
334
|
+
},
|
|
383
335
|
swatches: {
|
|
384
336
|
columnGap: GRID_GAP,
|
|
385
337
|
flexDirection: "row",
|
|
@@ -406,15 +358,128 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
406
358
|
}
|
|
407
359
|
});
|
|
408
360
|
|
|
409
|
-
// 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
|
|
410
399
|
var import_auto_paper3 = require("@rific/auto-paper");
|
|
411
400
|
var import_feedback_press2 = require("@rific/feedback-press");
|
|
412
|
-
var import_focus_chain = require("@rific/focus-chain");
|
|
413
|
-
var import_toaster = require("@rific/toaster");
|
|
414
|
-
var import_hud2 = require("@tastic/hud");
|
|
415
401
|
var import_react3 = require("react");
|
|
416
402
|
var import_react_native3 = require("react-native");
|
|
417
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");
|
|
418
483
|
var import_react_native_safe_area_context = require("react-native-safe-area-context");
|
|
419
484
|
|
|
420
485
|
// src/profilesValidation.ts
|
|
@@ -450,7 +515,7 @@ function isValidProfile(value) {
|
|
|
450
515
|
}
|
|
451
516
|
|
|
452
517
|
// src/ProfilesManager.tsx
|
|
453
|
-
var
|
|
518
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
454
519
|
var CHIP_SIZE2 = 40;
|
|
455
520
|
function deriveTag(name) {
|
|
456
521
|
const trimmed = name.trim();
|
|
@@ -459,19 +524,19 @@ function deriveTag(name) {
|
|
|
459
524
|
function ProfilesManager({ profiles, defaultColor, onCreate, onSave, onDelete, headerLeft, ref, fg: fgOverride, fgMuted: fgMutedOverride, titleVariant = "headlineSmall", colorPreview: colorPreviewProp, useColorPickerAlign }) {
|
|
460
525
|
const contextColorPreview = useProfileColorPreview();
|
|
461
526
|
const colorPreview = colorPreviewProp ?? contextColorPreview;
|
|
462
|
-
const { dark } = (0,
|
|
527
|
+
const { dark } = (0, import_auto_paper4.useAutoPaperTheme)();
|
|
463
528
|
const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
|
|
464
529
|
const { error: showErrorToast } = (0, import_toaster.useToast)();
|
|
465
530
|
const host = (0, import_hud2.usePopoverHost)();
|
|
466
531
|
const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
|
|
467
532
|
const fgMuted = fgMutedOverride ?? (dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)");
|
|
468
|
-
const [editingId, setEditingId] = (0,
|
|
469
|
-
const [draftName, setDraftName] = (0,
|
|
470
|
-
const [draftColor, setDraftColor] = (0,
|
|
471
|
-
const [draftTag, setDraftTag] = (0,
|
|
472
|
-
const [tagManuallySet, setTagManuallySet] = (0,
|
|
473
|
-
const [confirmDeleteId, setConfirmDeleteId] = (0,
|
|
474
|
-
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)(() => {
|
|
475
540
|
const name = draftName.trim();
|
|
476
541
|
if (editingId && name) {
|
|
477
542
|
const tagValid = isValidTag(draftTag);
|
|
@@ -482,13 +547,13 @@ function ProfilesManager({ profiles, defaultColor, onCreate, onSave, onDelete, h
|
|
|
482
547
|
}
|
|
483
548
|
setEditingId(null);
|
|
484
549
|
}, [editingId, draftName, draftColor, draftTag, onCreate, onSave, showErrorToast]);
|
|
485
|
-
const commitEditRef = (0,
|
|
486
|
-
(0,
|
|
550
|
+
const commitEditRef = (0, import_react4.useRef)(commitEdit);
|
|
551
|
+
(0, import_react4.useEffect)(() => {
|
|
487
552
|
commitEditRef.current = commitEdit;
|
|
488
553
|
});
|
|
489
|
-
(0,
|
|
490
|
-
(0,
|
|
491
|
-
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)(
|
|
492
557
|
(target) => {
|
|
493
558
|
commitEdit();
|
|
494
559
|
if (target === "new") {
|
|
@@ -506,79 +571,79 @@ function ProfilesManager({ profiles, defaultColor, onCreate, onSave, onDelete, h
|
|
|
506
571
|
},
|
|
507
572
|
[commitEdit, defaultColor]
|
|
508
573
|
);
|
|
509
|
-
const handleNameChange = (0,
|
|
574
|
+
const handleNameChange = (0, import_react4.useCallback)(
|
|
510
575
|
(name) => {
|
|
511
576
|
setDraftName(name);
|
|
512
577
|
if (!tagManuallySet) setDraftTag(deriveTag(name));
|
|
513
578
|
},
|
|
514
579
|
[tagManuallySet]
|
|
515
580
|
);
|
|
516
|
-
const handleTagChange = (0,
|
|
581
|
+
const handleTagChange = (0, import_react4.useCallback)((tag) => {
|
|
517
582
|
setDraftTag((previous) => clampTag(previous, tag));
|
|
518
583
|
setTagManuallySet(true);
|
|
519
584
|
}, []);
|
|
520
585
|
const confirmDeleteProfile = profiles.find((p) => p.id === confirmDeleteId) ?? null;
|
|
521
|
-
const handleConfirmDelete = (0,
|
|
586
|
+
const handleConfirmDelete = (0, import_react4.useCallback)(() => {
|
|
522
587
|
if (confirmDeleteId) {
|
|
523
588
|
onDelete(confirmDeleteId);
|
|
524
589
|
if (editingId === confirmDeleteId) setEditingId(null);
|
|
525
590
|
}
|
|
526
591
|
setConfirmDeleteId(null);
|
|
527
592
|
}, [confirmDeleteId, editingId, onDelete]);
|
|
528
|
-
const sortedProfiles = (0,
|
|
593
|
+
const sortedProfiles = (0, import_react4.useMemo)(() => [...profiles].sort((a, b) => a.name.localeCompare(b.name)), [profiles]);
|
|
529
594
|
const rows = [...sortedProfiles.map((profile) => ({ kind: "profile", profile })), { kind: "new" }];
|
|
530
|
-
return /* @__PURE__ */ (0,
|
|
531
|
-
/* @__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: [
|
|
532
597
|
headerLeft,
|
|
533
|
-
/* @__PURE__ */ (0,
|
|
598
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Text, { variant: titleVariant, style: [styles4.title, { color: fg }], children: "Profiles" })
|
|
534
599
|
] }),
|
|
535
|
-
/* @__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) => {
|
|
536
601
|
if (row.kind === "new") {
|
|
537
602
|
if (editingId !== "new") {
|
|
538
|
-
return /* @__PURE__ */ (0,
|
|
539
|
-
/* @__PURE__ */ (0,
|
|
540
|
-
/* @__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" })
|
|
541
606
|
] }) }, "new");
|
|
542
607
|
}
|
|
543
|
-
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");
|
|
544
609
|
}
|
|
545
610
|
const { profile } = row;
|
|
546
611
|
if (editingId === profile.id) {
|
|
547
|
-
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);
|
|
548
613
|
}
|
|
549
|
-
return /* @__PURE__ */ (0,
|
|
550
|
-
/* @__PURE__ */ (0,
|
|
551
|
-
/* @__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 })
|
|
552
617
|
] }) }, profile.id);
|
|
553
618
|
}) }) }),
|
|
554
|
-
/* @__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) })
|
|
555
620
|
] });
|
|
556
621
|
}
|
|
557
622
|
function AlignedColorPicker({ useAlign, ...props }) {
|
|
558
|
-
const { width: windowWidth } = (0,
|
|
559
|
-
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);
|
|
560
625
|
const alignOverride = useAlign(props.host.openId === props.id, width, height);
|
|
561
|
-
return /* @__PURE__ */ (0,
|
|
626
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_hud2.InlineColorPicker, { ...props, alignOverride });
|
|
562
627
|
}
|
|
563
628
|
function EditRow({ draftName, onNameChange, draftColor, onColorChange, draftTag, onTagChange, onSubmit, onDelete, autoFocus, fgMuted, host, dark, colorPreview, useColorPickerAlign }) {
|
|
564
629
|
const register = (0, import_focus_chain.useFocusChain)();
|
|
565
630
|
const tag = register();
|
|
566
631
|
const name = register();
|
|
567
|
-
const tagFocusRef = (0,
|
|
568
|
-
(0,
|
|
632
|
+
const tagFocusRef = (0, import_react4.useRef)(tag.props.focus);
|
|
633
|
+
(0, import_react4.useEffect)(() => {
|
|
569
634
|
tagFocusRef.current = tag.props.focus;
|
|
570
635
|
});
|
|
571
|
-
(0,
|
|
636
|
+
(0, import_react4.useEffect)(() => {
|
|
572
637
|
if (host.openId === "color") tagFocusRef.current();
|
|
573
638
|
}, [host.openId]);
|
|
574
|
-
return /* @__PURE__ */ (0,
|
|
575
|
-
useColorPickerAlign ? /* @__PURE__ */ (0,
|
|
576
|
-
/* @__PURE__ */ (0,
|
|
577
|
-
/* @__PURE__ */ (0,
|
|
578
|
-
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 }) })
|
|
579
644
|
] });
|
|
580
645
|
}
|
|
581
|
-
var
|
|
646
|
+
var styles4 = import_react_native4.StyleSheet.create({
|
|
582
647
|
content: {
|
|
583
648
|
gap: 4,
|
|
584
649
|
paddingHorizontal: 20
|
|
@@ -657,23 +722,23 @@ var styles3 = import_react_native3.StyleSheet.create({
|
|
|
657
722
|
});
|
|
658
723
|
|
|
659
724
|
// src/ProfilesScreen.tsx
|
|
660
|
-
var
|
|
661
|
-
var
|
|
662
|
-
var
|
|
663
|
-
var
|
|
664
|
-
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");
|
|
665
730
|
function ProfilesScreen({ profiles, defaultColor, onCreate, onSave, onDelete, onBack, fg: fgOverride, fgMuted, bg: bgOverride, titleVariant, colorPreview, useColorPickerAlign }) {
|
|
666
|
-
const { dark } = (0,
|
|
667
|
-
const managerRef = (0,
|
|
731
|
+
const { dark } = (0, import_auto_paper5.useAutoPaperTheme)();
|
|
732
|
+
const managerRef = (0, import_react5.useRef)(null);
|
|
668
733
|
const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
|
|
669
734
|
const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
|
|
670
735
|
const handleBack = () => {
|
|
671
736
|
managerRef.current?.commitPendingEdit();
|
|
672
737
|
onBack();
|
|
673
738
|
};
|
|
674
|
-
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" }) }) });
|
|
675
740
|
}
|
|
676
|
-
var
|
|
741
|
+
var styles5 = import_react_native5.StyleSheet.create({
|
|
677
742
|
container: {
|
|
678
743
|
flex: 1
|
|
679
744
|
}
|
|
@@ -837,36 +902,67 @@ async function resolveInitialProfiles(groupId, localFallback) {
|
|
|
837
902
|
|
|
838
903
|
// src/redux/seatColorsSlice.ts
|
|
839
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
|
+
}
|
|
840
912
|
function createSeatColorsSlice(namespace, defaultState, mountKey = "seatColors") {
|
|
841
913
|
const setLastCpuColor = createActionCreator(`seatColors/${namespace}/setLastCpuColor`);
|
|
842
914
|
const setLastGuestColor = createActionCreator(`seatColors/${namespace}/setLastGuestColor`);
|
|
843
|
-
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
|
+
}
|
|
844
922
|
function reducer(state = defaultState, action) {
|
|
845
923
|
if (action.type === REHYDRATE2) {
|
|
846
924
|
const persisted = action.payload?.[mountKey];
|
|
847
|
-
|
|
925
|
+
const next = { ...defaultState, ...state, ...persisted };
|
|
926
|
+
delete next.profileOverride;
|
|
927
|
+
return next;
|
|
848
928
|
}
|
|
849
929
|
if (setLastCpuColor.match(action)) return { ...state, lastCpuColor: action.payload };
|
|
850
930
|
if (setLastGuestColor.match(action)) return { ...state, lastGuestColor: { ...state.lastGuestColor, [action.payload.seat]: action.payload.color } };
|
|
851
|
-
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
|
+
}
|
|
852
948
|
return state;
|
|
853
949
|
}
|
|
854
|
-
return { actions: { setLastCpuColor, setLastGuestColor,
|
|
950
|
+
return { actions: { setLastCpuColor, setLastGuestColor, setProfileColor }, reducer };
|
|
855
951
|
}
|
|
856
952
|
|
|
857
953
|
// src/redux/useSharedProfilesSync.ts
|
|
858
|
-
var
|
|
859
|
-
var
|
|
954
|
+
var import_react6 = require("react");
|
|
955
|
+
var import_react_native6 = require("react-native");
|
|
860
956
|
function useSharedProfilesSync({ groupId, onRemoteChange }) {
|
|
861
|
-
const pendingWriteRef = (0,
|
|
862
|
-
const onRemoteChangeRef = (0,
|
|
863
|
-
(0,
|
|
957
|
+
const pendingWriteRef = (0, import_react6.useRef)(false);
|
|
958
|
+
const onRemoteChangeRef = (0, import_react6.useRef)(onRemoteChange);
|
|
959
|
+
(0, import_react6.useEffect)(() => {
|
|
864
960
|
onRemoteChangeRef.current = onRemoteChange;
|
|
865
961
|
}, [onRemoteChange]);
|
|
866
|
-
(0,
|
|
962
|
+
(0, import_react6.useEffect)(() => {
|
|
867
963
|
if (!isSharedProfileStoreAvailable) return;
|
|
868
964
|
let cancelled = false;
|
|
869
|
-
const sub =
|
|
965
|
+
const sub = import_react_native6.AppState.addEventListener("change", (next) => {
|
|
870
966
|
if (next !== "active" || pendingWriteRef.current) return;
|
|
871
967
|
readSharedProfiles(groupId).then((shared) => {
|
|
872
968
|
if (!cancelled && shared !== null) onRemoteChangeRef.current(shared);
|
|
@@ -877,7 +973,7 @@ function useSharedProfilesSync({ groupId, onRemoteChange }) {
|
|
|
877
973
|
sub.remove();
|
|
878
974
|
};
|
|
879
975
|
}, [groupId]);
|
|
880
|
-
const syncToShared = (0,
|
|
976
|
+
const syncToShared = (0, import_react6.useCallback)(
|
|
881
977
|
(next) => {
|
|
882
978
|
if (!isSharedProfileStoreAvailable) return;
|
|
883
979
|
pendingWriteRef.current = true;
|
|
@@ -901,6 +997,7 @@ function avoidSeatColorClash(p1Color, p2Color, defaults) {
|
|
|
901
997
|
0 && (module.exports = {
|
|
902
998
|
MAX_PROFILE_NAME_LENGTH,
|
|
903
999
|
MAX_TAG_LENGTH,
|
|
1000
|
+
OptionPicker,
|
|
904
1001
|
ProfileChip,
|
|
905
1002
|
ProfileColorProvider,
|
|
906
1003
|
ProfilePicker,
|
|
@@ -911,11 +1008,13 @@ function avoidSeatColorClash(p1Color, p2Color, defaults) {
|
|
|
911
1008
|
createProfileRecord,
|
|
912
1009
|
createProfileSelectionSlice,
|
|
913
1010
|
createSeatColorsSlice,
|
|
1011
|
+
getOptionPickerContentSize,
|
|
914
1012
|
getProfilePickerContentSize,
|
|
915
1013
|
isSharedProfileStoreAvailable,
|
|
916
1014
|
isValidProfile,
|
|
917
1015
|
isValidTag,
|
|
918
1016
|
loadSharedProfiles,
|
|
1017
|
+
profileSeatColor,
|
|
919
1018
|
profilesActions,
|
|
920
1019
|
profilesReducer,
|
|
921
1020
|
readSharedProfiles,
|