@tastic/profile 0.14.1 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -49,7 +49,9 @@ see its own doc comment for why that component is generic over your own `Profile
49
49
  - **`ProfilePicker`**: a name trigger + selection popover: pick an existing profile, fall back to a
50
50
  null/"guest" selection, or (if `onManage` is passed) navigate to a management screen. Selection
51
51
  only - creating, renaming, and deleting all live in `ProfilesManager`. Generic over your own
52
- `Profile` type (see above). Placement props (all optional, see "Fake-rotated frames" below):
52
+ `Profile` type (see above). `takenId` disables one other seat's profile in the list; `takenIds`
53
+ (an array) disables several, for a lobby with more than two seats, and never disables the
54
+ picker's own selection, so you can pass every seated id. Placement props (all optional, see "Fake-rotated frames" below):
53
55
  `align` (force a horizontal side), `alignOverride` (substitute the whole placement result), and
54
56
  `rotation` (forwarded to the automatic measurement). `colorSection`
55
57
  (`{ value, onChange, previewValue?, swatches?, label?, caption? }`) puts a Color row at the top of
@@ -72,7 +74,7 @@ see its own doc comment for why that component is generic over your own `Profile
72
74
  `profiles`/`defaultColor`/`onCreate`/`onSave`/`onDelete` as `ProfilesManager` itself, plus
73
75
  `onBack`. Owns its own `ProfilesManagerHandle` ref internally - there's no `ref` prop here, since
74
76
  nothing outside it needs one anymore.
75
- - **`readSharedProfiles` / `loadSharedProfiles` / `saveSharedProfiles` / `isSharedProfileStoreAvailable`**: an *optional*
77
+ - **`readSharedProfiles` / `loadSharedProfiles` / `saveSharedProfiles` / `subscribeSharedProfiles` / `isSharedProfileStoreAvailable`**: an *optional*
76
78
  cross-app roster, shared between multiple apps of yours via a native iOS App Group (same Apple
77
79
  Developer Team, same `"com.apple.security.application-groups"` entitlement value on every
78
80
  participating app). This only ever carries the base `Profile` shape above - a host app's own
@@ -103,9 +105,17 @@ see its own doc comment for why that component is generic over your own `Profile
103
105
  result can't replace a roster or lead to a write.
104
106
 
105
107
  Backed by a small native Expo Module (`ios/TasticProfileModule.swift`) wrapping
106
- `UserDefaults(suiteName:)` - iOS only (see `expo-module.config.json`'s `"apple"`-only platform
107
- list); `isSharedProfileStoreAvailable` is `false` on Android/web and on any iOS build that hasn't
108
- run `expo prebuild` since adding this App Group's entitlement, so a host app always needs its own
108
+ `UserDefaults(suiteName:)` on iOS (see `expo-module.config.json`'s `"apple"`-only platform list),
109
+ and on the web by `localStorage`, under the key `<groupId>:sharedProfiles`: games served from one
110
+ origin (for example `games.example.com/<game>/`) share it the way apps share an App Group, while
111
+ games on different origins can't see each other's. The web store writes and removes a probe key
112
+ once at load and stays unavailable if that fails (storage blocked), and after a write that fails
113
+ anyway, reads fail until a write succeeds, so an older roster can't undo a local change.
114
+ `subscribeSharedProfiles(groupId, listener)` hands `listener` the roster another tab or game on
115
+ the same origin has just saved (the browser's `storage` event); it does nothing on native.
116
+ `useSharedProfilesSync` subscribes for you. `isSharedProfileStoreAvailable` is `false` on
117
+ Android, on a web page that can't write `localStorage`, and on any iOS build that hasn't run
118
+ `expo prebuild` since adding this App Group's entitlement, so a host app always needs its own
109
119
  local-storage fallback path regardless of platform. Requires the App Group itself to be declared
110
120
  in each consuming app's own Expo config, e.g.:
111
121
 
@@ -278,7 +288,7 @@ so a host app plugs the reducer(s) into whatever store it already has:
278
288
  Always local, like the guest/CPU/override colors below, and never part of the shared
279
289
  App Group roster, since who's selected on *this* device is naturally per-app, per-device state.
280
290
 
281
- ## Muted profile colors (`ProfileColorProvider`)
291
+ ## Muted profile colors and drawn swatches (`ProfileColorProvider`)
282
292
 
283
293
  An app that draws profile colors through a transform (Solitaire blends them toward its muted
284
294
  card-back palette) wraps its tree once:
@@ -298,6 +308,26 @@ for free. Only what's drawn changes: saved colors, `onCreate`/`onSave` values an
298
308
  untouched. `useProfileColorPreview()` returns the provider's function (or `undefined`), and
299
309
  `useProfileDisplayColor(hex)` resolves one color. Without a provider nothing changes.
300
310
 
311
+ `renderSwatch` (also optional, with or without `preview`) draws the fill of every round swatch this
312
+ package draws, in place of the flat color: `ProfileChip`, the pickers' chip trigger, the Color row's
313
+ swatch and the color page's swatches. It's called as `renderSwatch(color, size)` with the drawn
314
+ color (after `preview`) and the circle's diameter, and its drawing is clipped to the circle, behind
315
+ the tag, icon or check. The tag and check still take their contrast from `color`, so treat it as
316
+ the primary color of whatever you draw. Hangman draws a pie of each color's triad:
317
+
318
+ ```tsx
319
+ import { getTriadicPalette } from '@rific/auto-paper'
320
+ import { ProfileColorProvider, type ProfileSwatchRenderer } from '@tastic/profile'
321
+
322
+ const renderSwatch: ProfileSwatchRenderer = (color, size) => <TriadPie colors={getTriadicPalette(color)} size={size} />
323
+ <ProfileColorProvider renderSwatch={renderSwatch}>{children}</ProfileColorProvider>
324
+ ```
325
+
326
+ (`TriadPie` is your own component, e.g. three `react-native-svg` arcs.) Give it a stable identity
327
+ (module level, or `useCallback`). Rows that fill with a color (a selected picker row) stay flat, and
328
+ so do `@tastic/hud`'s `InlineColorPicker` swatches in `ProfilesManager`'s edit row, which don't read
329
+ this provider. `useProfileSwatchRenderer()` returns it (or `undefined`).
330
+
301
331
  ## Per-seat color persistence
302
332
 
303
333
  A loadout/lobby screen's color for a given seat is never just "the selected profile's saved
@@ -362,11 +392,16 @@ Published to the public npm registry via tag-based CI (OIDC trusted publishing -
362
392
  ## Peer dependencies
363
393
 
364
394
  `react`, `react-native`, `react-native-paper`, `react-native-safe-area-context`, `@rific/auto-paper`
365
- (`getContrastColor`, `useAutoPaperTheme`), `@rific/feedback-press` (`TouchableRipple`),
366
- `@rific/focus-chain` (`useFocusChain`), `@rific/toaster` (`useToast`), `@tastic/hud`
367
- (`InlineColorPicker`, `PopoverBody`, `PopoverHost`, `useAutoAlign`, `usePopoverHost`), `@tastic/core`
368
- (a peer of `@tastic/hud` itself) - none of these are bundled, so use whatever versions your app
369
- already has.
395
+ (`defaultColors`, `FadingScrollView`, `getContrastColor`, `useAutoPaperTheme`), `@rific/feedback-press`
396
+ (`TouchableRipple`), `@rific/focus-chain` (`useFocusChain`), `@rific/toaster` (`useToast`),
397
+ `@tastic/hud` >= 0.23.0 (`ConfirmDialog`, `InlineColorPicker`, `PopoverBody`, `useAutoAlign`,
398
+ `usePopoverHost`), `@tastic/core` (a peer of `@tastic/hud` itself) - none of these are bundled, so
399
+ use whatever versions your app already has.
400
+
401
+ This package imports `@tastic/hud` only through its light `@tastic/hud/chrome` entry, never the main
402
+ one (which also loads Skia and `@tastic/split-screen`), so an app with neither, like Hangman, can use
403
+ every component here. That's why it needs hud 0.23.0, the first whose `./chrome` has the popover
404
+ pieces and the color picker.
370
405
 
371
406
  `expo-modules-core` is an *optional* peer - only resolved by `loadSharedProfiles`/`saveSharedProfiles`
372
407
  for the native App Group bridge described above; safe to omit entirely on an Android/web-only
package/dist/index.d.mts CHANGED
@@ -1,8 +1,54 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, RefObject, Ref } from 'react';
3
- import { SeedColor } from '@rific/auto-paper';
4
- import { PopoverHost, PopoverRotation } from '@tastic/hud';
2
+ import { RefObject, ReactNode, Ref } from 'react';
3
+ import { PopoverHost, PopoverRotation } from '@tastic/hud/chrome';
5
4
  import { View, StyleProp, ViewStyle } from 'react-native';
5
+ import { SeedColor } from '@rific/auto-paper';
6
+
7
+ interface ProfilePickerColorSection {
8
+ value: string;
9
+ onChange: (hex: string) => void;
10
+ previewValue?: (hex: string) => string;
11
+ swatches?: SeedColor[];
12
+ label?: string;
13
+ caption?: string;
14
+ takenValue?: string;
15
+ allowSwapTaken?: boolean;
16
+ }
17
+ interface ProfilePickerAlignResult {
18
+ align: 'left' | 'right' | 'center';
19
+ verticalAlign: 'below' | 'above';
20
+ maxHeight: number;
21
+ measured: boolean;
22
+ triggerRef: RefObject<View | null>;
23
+ }
24
+ interface ProfilePickerContentSize {
25
+ width: number;
26
+ height: number;
27
+ }
28
+
29
+ interface OptionPickerOption<T extends string> {
30
+ value: T;
31
+ label: string;
32
+ icon?: string;
33
+ }
34
+ declare function getOptionPickerContentSize(optionCount: number, colorSection?: Pick<ProfilePickerColorSection, 'swatches' | 'caption'>): ProfilePickerContentSize;
35
+ interface OptionPickerProps<T extends string> {
36
+ id: string;
37
+ host: PopoverHost;
38
+ options: OptionPickerOption<T>[];
39
+ value: T;
40
+ onChange: (value: T) => void;
41
+ color: string;
42
+ dark: boolean;
43
+ icon: string;
44
+ rowIcon?: string;
45
+ colorSection?: ProfilePickerColorSection;
46
+ align?: 'left' | 'right' | 'center';
47
+ alignOverride?: ProfilePickerAlignResult;
48
+ rotation?: PopoverRotation;
49
+ triggerStyle?: StyleProp<ViewStyle>;
50
+ }
51
+ declare function OptionPicker<T extends string>({ id, host, options, value, onChange, color, dark, icon, rowIcon, colorSection, align, alignOverride, rotation, triggerStyle }: OptionPickerProps<T>): react.JSX.Element;
6
52
 
7
53
  interface Profile {
8
54
  id: string;
@@ -20,33 +66,17 @@ interface Props {
20
66
  }
21
67
  declare function ProfileChip({ profile, size, filled }: Props): react.JSX.Element;
22
68
 
69
+ type ProfileSwatchRenderer = (color: string, size: number) => ReactNode;
23
70
  interface ProfileColorProviderProps {
24
- preview: (hex: string) => string;
71
+ preview?: (hex: string) => string;
72
+ renderSwatch?: ProfileSwatchRenderer;
25
73
  children: ReactNode;
26
74
  }
27
- declare function ProfileColorProvider({ preview, children }: ProfileColorProviderProps): react.JSX.Element;
75
+ declare function ProfileColorProvider({ preview, renderSwatch, children }: ProfileColorProviderProps): react.JSX.Element;
28
76
  declare function useProfileColorPreview(): ((hex: string) => string) | undefined;
77
+ declare function useProfileSwatchRenderer(): ProfileSwatchRenderer | undefined;
29
78
  declare function useProfileDisplayColor(hex: string): string;
30
79
 
31
- interface ProfilePickerColorSection {
32
- value: string;
33
- onChange: (hex: string) => void;
34
- previewValue?: (hex: string) => string;
35
- swatches?: SeedColor[];
36
- label?: string;
37
- caption?: string;
38
- }
39
- interface ProfilePickerAlignResult {
40
- align: 'left' | 'right' | 'center';
41
- verticalAlign: 'below' | 'above';
42
- maxHeight: number;
43
- measured: boolean;
44
- triggerRef: RefObject<View | null>;
45
- }
46
- interface ProfilePickerContentSize {
47
- width: number;
48
- height: number;
49
- }
50
80
  declare function getProfilePickerContentSize(profileCount: number, hasManageRow?: boolean, colorSection?: Pick<ProfilePickerColorSection, 'swatches' | 'caption'>): ProfilePickerContentSize;
51
81
  interface ProfilePickerProps<P extends Profile> {
52
82
  idPrefix: string;
@@ -54,6 +84,7 @@ interface ProfilePickerProps<P extends Profile> {
54
84
  profiles: P[];
55
85
  selectedId: string | null;
56
86
  takenId?: string | null;
87
+ takenIds?: readonly string[];
57
88
  color: string;
58
89
  dark: boolean;
59
90
  align?: 'left' | 'right' | 'center';
@@ -67,7 +98,7 @@ interface ProfilePickerProps<P extends Profile> {
67
98
  colorSection?: ProfilePickerColorSection;
68
99
  triggerStyle?: StyleProp<ViewStyle>;
69
100
  }
70
- declare function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, selectedId, takenId, color, dark, align: forcedAlign, alignOverride, rotation, guestLabel, nullLabel, nullIcon, onSelect, onManage, colorSection, triggerStyle }: ProfilePickerProps<P>): react.JSX.Element;
101
+ declare function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, selectedId, takenId, takenIds, color, dark, align, alignOverride, rotation, guestLabel, nullLabel, nullIcon, onSelect, onManage, colorSection, triggerStyle }: ProfilePickerProps<P>): react.JSX.Element;
71
102
 
72
103
  type MD3TextVariant$1 = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'labelLarge' | 'labelMedium' | 'labelSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall';
73
104
  interface ProfileEditPatch {
@@ -189,19 +220,23 @@ interface SetLastGuestColorPayload<TSeat> {
189
220
  color: string;
190
221
  seat: TSeat;
191
222
  }
192
- interface SetProfileOverridePayload<TSeat> {
223
+ interface ProfileColorPick {
224
+ color: string;
225
+ profileColor: string;
226
+ }
227
+ interface SetProfileColorPayload {
228
+ profile: Pick<Profile, 'id' | 'color'>;
193
229
  color: string | null;
194
- seat: TSeat;
195
230
  }
196
231
  interface SeatColorsActions<TSeat> {
197
232
  setLastCpuColor: ActionCreator<string>;
198
233
  setLastGuestColor: ActionCreator<SetLastGuestColorPayload<TSeat>>;
199
- setProfileOverride: ActionCreator<SetProfileOverridePayload<TSeat>>;
234
+ setProfileColor: ActionCreator<SetProfileColorPayload>;
200
235
  }
201
236
  type SeatColorsState<TSeat extends string | number> = {
202
237
  lastCpuColor: string;
203
238
  lastGuestColor: Record<TSeat, string>;
204
- profileOverride: Record<TSeat, string | null>;
239
+ profileColors: Record<string, ProfileColorPick>;
205
240
  };
206
241
  interface SeatColorsSlice<TSeat extends string | number> {
207
242
  actions: SeatColorsActions<TSeat>;
@@ -210,6 +245,7 @@ interface SeatColorsSlice<TSeat extends string | number> {
210
245
  payload?: unknown;
211
246
  }) => SeatColorsState<TSeat>;
212
247
  }
248
+ declare function profileSeatColor(profile: Pick<Profile, 'id' | 'color'>, profileColors: Record<string, ProfileColorPick>): string;
213
249
  declare function createSeatColorsSlice<TSeat extends string | number>(namespace: string, defaultState: SeatColorsState<TSeat>, mountKey?: string): SeatColorsSlice<TSeat>;
214
250
 
215
251
  interface UseSharedProfilesSyncOptions {
@@ -227,5 +263,6 @@ declare const isSharedProfileStoreAvailable: boolean;
227
263
  declare function readSharedProfiles(groupId: string): Promise<Profile[] | null>;
228
264
  declare function loadSharedProfiles(groupId: string): Promise<Profile[]>;
229
265
  declare function saveSharedProfiles(groupId: string, profiles: Profile[]): Promise<void>;
266
+ declare function subscribeSharedProfiles(groupId: string, listener: (profiles: Profile[]) => void): () => void;
230
267
 
231
- export { type CreateProfileInput, MAX_PROFILE_NAME_LENGTH, MAX_TAG_LENGTH, type Profile, ProfileChip, ProfileColorProvider, type ProfileEditPatch, type ProfileExtensionActions, type ProfileExtensionSlice, type ProfileExtensionState, ProfilePicker, type ProfilePickerAlignResult, type ProfilePickerColorSection, type ProfilePickerContentSize, type ProfileSelectionActions, type ProfileSelectionSlice, type ProfileSelectionState, ProfilesManager, type ProfilesManagerHandle, type ProfilesManagerProps, ProfilesScreen, type ProfilesScreenProps, type SeatColorsActions, type SeatColorsSlice, type SeatColorsState, type SelectProfilePayload, type SetLastGuestColorPayload, type SetProfileExtensionPayload, type SetProfileOverridePayload, type UpdateProfilePayload, type UseSharedProfilesSyncOptions, type UseSharedProfilesSyncResult, avoidSeatColorClash, createProfileExtensionSlice, createProfileRecord, createProfileSelectionSlice, createSeatColorsSlice, getProfilePickerContentSize, isSharedProfileStoreAvailable, isValidProfile, isValidTag, loadSharedProfiles, profilesActions, profilesReducer, readSharedProfiles, resolveInitialProfiles, saveSharedProfiles, useProfileColorPreview, useProfileDisplayColor, useSharedProfilesSync };
268
+ export { type CreateProfileInput, MAX_PROFILE_NAME_LENGTH, MAX_TAG_LENGTH, OptionPicker, type OptionPickerOption, type Profile, ProfileChip, type ProfileColorPick, ProfileColorProvider, type ProfileEditPatch, type ProfileExtensionActions, type ProfileExtensionSlice, type ProfileExtensionState, ProfilePicker, type ProfilePickerAlignResult, type ProfilePickerColorSection, type ProfilePickerContentSize, type ProfileSelectionActions, type ProfileSelectionSlice, type ProfileSelectionState, type ProfileSwatchRenderer, ProfilesManager, type ProfilesManagerHandle, type ProfilesManagerProps, ProfilesScreen, type ProfilesScreenProps, type SeatColorsActions, type SeatColorsSlice, type SeatColorsState, type SelectProfilePayload, type SetLastGuestColorPayload, type SetProfileColorPayload, type SetProfileExtensionPayload, type UpdateProfilePayload, type UseSharedProfilesSyncOptions, type UseSharedProfilesSyncResult, avoidSeatColorClash, createProfileExtensionSlice, createProfileRecord, createProfileSelectionSlice, createSeatColorsSlice, getOptionPickerContentSize, getProfilePickerContentSize, isSharedProfileStoreAvailable, isValidProfile, isValidTag, loadSharedProfiles, profileSeatColor, profilesActions, profilesReducer, readSharedProfiles, resolveInitialProfiles, saveSharedProfiles, subscribeSharedProfiles, useProfileColorPreview, useProfileDisplayColor, useProfileSwatchRenderer, useSharedProfilesSync };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,54 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, RefObject, Ref } from 'react';
3
- import { SeedColor } from '@rific/auto-paper';
4
- import { PopoverHost, PopoverRotation } from '@tastic/hud';
2
+ import { RefObject, ReactNode, Ref } from 'react';
3
+ import { PopoverHost, PopoverRotation } from '@tastic/hud/chrome';
5
4
  import { View, StyleProp, ViewStyle } from 'react-native';
5
+ import { SeedColor } from '@rific/auto-paper';
6
+
7
+ interface ProfilePickerColorSection {
8
+ value: string;
9
+ onChange: (hex: string) => void;
10
+ previewValue?: (hex: string) => string;
11
+ swatches?: SeedColor[];
12
+ label?: string;
13
+ caption?: string;
14
+ takenValue?: string;
15
+ allowSwapTaken?: boolean;
16
+ }
17
+ interface ProfilePickerAlignResult {
18
+ align: 'left' | 'right' | 'center';
19
+ verticalAlign: 'below' | 'above';
20
+ maxHeight: number;
21
+ measured: boolean;
22
+ triggerRef: RefObject<View | null>;
23
+ }
24
+ interface ProfilePickerContentSize {
25
+ width: number;
26
+ height: number;
27
+ }
28
+
29
+ interface OptionPickerOption<T extends string> {
30
+ value: T;
31
+ label: string;
32
+ icon?: string;
33
+ }
34
+ declare function getOptionPickerContentSize(optionCount: number, colorSection?: Pick<ProfilePickerColorSection, 'swatches' | 'caption'>): ProfilePickerContentSize;
35
+ interface OptionPickerProps<T extends string> {
36
+ id: string;
37
+ host: PopoverHost;
38
+ options: OptionPickerOption<T>[];
39
+ value: T;
40
+ onChange: (value: T) => void;
41
+ color: string;
42
+ dark: boolean;
43
+ icon: string;
44
+ rowIcon?: string;
45
+ colorSection?: ProfilePickerColorSection;
46
+ align?: 'left' | 'right' | 'center';
47
+ alignOverride?: ProfilePickerAlignResult;
48
+ rotation?: PopoverRotation;
49
+ triggerStyle?: StyleProp<ViewStyle>;
50
+ }
51
+ declare function OptionPicker<T extends string>({ id, host, options, value, onChange, color, dark, icon, rowIcon, colorSection, align, alignOverride, rotation, triggerStyle }: OptionPickerProps<T>): react.JSX.Element;
6
52
 
7
53
  interface Profile {
8
54
  id: string;
@@ -20,33 +66,17 @@ interface Props {
20
66
  }
21
67
  declare function ProfileChip({ profile, size, filled }: Props): react.JSX.Element;
22
68
 
69
+ type ProfileSwatchRenderer = (color: string, size: number) => ReactNode;
23
70
  interface ProfileColorProviderProps {
24
- preview: (hex: string) => string;
71
+ preview?: (hex: string) => string;
72
+ renderSwatch?: ProfileSwatchRenderer;
25
73
  children: ReactNode;
26
74
  }
27
- declare function ProfileColorProvider({ preview, children }: ProfileColorProviderProps): react.JSX.Element;
75
+ declare function ProfileColorProvider({ preview, renderSwatch, children }: ProfileColorProviderProps): react.JSX.Element;
28
76
  declare function useProfileColorPreview(): ((hex: string) => string) | undefined;
77
+ declare function useProfileSwatchRenderer(): ProfileSwatchRenderer | undefined;
29
78
  declare function useProfileDisplayColor(hex: string): string;
30
79
 
31
- interface ProfilePickerColorSection {
32
- value: string;
33
- onChange: (hex: string) => void;
34
- previewValue?: (hex: string) => string;
35
- swatches?: SeedColor[];
36
- label?: string;
37
- caption?: string;
38
- }
39
- interface ProfilePickerAlignResult {
40
- align: 'left' | 'right' | 'center';
41
- verticalAlign: 'below' | 'above';
42
- maxHeight: number;
43
- measured: boolean;
44
- triggerRef: RefObject<View | null>;
45
- }
46
- interface ProfilePickerContentSize {
47
- width: number;
48
- height: number;
49
- }
50
80
  declare function getProfilePickerContentSize(profileCount: number, hasManageRow?: boolean, colorSection?: Pick<ProfilePickerColorSection, 'swatches' | 'caption'>): ProfilePickerContentSize;
51
81
  interface ProfilePickerProps<P extends Profile> {
52
82
  idPrefix: string;
@@ -54,6 +84,7 @@ interface ProfilePickerProps<P extends Profile> {
54
84
  profiles: P[];
55
85
  selectedId: string | null;
56
86
  takenId?: string | null;
87
+ takenIds?: readonly string[];
57
88
  color: string;
58
89
  dark: boolean;
59
90
  align?: 'left' | 'right' | 'center';
@@ -67,7 +98,7 @@ interface ProfilePickerProps<P extends Profile> {
67
98
  colorSection?: ProfilePickerColorSection;
68
99
  triggerStyle?: StyleProp<ViewStyle>;
69
100
  }
70
- declare function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, selectedId, takenId, color, dark, align: forcedAlign, alignOverride, rotation, guestLabel, nullLabel, nullIcon, onSelect, onManage, colorSection, triggerStyle }: ProfilePickerProps<P>): react.JSX.Element;
101
+ declare function ProfilePicker<P extends Profile>({ idPrefix, host, profiles, selectedId, takenId, takenIds, color, dark, align, alignOverride, rotation, guestLabel, nullLabel, nullIcon, onSelect, onManage, colorSection, triggerStyle }: ProfilePickerProps<P>): react.JSX.Element;
71
102
 
72
103
  type MD3TextVariant$1 = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'labelLarge' | 'labelMedium' | 'labelSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall';
73
104
  interface ProfileEditPatch {
@@ -189,19 +220,23 @@ interface SetLastGuestColorPayload<TSeat> {
189
220
  color: string;
190
221
  seat: TSeat;
191
222
  }
192
- interface SetProfileOverridePayload<TSeat> {
223
+ interface ProfileColorPick {
224
+ color: string;
225
+ profileColor: string;
226
+ }
227
+ interface SetProfileColorPayload {
228
+ profile: Pick<Profile, 'id' | 'color'>;
193
229
  color: string | null;
194
- seat: TSeat;
195
230
  }
196
231
  interface SeatColorsActions<TSeat> {
197
232
  setLastCpuColor: ActionCreator<string>;
198
233
  setLastGuestColor: ActionCreator<SetLastGuestColorPayload<TSeat>>;
199
- setProfileOverride: ActionCreator<SetProfileOverridePayload<TSeat>>;
234
+ setProfileColor: ActionCreator<SetProfileColorPayload>;
200
235
  }
201
236
  type SeatColorsState<TSeat extends string | number> = {
202
237
  lastCpuColor: string;
203
238
  lastGuestColor: Record<TSeat, string>;
204
- profileOverride: Record<TSeat, string | null>;
239
+ profileColors: Record<string, ProfileColorPick>;
205
240
  };
206
241
  interface SeatColorsSlice<TSeat extends string | number> {
207
242
  actions: SeatColorsActions<TSeat>;
@@ -210,6 +245,7 @@ interface SeatColorsSlice<TSeat extends string | number> {
210
245
  payload?: unknown;
211
246
  }) => SeatColorsState<TSeat>;
212
247
  }
248
+ declare function profileSeatColor(profile: Pick<Profile, 'id' | 'color'>, profileColors: Record<string, ProfileColorPick>): string;
213
249
  declare function createSeatColorsSlice<TSeat extends string | number>(namespace: string, defaultState: SeatColorsState<TSeat>, mountKey?: string): SeatColorsSlice<TSeat>;
214
250
 
215
251
  interface UseSharedProfilesSyncOptions {
@@ -227,5 +263,6 @@ declare const isSharedProfileStoreAvailable: boolean;
227
263
  declare function readSharedProfiles(groupId: string): Promise<Profile[] | null>;
228
264
  declare function loadSharedProfiles(groupId: string): Promise<Profile[]>;
229
265
  declare function saveSharedProfiles(groupId: string, profiles: Profile[]): Promise<void>;
266
+ declare function subscribeSharedProfiles(groupId: string, listener: (profiles: Profile[]) => void): () => void;
230
267
 
231
- export { type CreateProfileInput, MAX_PROFILE_NAME_LENGTH, MAX_TAG_LENGTH, type Profile, ProfileChip, ProfileColorProvider, type ProfileEditPatch, type ProfileExtensionActions, type ProfileExtensionSlice, type ProfileExtensionState, ProfilePicker, type ProfilePickerAlignResult, type ProfilePickerColorSection, type ProfilePickerContentSize, type ProfileSelectionActions, type ProfileSelectionSlice, type ProfileSelectionState, ProfilesManager, type ProfilesManagerHandle, type ProfilesManagerProps, ProfilesScreen, type ProfilesScreenProps, type SeatColorsActions, type SeatColorsSlice, type SeatColorsState, type SelectProfilePayload, type SetLastGuestColorPayload, type SetProfileExtensionPayload, type SetProfileOverridePayload, type UpdateProfilePayload, type UseSharedProfilesSyncOptions, type UseSharedProfilesSyncResult, avoidSeatColorClash, createProfileExtensionSlice, createProfileRecord, createProfileSelectionSlice, createSeatColorsSlice, getProfilePickerContentSize, isSharedProfileStoreAvailable, isValidProfile, isValidTag, loadSharedProfiles, profilesActions, profilesReducer, readSharedProfiles, resolveInitialProfiles, saveSharedProfiles, useProfileColorPreview, useProfileDisplayColor, useSharedProfilesSync };
268
+ export { type CreateProfileInput, MAX_PROFILE_NAME_LENGTH, MAX_TAG_LENGTH, OptionPicker, type OptionPickerOption, type Profile, ProfileChip, type ProfileColorPick, ProfileColorProvider, type ProfileEditPatch, type ProfileExtensionActions, type ProfileExtensionSlice, type ProfileExtensionState, ProfilePicker, type ProfilePickerAlignResult, type ProfilePickerColorSection, type ProfilePickerContentSize, type ProfileSelectionActions, type ProfileSelectionSlice, type ProfileSelectionState, type ProfileSwatchRenderer, ProfilesManager, type ProfilesManagerHandle, type ProfilesManagerProps, ProfilesScreen, type ProfilesScreenProps, type SeatColorsActions, type SeatColorsSlice, type SeatColorsState, type SelectProfilePayload, type SetLastGuestColorPayload, type SetProfileColorPayload, type SetProfileExtensionPayload, type UpdateProfilePayload, type UseSharedProfilesSyncOptions, type UseSharedProfilesSyncResult, avoidSeatColorClash, createProfileExtensionSlice, createProfileRecord, createProfileSelectionSlice, createSeatColorsSlice, getOptionPickerContentSize, getProfilePickerContentSize, isSharedProfileStoreAvailable, isValidProfile, isValidTag, loadSharedProfiles, profileSeatColor, profilesActions, profilesReducer, readSharedProfiles, resolveInitialProfiles, saveSharedProfiles, subscribeSharedProfiles, useProfileColorPreview, useProfileDisplayColor, useProfileSwatchRenderer, useSharedProfilesSync };