@xipkg/calls-store 0.0.13 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +28 -13
- package/dist/index.mjs +79 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -5,15 +5,27 @@ import { Track, VideoQuality } from 'livekit-client';
|
|
|
5
5
|
import { TrackReferenceOrPlaceholder, LocalUserChoices as LocalUserChoices$1 } from '@livekit/components-core';
|
|
6
6
|
import { NoiseCancellationMode } from '@xipkg/calls-types';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/** Стабильный идентификатор участника для закрепления в рамках кабинета */
|
|
9
|
+
type PinnedParticipantT = {
|
|
10
|
+
userId: string;
|
|
10
11
|
source: Track.Source;
|
|
11
12
|
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
declare function
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
/** @deprecated Используйте PinnedParticipantT */
|
|
14
|
+
type PinnedTrackT = PinnedParticipantT;
|
|
15
|
+
declare function getParticipantUserId(participant: {
|
|
16
|
+
identity: string;
|
|
17
|
+
metadata?: string;
|
|
18
|
+
}): string;
|
|
19
|
+
declare function toPinnedParticipant(track: TrackReferenceOrPlaceholder): PinnedParticipantT;
|
|
20
|
+
/** @deprecated Используйте toPinnedParticipant */
|
|
21
|
+
declare const toPinnedTrack: typeof toPinnedParticipant;
|
|
22
|
+
declare function matchesPinnedParticipant(track: TrackReferenceOrPlaceholder, pinned: PinnedParticipantT): boolean;
|
|
23
|
+
/** @deprecated Используйте matchesPinnedParticipant */
|
|
24
|
+
declare const matchesPinnedTrack: typeof matchesPinnedParticipant;
|
|
25
|
+
declare function findPinnedTrackRef(tracks: TrackReferenceOrPlaceholder[], pinned: PinnedParticipantT): TrackReferenceOrPlaceholder | undefined;
|
|
26
|
+
/** Перемещает закреплённых участников в начало списка (порядок pin сохраняется) */
|
|
27
|
+
declare function applyPinsFirst(tracks: TrackReferenceOrPlaceholder[], pins: PinnedParticipantT[]): TrackReferenceOrPlaceholder[];
|
|
28
|
+
declare function applyPinFirst(tracks: TrackReferenceOrPlaceholder[], pinned: PinnedParticipantT | null): TrackReferenceOrPlaceholder[];
|
|
17
29
|
/** Участник для главной плитки focus-сетки (без учёта локального pin) */
|
|
18
30
|
declare function pickDefaultFocusTrack(tracks: TrackReferenceOrPlaceholder[]): TrackReferenceOrPlaceholder | undefined;
|
|
19
31
|
|
|
@@ -48,12 +60,13 @@ type useCallStoreT = {
|
|
|
48
60
|
token: string | undefined;
|
|
49
61
|
raisedHands: RaisedHandT[];
|
|
50
62
|
isHandRaised: boolean;
|
|
51
|
-
/**
|
|
52
|
-
|
|
63
|
+
/** Закреплённые участники по кабинетам (userId + source), порядок = приоритет */
|
|
64
|
+
pinnedByClassroom: Record<string, PinnedParticipantT[]>;
|
|
53
65
|
updateStore: (type: keyof useCallStoreT, value: any) => void;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
togglePinnedParticipant: (pin: PinnedParticipantT, classroomId: string) => void;
|
|
67
|
+
removePinnedParticipant: (pin: PinnedParticipantT, classroomId: string) => void;
|
|
68
|
+
getPinsForClassroom: (classroomId: string) => PinnedParticipantT[];
|
|
69
|
+
isParticipantPinned: (pin: PinnedParticipantT, classroomId: string) => boolean;
|
|
57
70
|
addRaisedHand: (hand: RaisedHandT) => void;
|
|
58
71
|
removeRaisedHand: (participantId: string) => void;
|
|
59
72
|
toggleHandRaised: () => void;
|
|
@@ -73,6 +86,7 @@ declare const useCallStore: zustand.UseBoundStore<Omit<zustand.StoreApi<useCallS
|
|
|
73
86
|
preferredFocusLayout: "horizontal" | "vertical";
|
|
74
87
|
activeCorner: CornerT;
|
|
75
88
|
compactViewMode: CompactViewModeT;
|
|
89
|
+
pinnedByClassroom: Record<string, PinnedParticipantT[]>;
|
|
76
90
|
}>>) => void;
|
|
77
91
|
clearStorage: () => void;
|
|
78
92
|
rehydrate: () => Promise<void> | void;
|
|
@@ -90,6 +104,7 @@ declare const useCallStore: zustand.UseBoundStore<Omit<zustand.StoreApi<useCallS
|
|
|
90
104
|
preferredFocusLayout: "horizontal" | "vertical";
|
|
91
105
|
activeCorner: CornerT;
|
|
92
106
|
compactViewMode: CompactViewModeT;
|
|
107
|
+
pinnedByClassroom: Record<string, PinnedParticipantT[]>;
|
|
93
108
|
}>>;
|
|
94
109
|
};
|
|
95
110
|
}>;
|
|
@@ -237,4 +252,4 @@ interface FocusModeState {
|
|
|
237
252
|
}
|
|
238
253
|
declare const useFocusModeStore: zustand.UseBoundStore<zustand.StoreApi<FocusModeState>>;
|
|
239
254
|
|
|
240
|
-
export { type CompactViewModeT, type CornerT, type PinnedTrackT, type VideoResolution, applyPinFirst, closePermissionsDialog, findPinnedTrackRef, matchesPinnedTrack, openPermissionsDialog, pickDefaultFocusTrack, toPinnedTrack, useCallStore, useFeaturesStore, useFocusModeStore, usePermissionsStore, useSoundEffectsStore, useUserChoicesStore };
|
|
255
|
+
export { type CompactViewModeT, type CornerT, type PinnedParticipantT, type PinnedTrackT, type VideoResolution, applyPinFirst, applyPinsFirst, closePermissionsDialog, findPinnedTrackRef, getParticipantUserId, matchesPinnedParticipant, matchesPinnedTrack, openPermissionsDialog, pickDefaultFocusTrack, toPinnedParticipant, toPinnedTrack, useCallStore, useFeaturesStore, useFocusModeStore, usePermissionsStore, useSoundEffectsStore, useUserChoicesStore };
|
package/dist/index.mjs
CHANGED
|
@@ -31,16 +31,44 @@ var useCallStore = create()(
|
|
|
31
31
|
// Поднятые руки
|
|
32
32
|
raisedHands: [],
|
|
33
33
|
isHandRaised: false,
|
|
34
|
-
|
|
34
|
+
pinnedByClassroom: {},
|
|
35
35
|
updateStore: (type, value) => set({ [type]: value }),
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
36
|
+
togglePinnedParticipant: (pin, classroomId) => set((state) => {
|
|
37
|
+
const current = state.pinnedByClassroom[classroomId] ?? [];
|
|
38
|
+
const existingIndex = current.findIndex(
|
|
39
|
+
(item) => item.userId === pin.userId && item.source === pin.source
|
|
40
|
+
);
|
|
41
|
+
const next = { ...state.pinnedByClassroom };
|
|
42
|
+
if (existingIndex >= 0) {
|
|
43
|
+
const updated = current.filter((_, index) => index !== existingIndex);
|
|
44
|
+
if (updated.length) {
|
|
45
|
+
next[classroomId] = updated;
|
|
46
|
+
} else {
|
|
47
|
+
delete next[classroomId];
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
next[classroomId] = [...current, pin];
|
|
51
|
+
}
|
|
52
|
+
return { pinnedByClassroom: next };
|
|
53
|
+
}),
|
|
54
|
+
removePinnedParticipant: (pin, classroomId) => set((state) => {
|
|
55
|
+
const current = state.pinnedByClassroom[classroomId];
|
|
56
|
+
if (!current?.length) return state;
|
|
57
|
+
const updated = current.filter(
|
|
58
|
+
(item) => !(item.userId === pin.userId && item.source === pin.source)
|
|
59
|
+
);
|
|
60
|
+
const next = { ...state.pinnedByClassroom };
|
|
61
|
+
if (updated.length) {
|
|
62
|
+
next[classroomId] = updated;
|
|
63
|
+
} else {
|
|
64
|
+
delete next[classroomId];
|
|
65
|
+
}
|
|
66
|
+
return { pinnedByClassroom: next };
|
|
39
67
|
}),
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
return
|
|
68
|
+
getPinsForClassroom: (classroomId) => get().pinnedByClassroom[classroomId] ?? [],
|
|
69
|
+
isParticipantPinned: (pin, classroomId) => {
|
|
70
|
+
const pins = get().pinnedByClassroom[classroomId] ?? [];
|
|
71
|
+
return pins.some((item) => item.userId === pin.userId && item.source === pin.source);
|
|
44
72
|
},
|
|
45
73
|
// Поднятые руки
|
|
46
74
|
addRaisedHand: (hand) => set((state) => {
|
|
@@ -68,7 +96,7 @@ var useCallStore = create()(
|
|
|
68
96
|
}),
|
|
69
97
|
{
|
|
70
98
|
name: "call-store",
|
|
71
|
-
version:
|
|
99
|
+
version: 5,
|
|
72
100
|
migrate: (persisted, version) => {
|
|
73
101
|
const state = persisted;
|
|
74
102
|
if (version < 2) {
|
|
@@ -85,6 +113,10 @@ var useCallStore = create()(
|
|
|
85
113
|
const mode = state.compactViewMode;
|
|
86
114
|
state.compactViewMode = mode === "basic" || mode === "expanded" || mode === "audio" ? mode : "basic";
|
|
87
115
|
}
|
|
116
|
+
if (version < 5) {
|
|
117
|
+
state.pinnedByClassroom = typeof state.pinnedByClassroom === "object" && state.pinnedByClassroom !== null ? state.pinnedByClassroom : {};
|
|
118
|
+
delete state.pinnedTrack;
|
|
119
|
+
}
|
|
88
120
|
return state;
|
|
89
121
|
},
|
|
90
122
|
partialize: (state) => ({
|
|
@@ -97,7 +129,8 @@ var useCallStore = create()(
|
|
|
97
129
|
carouselType: state.carouselType,
|
|
98
130
|
preferredFocusLayout: state.preferredFocusLayout,
|
|
99
131
|
activeCorner: state.activeCorner,
|
|
100
|
-
compactViewMode: state.compactViewMode
|
|
132
|
+
compactViewMode: state.compactViewMode,
|
|
133
|
+
pinnedByClassroom: state.pinnedByClassroom
|
|
101
134
|
})
|
|
102
135
|
}
|
|
103
136
|
)
|
|
@@ -170,24 +203,47 @@ var useUserChoicesStore = create()(
|
|
|
170
203
|
}
|
|
171
204
|
)
|
|
172
205
|
);
|
|
173
|
-
function
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
206
|
+
function getParticipantUserId(participant) {
|
|
207
|
+
if (participant.metadata) {
|
|
208
|
+
try {
|
|
209
|
+
const meta = JSON.parse(participant.metadata);
|
|
210
|
+
if (meta?.user_id != null) return String(meta.user_id);
|
|
211
|
+
if (meta?.id != null) return String(meta.id);
|
|
212
|
+
} catch {
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return participant.identity;
|
|
179
216
|
}
|
|
180
|
-
function
|
|
217
|
+
function toPinnedParticipant(track) {
|
|
181
218
|
return {
|
|
182
|
-
|
|
219
|
+
userId: getParticipantUserId(track.participant),
|
|
183
220
|
source: track.source ?? Track.Source.Camera
|
|
184
221
|
};
|
|
185
222
|
}
|
|
223
|
+
var toPinnedTrack = toPinnedParticipant;
|
|
224
|
+
function matchesPinnedParticipant(track, pinned) {
|
|
225
|
+
return getParticipantUserId(track.participant) === pinned.userId && track.source === pinned.source;
|
|
226
|
+
}
|
|
227
|
+
var matchesPinnedTrack = matchesPinnedParticipant;
|
|
228
|
+
function findPinnedTrackRef(tracks, pinned) {
|
|
229
|
+
return tracks.find((track) => matchesPinnedParticipant(track, pinned));
|
|
230
|
+
}
|
|
231
|
+
function applyPinsFirst(tracks, pins) {
|
|
232
|
+
if (!pins.length) return tracks;
|
|
233
|
+
const pinnedRefs = [];
|
|
234
|
+
const seen = /* @__PURE__ */ new Set();
|
|
235
|
+
for (const pin of pins) {
|
|
236
|
+
const ref = findPinnedTrackRef(tracks, pin);
|
|
237
|
+
if (ref && !seen.has(ref)) {
|
|
238
|
+
pinnedRefs.push(ref);
|
|
239
|
+
seen.add(ref);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (!pinnedRefs.length) return tracks;
|
|
243
|
+
return [...pinnedRefs, ...tracks.filter((track) => !seen.has(track))];
|
|
244
|
+
}
|
|
186
245
|
function applyPinFirst(tracks, pinned) {
|
|
187
|
-
|
|
188
|
-
const pinnedRef = findPinnedTrackRef(tracks, pinned);
|
|
189
|
-
if (!pinnedRef) return tracks;
|
|
190
|
-
return [pinnedRef, ...tracks.filter((track) => track !== pinnedRef)];
|
|
246
|
+
return applyPinsFirst(tracks, pinned ? [pinned] : []);
|
|
191
247
|
}
|
|
192
248
|
function pickDefaultFocusTrack(tracks) {
|
|
193
249
|
const screenShare = tracks.find(
|
|
@@ -267,6 +323,6 @@ var useFocusModeStore = create((set) => ({
|
|
|
267
323
|
toggleFocusMode: () => set((state) => ({ focusMode: !state.focusMode }))
|
|
268
324
|
}));
|
|
269
325
|
|
|
270
|
-
export { applyPinFirst, closePermissionsDialog, findPinnedTrackRef, matchesPinnedTrack, openPermissionsDialog, pickDefaultFocusTrack, toPinnedTrack, useCallStore, useFeaturesStore, useFocusModeStore, usePermissionsStore, useSoundEffectsStore, useUserChoicesStore };
|
|
326
|
+
export { applyPinFirst, applyPinsFirst, closePermissionsDialog, findPinnedTrackRef, getParticipantUserId, matchesPinnedParticipant, matchesPinnedTrack, openPermissionsDialog, pickDefaultFocusTrack, toPinnedParticipant, toPinnedTrack, useCallStore, useFeaturesStore, useFocusModeStore, usePermissionsStore, useSoundEffectsStore, useUserChoicesStore };
|
|
271
327
|
//# sourceMappingURL=index.mjs.map
|
|
272
328
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store/callStore.ts","../src/store/permissions.ts","../src/store/userChoices.ts","../src/store/pinnedTrack.ts","../src/store/useSoundEffectsStore.ts","../src/store/featuresStore.ts","../src/store/useFocusModeStore.ts"],"names":["create","persist"],"mappings":"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","file":"index.mjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { LiveKitRoomProps } from '@livekit/components-react';\nimport { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport type { PinnedTrackT } from './pinnedTrack';\n\ntype RaisedHandT = {\n participantId: string;\n participantName: string;\n timestamp: number;\n};\n\nexport type CornerT = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\nexport type CompactViewModeT = 'basic' | 'expanded' | 'audio';\n\ntype useCallStoreT = {\n // разрешение от браузера на использование камеры\n isCameraPermission: boolean | null;\n isMicroPermission: boolean | null;\n // включён ли у пользователя микро\n audioEnabled: boolean;\n videoEnabled: boolean;\n // id-выбранного устройства\n audioDeviceId: ConstrainDOMString | undefined;\n audioOutputDeviceId: ConstrainDOMString | undefined;\n videoDeviceId: ConstrainDOMString | undefined;\n // подключена ли конференция\n connect: LiveKitRoomProps['connect'];\n // началась ли ВКС для пользователя\n isStarted: boolean | undefined;\n // состояние подключения\n isConnecting: boolean;\n\n mode: 'compact' | 'full';\n carouselType: 'grid' | 'horizontal' | 'vertical';\n preferredFocusLayout: 'horizontal' | 'vertical';\n activeCorner: CornerT;\n\n /** Режим вида компакт-ВКС: одна плитка, несколько плиток или только аудио */\n compactViewMode: CompactViewModeT;\n\n // Текущая активная доска (для синхронизации с новыми участниками)\n activeBoardId: string | undefined;\n activeClassroom: string | undefined;\n\n /** Локальный переключатель: пользователь сам ушёл в полную ВКС («Только меня»), комната на сервере остаётся на доске */\n localFullView: boolean;\n\n // токен для конференции\n token: string | undefined;\n\n // Поднятые руки\n raisedHands: RaisedHandT[];\n isHandRaised: boolean;\n\n /** Локально закреплённый участник (только для текущего пользователя) */\n pinnedTrack: PinnedTrackT | null;\n\n updateStore: (type: keyof useCallStoreT, value: any) => void;\n togglePinnedTrack: (track: PinnedTrackT) => void;\n clearPinnedTrack: () => void;\n isTrackPinned: (track: PinnedTrackT) => boolean;\n addRaisedHand: (hand: RaisedHandT) => void;\n removeRaisedHand: (participantId: string) => void;\n toggleHandRaised: () => void;\n clearAllRaisedHands: () => void;\n isHandRaisedByParticipant: (participantId: string) => boolean;\n};\n\nexport const useCallStore = create<useCallStoreT>()(\n persist(\n (set, get) => ({\n isCameraPermission: null,\n isMicroPermission: null,\n audioEnabled: false,\n videoEnabled: false,\n audioDeviceId: undefined,\n audioOutputDeviceId: undefined,\n videoDeviceId: undefined,\n connect: undefined,\n isStarted: undefined,\n isConnecting: false,\n mode: 'full',\n carouselType: 'grid',\n preferredFocusLayout: 'horizontal',\n activeCorner: 'top-left',\n compactViewMode: 'basic',\n\n // Текущая активная доска\n activeBoardId: undefined,\n activeClassroom: undefined,\n\n localFullView: false,\n\n // токен для конференции\n token: undefined,\n\n // Поднятые руки\n raisedHands: [],\n isHandRaised: false,\n\n pinnedTrack: null,\n\n updateStore: (type: keyof useCallStoreT, value: any) => set({ [type]: value }),\n\n togglePinnedTrack: (track: PinnedTrackT) =>\n set((state) => {\n const isSame =\n state.pinnedTrack?.participantIdentity === track.participantIdentity &&\n state.pinnedTrack?.source === track.source;\n return { pinnedTrack: isSame ? null : track };\n }),\n clearPinnedTrack: () => set({ pinnedTrack: null }),\n isTrackPinned: (track: PinnedTrackT) => {\n const { pinnedTrack } = get();\n return (\n pinnedTrack?.participantIdentity === track.participantIdentity &&\n pinnedTrack?.source === track.source\n );\n },\n\n // Поднятые руки\n addRaisedHand: (hand: RaisedHandT) =>\n set((state) => {\n // Проверяем, есть ли уже рука от этого участника\n const existingHand = state.raisedHands.find(\n (h) => h.participantId === hand.participantId,\n );\n if (existingHand) {\n // Обновляем существующую руку\n return {\n raisedHands: state.raisedHands.map((h) =>\n h.participantId === hand.participantId ? hand : h,\n ),\n };\n }\n // Добавляем новую руку\n return { raisedHands: [...state.raisedHands, hand] };\n }),\n removeRaisedHand: (participantId: string) =>\n set((state) => ({\n raisedHands: state.raisedHands.filter((hand) => hand.participantId !== participantId),\n })),\n toggleHandRaised: () => set((state) => ({ isHandRaised: !state.isHandRaised })),\n clearAllRaisedHands: () => set({ raisedHands: [], isHandRaised: false }),\n isHandRaisedByParticipant: (participantId: string) => {\n const state = get();\n return state.raisedHands.some((hand) => hand.participantId === participantId);\n },\n }),\n {\n name: 'call-store',\n version: 4,\n migrate: (persisted, version) => {\n const state = persisted as Record<string, unknown>;\n if (version < 2) {\n const ct = state.carouselType;\n if (ct === 'focus') {\n state.carouselType = 'horizontal';\n }\n }\n if (version < 3) {\n const ct = state.carouselType;\n state.preferredFocusLayout = ct === 'horizontal' || ct === 'vertical' ? ct : 'horizontal';\n }\n if (version < 4) {\n const mode = state.compactViewMode;\n state.compactViewMode =\n mode === 'basic' || mode === 'expanded' || mode === 'audio' ? mode : 'basic';\n }\n return state as useCallStoreT;\n },\n partialize: (state) => ({\n isCameraPermission: state.isCameraPermission,\n isMicroPermission: state.isMicroPermission,\n audioEnabled: state.audioEnabled,\n videoEnabled: state.videoEnabled,\n audioDeviceId: state.audioDeviceId,\n videoDeviceId: state.videoDeviceId,\n carouselType: state.carouselType,\n preferredFocusLayout: state.preferredFocusLayout,\n activeCorner: state.activeCorner,\n compactViewMode: state.compactViewMode,\n }),\n },\n ),\n);\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\ntype PermissionStateT = undefined | 'granted' | 'prompt' | 'denied' | 'unavailable';\n\ntype BaseStateT = {\n cameraPermission: PermissionStateT;\n microphonePermission: PermissionStateT;\n isLoading: boolean;\n isPermissionDialogOpen: boolean;\n};\n\ntype DerivedStateT = {\n isCameraGranted: boolean;\n isMicrophoneGranted: boolean;\n isCameraDenied: boolean;\n isMicrophoneDenied: boolean;\n isCameraPrompted: boolean;\n isMicrophonePrompted: boolean;\n};\n\ntype State = BaseStateT & DerivedStateT;\n\nexport const usePermissionsStore = create<State>()(\n persist(\n (_, get) => ({\n cameraPermission: undefined,\n microphonePermission: undefined,\n isLoading: true,\n isPermissionDialogOpen: false,\n\n get isCameraGranted() {\n return get().cameraPermission === 'granted';\n },\n get isMicrophoneGranted() {\n return get().microphonePermission === 'granted';\n },\n get isCameraDenied() {\n return get().cameraPermission === 'denied';\n },\n get isMicrophoneDenied() {\n return get().microphonePermission === 'denied';\n },\n get isCameraPrompted() {\n return get().cameraPermission === 'prompt';\n },\n get isMicrophonePrompted() {\n return get().microphonePermission === 'prompt';\n },\n }),\n {\n name: 'permissions-storage',\n partialize: (state) => ({\n cameraPermission: state.cameraPermission,\n microphonePermission: state.microphonePermission,\n }),\n },\n ),\n);\n\nexport const openPermissionsDialog = () => {\n usePermissionsStore.setState({ isPermissionDialogOpen: true });\n};\n\nexport const closePermissionsDialog = () => {\n usePermissionsStore.setState({ isPermissionDialogOpen: false });\n};\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport {\n loadUserChoices,\n saveUserChoices,\n LocalUserChoices as LocalUserChoicesLK,\n} from '@livekit/components-core';\nimport { VideoQuality } from 'livekit-client';\nimport type { NoiseCancellationMode } from '@xipkg/calls-types';\n\nexport type VideoResolution = 'h720' | 'h360' | 'h180';\n\nexport type LocalUserChoices = LocalUserChoicesLK & {\n noiseReductionEnabled?: boolean;\n blurEnabled?: boolean;\n audioOutputDeviceId?: string;\n videoPublishResolution?: VideoResolution;\n videoSubscribeQuality?: VideoQuality;\n /** Включено ли шумоподавление (любой режим кроме off). */\n noiseCancellationEnabled?: boolean;\n /** Режим шумоподавления: off | webrtc | krisp. */\n noiseCancellationMode?: NoiseCancellationMode;\n};\n\nfunction getUserChoicesState(): LocalUserChoices {\n return {\n noiseReductionEnabled: false,\n blurEnabled: false,\n audioOutputDeviceId: 'default',\n videoPublishResolution: 'h720',\n videoSubscribeQuality: VideoQuality.HIGH,\n noiseCancellationEnabled: false,\n noiseCancellationMode: 'webrtc',\n ...loadUserChoices(),\n };\n}\n\nexport const useUserChoicesStore = create<LocalUserChoices>()(\n persist(\n () => ({\n ...getUserChoicesState(),\n }),\n {\n name: 'user-choices-storage',\n onRehydrateStorage: () => (state) => {\n if (state) {\n saveUserChoices(state, false);\n }\n },\n },\n ),\n);\n","import { Track } from 'livekit-client';\nimport type { TrackReferenceOrPlaceholder } from '@livekit/components-core';\n\nexport type PinnedTrackT = {\n participantIdentity: string;\n source: Track.Source;\n};\n\nexport function matchesPinnedTrack(\n track: TrackReferenceOrPlaceholder,\n pinned: PinnedTrackT,\n): boolean {\n return (\n track.participant.identity === pinned.participantIdentity && track.source === pinned.source\n );\n}\n\nexport function findPinnedTrackRef(\n tracks: TrackReferenceOrPlaceholder[],\n pinned: PinnedTrackT | null,\n): TrackReferenceOrPlaceholder | undefined {\n if (!pinned) return undefined;\n return tracks.find((track) => matchesPinnedTrack(track, pinned));\n}\n\nexport function toPinnedTrack(\n track: TrackReferenceOrPlaceholder,\n): PinnedTrackT {\n return {\n participantIdentity: track.participant.identity,\n source: track.source ?? Track.Source.Camera,\n };\n}\n\n/** Перемещает закреплённый трек на первое место в переданном списке */\nexport function applyPinFirst(\n tracks: TrackReferenceOrPlaceholder[],\n pinned: PinnedTrackT | null,\n): TrackReferenceOrPlaceholder[] {\n if (!pinned) return tracks;\n const pinnedRef = findPinnedTrackRef(tracks, pinned);\n if (!pinnedRef) return tracks;\n return [pinnedRef, ...tracks.filter((track) => track !== pinnedRef)];\n}\n\n/** Участник для главной плитки focus-сетки (без учёта локального pin) */\nexport function pickDefaultFocusTrack(\n tracks: TrackReferenceOrPlaceholder[],\n): TrackReferenceOrPlaceholder | undefined {\n const screenShare = tracks.find(\n (track) =>\n track.source === Track.Source.ScreenShare && track.publication?.isSubscribed,\n );\n if (screenShare) return screenShare;\n return tracks.find((track) => track.source === Track.Source.Camera);\n}\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\ntype SoundKey =\n | 'chatMessage'\n | 'handRaise'\n | 'userJoin'\n | 'userLeft'\n | 'boardTimerEnd'\n | 'boardTimerWarn';\n\ninterface SoundEffectsState {\n chatMessageVolume: number;\n handRaiseVolume: number;\n userJoinVolume: number;\n userLeftVolume: number;\n boardTimerEndVolume: number;\n boardTimerWarnVolume: number;\n\n setSoundVolume: (key: SoundKey, volume: number) => void;\n getEffectiveVolume: (key: SoundKey) => number;\n}\n\nconst DEFAULTS: Record<SoundKey, number> = {\n chatMessage: 0.25,\n handRaise: 0.25,\n userJoin: 0.25,\n userLeft: 0.25,\n boardTimerEnd: 1,\n boardTimerWarn: 1,\n};\n\nconst VOLUME_KEY_MAP: Record<SoundKey, keyof SoundEffectsState> = {\n chatMessage: 'chatMessageVolume',\n handRaise: 'handRaiseVolume',\n userJoin: 'userJoinVolume',\n userLeft: 'userLeftVolume',\n boardTimerEnd: 'boardTimerEndVolume',\n boardTimerWarn: 'boardTimerWarnVolume',\n};\n\nconst clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value));\n\nexport const useSoundEffectsStore = create<SoundEffectsState>()(\n persist(\n (set, get) => ({\n chatMessageVolume: DEFAULTS.chatMessage,\n handRaiseVolume: DEFAULTS.handRaise,\n userJoinVolume: DEFAULTS.userJoin,\n userLeftVolume: DEFAULTS.userLeft,\n boardTimerEndVolume: DEFAULTS.boardTimerEnd,\n boardTimerWarnVolume: DEFAULTS.boardTimerWarn,\n\n setSoundVolume: (key, volume) => {\n const min = key === 'boardTimerEnd' ? 0.2 : 0;\n const clamped = clamp(volume, min, 1);\n set({ [VOLUME_KEY_MAP[key]]: clamped });\n },\n\n getEffectiveVolume: (key) => {\n const storeKey = VOLUME_KEY_MAP[key];\n return get()[storeKey] as number;\n },\n }),\n {\n name: 'sound-effects-store',\n version: 1,\n partialize: (state) => ({\n chatMessageVolume: state.chatMessageVolume,\n handRaiseVolume: state.handRaiseVolume,\n userJoinVolume: state.userJoinVolume,\n userLeftVolume: state.userLeftVolume,\n boardTimerEndVolume: state.boardTimerEndVolume,\n boardTimerWarnVolume: state.boardTimerWarnVolume,\n }),\n },\n ),\n);\n\nexport { DEFAULTS as SOUND_DEFAULTS };\nexport type { SoundKey };\n","import { create } from 'zustand';\n\nexport type FeatureKey = 'compactView' | 'whiteboard' | 'raiseHand' | 'chat';\n\ntype FeatureMapT = Record<FeatureKey, boolean>;\n\ntype FeaturesState = {\n features: FeatureMapT;\n\n setFeature: (key: FeatureKey, value: boolean) => void;\n setFeatures: (features: Partial<FeatureMapT>) => void;\n};\n\nconst defaultFeatures: FeatureMapT = {\n compactView: true,\n whiteboard: true,\n raiseHand: true,\n chat: true,\n};\n\nexport const useFeaturesStore = create<FeaturesState>((set) => ({\n features: defaultFeatures,\n\n setFeature: (key, value) =>\n set((state) => ({\n features: { ...state.features, [key]: value },\n })),\n\n setFeatures: (features) =>\n set((state) => ({\n features: { ...state.features, ...features },\n })),\n}));\n","import { create } from 'zustand';\n\ninterface FocusModeState {\n focusMode: boolean;\n setFocusMode: (value: boolean) => void;\n toggleFocusMode: () => void;\n}\n\nexport const useFocusModeStore = create<FocusModeState>((set) => ({\n focusMode: false,\n setFocusMode: (value) => set({ focusMode: value }),\n toggleFocusMode: () => set((state) => ({ focusMode: !state.focusMode })),\n}));\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/store/callStore.ts","../src/store/permissions.ts","../src/store/userChoices.ts","../src/store/pinnedTrack.ts","../src/store/useSoundEffectsStore.ts","../src/store/featuresStore.ts","../src/store/useFocusModeStore.ts"],"names":["create","persist"],"mappings":"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","file":"index.mjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { LiveKitRoomProps } from '@livekit/components-react';\nimport { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport type { PinnedParticipantT } from './pinnedTrack';\n\ntype RaisedHandT = {\n participantId: string;\n participantName: string;\n timestamp: number;\n};\n\nexport type CornerT = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\nexport type CompactViewModeT = 'basic' | 'expanded' | 'audio';\n\ntype useCallStoreT = {\n // разрешение от браузера на использование камеры\n isCameraPermission: boolean | null;\n isMicroPermission: boolean | null;\n // включён ли у пользователя микро\n audioEnabled: boolean;\n videoEnabled: boolean;\n // id-выбранного устройства\n audioDeviceId: ConstrainDOMString | undefined;\n audioOutputDeviceId: ConstrainDOMString | undefined;\n videoDeviceId: ConstrainDOMString | undefined;\n // подключена ли конференция\n connect: LiveKitRoomProps['connect'];\n // началась ли ВКС для пользователя\n isStarted: boolean | undefined;\n // состояние подключения\n isConnecting: boolean;\n\n mode: 'compact' | 'full';\n carouselType: 'grid' | 'horizontal' | 'vertical';\n preferredFocusLayout: 'horizontal' | 'vertical';\n activeCorner: CornerT;\n\n /** Режим вида компакт-ВКС: одна плитка, несколько плиток или только аудио */\n compactViewMode: CompactViewModeT;\n\n // Текущая активная доска (для синхронизации с новыми участниками)\n activeBoardId: string | undefined;\n activeClassroom: string | undefined;\n\n /** Локальный переключатель: пользователь сам ушёл в полную ВКС («Только меня»), комната на сервере остаётся на доске */\n localFullView: boolean;\n\n // токен для конференции\n token: string | undefined;\n\n // Поднятые руки\n raisedHands: RaisedHandT[];\n isHandRaised: boolean;\n\n /** Закреплённые участники по кабинетам (userId + source), порядок = приоритет */\n pinnedByClassroom: Record<string, PinnedParticipantT[]>;\n\n updateStore: (type: keyof useCallStoreT, value: any) => void;\n togglePinnedParticipant: (pin: PinnedParticipantT, classroomId: string) => void;\n removePinnedParticipant: (pin: PinnedParticipantT, classroomId: string) => void;\n getPinsForClassroom: (classroomId: string) => PinnedParticipantT[];\n isParticipantPinned: (pin: PinnedParticipantT, classroomId: string) => boolean;\n addRaisedHand: (hand: RaisedHandT) => void;\n removeRaisedHand: (participantId: string) => void;\n toggleHandRaised: () => void;\n clearAllRaisedHands: () => void;\n isHandRaisedByParticipant: (participantId: string) => boolean;\n};\n\nexport const useCallStore = create<useCallStoreT>()(\n persist(\n (set, get) => ({\n isCameraPermission: null,\n isMicroPermission: null,\n audioEnabled: false,\n videoEnabled: false,\n audioDeviceId: undefined,\n audioOutputDeviceId: undefined,\n videoDeviceId: undefined,\n connect: undefined,\n isStarted: undefined,\n isConnecting: false,\n mode: 'full',\n carouselType: 'grid',\n preferredFocusLayout: 'horizontal',\n activeCorner: 'top-left',\n compactViewMode: 'basic',\n\n // Текущая активная доска\n activeBoardId: undefined,\n activeClassroom: undefined,\n\n localFullView: false,\n\n // токен для конференции\n token: undefined,\n\n // Поднятые руки\n raisedHands: [],\n isHandRaised: false,\n\n pinnedByClassroom: {},\n\n updateStore: (type: keyof useCallStoreT, value: any) => set({ [type]: value }),\n\n togglePinnedParticipant: (pin: PinnedParticipantT, classroomId: string) =>\n set((state) => {\n const current = state.pinnedByClassroom[classroomId] ?? [];\n const existingIndex = current.findIndex(\n (item) => item.userId === pin.userId && item.source === pin.source,\n );\n const next = { ...state.pinnedByClassroom };\n\n if (existingIndex >= 0) {\n const updated = current.filter((_, index) => index !== existingIndex);\n if (updated.length) {\n next[classroomId] = updated;\n } else {\n delete next[classroomId];\n }\n } else {\n next[classroomId] = [...current, pin];\n }\n\n return { pinnedByClassroom: next };\n }),\n removePinnedParticipant: (pin: PinnedParticipantT, classroomId: string) =>\n set((state) => {\n const current = state.pinnedByClassroom[classroomId];\n if (!current?.length) return state;\n\n const updated = current.filter(\n (item) => !(item.userId === pin.userId && item.source === pin.source),\n );\n const next = { ...state.pinnedByClassroom };\n if (updated.length) {\n next[classroomId] = updated;\n } else {\n delete next[classroomId];\n }\n return { pinnedByClassroom: next };\n }),\n getPinsForClassroom: (classroomId: string) => get().pinnedByClassroom[classroomId] ?? [],\n isParticipantPinned: (pin: PinnedParticipantT, classroomId: string) => {\n const pins = get().pinnedByClassroom[classroomId] ?? [];\n return pins.some((item) => item.userId === pin.userId && item.source === pin.source);\n },\n\n // Поднятые руки\n addRaisedHand: (hand: RaisedHandT) =>\n set((state) => {\n // Проверяем, есть ли уже рука от этого участника\n const existingHand = state.raisedHands.find(\n (h) => h.participantId === hand.participantId,\n );\n if (existingHand) {\n // Обновляем существующую руку\n return {\n raisedHands: state.raisedHands.map((h) =>\n h.participantId === hand.participantId ? hand : h,\n ),\n };\n }\n // Добавляем новую руку\n return { raisedHands: [...state.raisedHands, hand] };\n }),\n removeRaisedHand: (participantId: string) =>\n set((state) => ({\n raisedHands: state.raisedHands.filter((hand) => hand.participantId !== participantId),\n })),\n toggleHandRaised: () => set((state) => ({ isHandRaised: !state.isHandRaised })),\n clearAllRaisedHands: () => set({ raisedHands: [], isHandRaised: false }),\n isHandRaisedByParticipant: (participantId: string) => {\n const state = get();\n return state.raisedHands.some((hand) => hand.participantId === participantId);\n },\n }),\n {\n name: 'call-store',\n version: 5,\n migrate: (persisted, version) => {\n const state = persisted as Record<string, unknown>;\n if (version < 2) {\n const ct = state.carouselType;\n if (ct === 'focus') {\n state.carouselType = 'horizontal';\n }\n }\n if (version < 3) {\n const ct = state.carouselType;\n state.preferredFocusLayout = ct === 'horizontal' || ct === 'vertical' ? ct : 'horizontal';\n }\n if (version < 4) {\n const mode = state.compactViewMode;\n state.compactViewMode =\n mode === 'basic' || mode === 'expanded' || mode === 'audio' ? mode : 'basic';\n }\n if (version < 5) {\n state.pinnedByClassroom =\n typeof state.pinnedByClassroom === 'object' && state.pinnedByClassroom !== null\n ? state.pinnedByClassroom\n : {};\n delete state.pinnedTrack;\n }\n return state as useCallStoreT;\n },\n partialize: (state) => ({\n isCameraPermission: state.isCameraPermission,\n isMicroPermission: state.isMicroPermission,\n audioEnabled: state.audioEnabled,\n videoEnabled: state.videoEnabled,\n audioDeviceId: state.audioDeviceId,\n videoDeviceId: state.videoDeviceId,\n carouselType: state.carouselType,\n preferredFocusLayout: state.preferredFocusLayout,\n activeCorner: state.activeCorner,\n compactViewMode: state.compactViewMode,\n pinnedByClassroom: state.pinnedByClassroom,\n }),\n },\n ),\n);\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\ntype PermissionStateT = undefined | 'granted' | 'prompt' | 'denied' | 'unavailable';\n\ntype BaseStateT = {\n cameraPermission: PermissionStateT;\n microphonePermission: PermissionStateT;\n isLoading: boolean;\n isPermissionDialogOpen: boolean;\n};\n\ntype DerivedStateT = {\n isCameraGranted: boolean;\n isMicrophoneGranted: boolean;\n isCameraDenied: boolean;\n isMicrophoneDenied: boolean;\n isCameraPrompted: boolean;\n isMicrophonePrompted: boolean;\n};\n\ntype State = BaseStateT & DerivedStateT;\n\nexport const usePermissionsStore = create<State>()(\n persist(\n (_, get) => ({\n cameraPermission: undefined,\n microphonePermission: undefined,\n isLoading: true,\n isPermissionDialogOpen: false,\n\n get isCameraGranted() {\n return get().cameraPermission === 'granted';\n },\n get isMicrophoneGranted() {\n return get().microphonePermission === 'granted';\n },\n get isCameraDenied() {\n return get().cameraPermission === 'denied';\n },\n get isMicrophoneDenied() {\n return get().microphonePermission === 'denied';\n },\n get isCameraPrompted() {\n return get().cameraPermission === 'prompt';\n },\n get isMicrophonePrompted() {\n return get().microphonePermission === 'prompt';\n },\n }),\n {\n name: 'permissions-storage',\n partialize: (state) => ({\n cameraPermission: state.cameraPermission,\n microphonePermission: state.microphonePermission,\n }),\n },\n ),\n);\n\nexport const openPermissionsDialog = () => {\n usePermissionsStore.setState({ isPermissionDialogOpen: true });\n};\n\nexport const closePermissionsDialog = () => {\n usePermissionsStore.setState({ isPermissionDialogOpen: false });\n};\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport {\n loadUserChoices,\n saveUserChoices,\n LocalUserChoices as LocalUserChoicesLK,\n} from '@livekit/components-core';\nimport { VideoQuality } from 'livekit-client';\nimport type { NoiseCancellationMode } from '@xipkg/calls-types';\n\nexport type VideoResolution = 'h720' | 'h360' | 'h180';\n\nexport type LocalUserChoices = LocalUserChoicesLK & {\n noiseReductionEnabled?: boolean;\n blurEnabled?: boolean;\n audioOutputDeviceId?: string;\n videoPublishResolution?: VideoResolution;\n videoSubscribeQuality?: VideoQuality;\n /** Включено ли шумоподавление (любой режим кроме off). */\n noiseCancellationEnabled?: boolean;\n /** Режим шумоподавления: off | webrtc | krisp. */\n noiseCancellationMode?: NoiseCancellationMode;\n};\n\nfunction getUserChoicesState(): LocalUserChoices {\n return {\n noiseReductionEnabled: false,\n blurEnabled: false,\n audioOutputDeviceId: 'default',\n videoPublishResolution: 'h720',\n videoSubscribeQuality: VideoQuality.HIGH,\n noiseCancellationEnabled: false,\n noiseCancellationMode: 'webrtc',\n ...loadUserChoices(),\n };\n}\n\nexport const useUserChoicesStore = create<LocalUserChoices>()(\n persist(\n () => ({\n ...getUserChoicesState(),\n }),\n {\n name: 'user-choices-storage',\n onRehydrateStorage: () => (state) => {\n if (state) {\n saveUserChoices(state, false);\n }\n },\n },\n ),\n);\n","import { Track } from 'livekit-client';\nimport type { TrackReferenceOrPlaceholder } from '@livekit/components-core';\n\n/** Стабильный идентификатор участника для закрепления в рамках кабинета */\nexport type PinnedParticipantT = {\n userId: string;\n source: Track.Source;\n};\n\n/** @deprecated Используйте PinnedParticipantT */\nexport type PinnedTrackT = PinnedParticipantT;\n\nexport function getParticipantUserId(participant: { identity: string; metadata?: string }): string {\n if (participant.metadata) {\n try {\n const meta = JSON.parse(participant.metadata) as {\n user_id?: string | number;\n id?: string | number;\n };\n if (meta?.user_id != null) return String(meta.user_id);\n if (meta?.id != null) return String(meta.id);\n } catch {\n /* metadata is not JSON */\n }\n }\n return participant.identity;\n}\n\nexport function toPinnedParticipant(track: TrackReferenceOrPlaceholder): PinnedParticipantT {\n return {\n userId: getParticipantUserId(track.participant),\n source: track.source ?? Track.Source.Camera,\n };\n}\n\n/** @deprecated Используйте toPinnedParticipant */\nexport const toPinnedTrack = toPinnedParticipant;\n\nexport function matchesPinnedParticipant(\n track: TrackReferenceOrPlaceholder,\n pinned: PinnedParticipantT,\n): boolean {\n return (\n getParticipantUserId(track.participant) === pinned.userId && track.source === pinned.source\n );\n}\n\n/** @deprecated Используйте matchesPinnedParticipant */\nexport const matchesPinnedTrack = matchesPinnedParticipant;\n\nexport function findPinnedTrackRef(\n tracks: TrackReferenceOrPlaceholder[],\n pinned: PinnedParticipantT,\n): TrackReferenceOrPlaceholder | undefined {\n return tracks.find((track) => matchesPinnedParticipant(track, pinned));\n}\n\n/** Перемещает закреплённых участников в начало списка (порядок pin сохраняется) */\nexport function applyPinsFirst(\n tracks: TrackReferenceOrPlaceholder[],\n pins: PinnedParticipantT[],\n): TrackReferenceOrPlaceholder[] {\n if (!pins.length) return tracks;\n\n const pinnedRefs: TrackReferenceOrPlaceholder[] = [];\n const seen = new Set<TrackReferenceOrPlaceholder>();\n\n for (const pin of pins) {\n const ref = findPinnedTrackRef(tracks, pin);\n if (ref && !seen.has(ref)) {\n pinnedRefs.push(ref);\n seen.add(ref);\n }\n }\n\n if (!pinnedRefs.length) return tracks;\n return [...pinnedRefs, ...tracks.filter((track) => !seen.has(track))];\n}\n\nexport function applyPinFirst(\n tracks: TrackReferenceOrPlaceholder[],\n pinned: PinnedParticipantT | null,\n): TrackReferenceOrPlaceholder[] {\n return applyPinsFirst(tracks, pinned ? [pinned] : []);\n}\n\n/** Участник для главной плитки focus-сетки (без учёта локального pin) */\nexport function pickDefaultFocusTrack(\n tracks: TrackReferenceOrPlaceholder[],\n): TrackReferenceOrPlaceholder | undefined {\n const screenShare = tracks.find(\n (track) => track.source === Track.Source.ScreenShare && track.publication?.isSubscribed,\n );\n if (screenShare) return screenShare;\n return tracks.find((track) => track.source === Track.Source.Camera);\n}\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\n\ntype SoundKey =\n | 'chatMessage'\n | 'handRaise'\n | 'userJoin'\n | 'userLeft'\n | 'boardTimerEnd'\n | 'boardTimerWarn';\n\ninterface SoundEffectsState {\n chatMessageVolume: number;\n handRaiseVolume: number;\n userJoinVolume: number;\n userLeftVolume: number;\n boardTimerEndVolume: number;\n boardTimerWarnVolume: number;\n\n setSoundVolume: (key: SoundKey, volume: number) => void;\n getEffectiveVolume: (key: SoundKey) => number;\n}\n\nconst DEFAULTS: Record<SoundKey, number> = {\n chatMessage: 0.25,\n handRaise: 0.25,\n userJoin: 0.25,\n userLeft: 0.25,\n boardTimerEnd: 1,\n boardTimerWarn: 1,\n};\n\nconst VOLUME_KEY_MAP: Record<SoundKey, keyof SoundEffectsState> = {\n chatMessage: 'chatMessageVolume',\n handRaise: 'handRaiseVolume',\n userJoin: 'userJoinVolume',\n userLeft: 'userLeftVolume',\n boardTimerEnd: 'boardTimerEndVolume',\n boardTimerWarn: 'boardTimerWarnVolume',\n};\n\nconst clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value));\n\nexport const useSoundEffectsStore = create<SoundEffectsState>()(\n persist(\n (set, get) => ({\n chatMessageVolume: DEFAULTS.chatMessage,\n handRaiseVolume: DEFAULTS.handRaise,\n userJoinVolume: DEFAULTS.userJoin,\n userLeftVolume: DEFAULTS.userLeft,\n boardTimerEndVolume: DEFAULTS.boardTimerEnd,\n boardTimerWarnVolume: DEFAULTS.boardTimerWarn,\n\n setSoundVolume: (key, volume) => {\n const min = key === 'boardTimerEnd' ? 0.2 : 0;\n const clamped = clamp(volume, min, 1);\n set({ [VOLUME_KEY_MAP[key]]: clamped });\n },\n\n getEffectiveVolume: (key) => {\n const storeKey = VOLUME_KEY_MAP[key];\n return get()[storeKey] as number;\n },\n }),\n {\n name: 'sound-effects-store',\n version: 1,\n partialize: (state) => ({\n chatMessageVolume: state.chatMessageVolume,\n handRaiseVolume: state.handRaiseVolume,\n userJoinVolume: state.userJoinVolume,\n userLeftVolume: state.userLeftVolume,\n boardTimerEndVolume: state.boardTimerEndVolume,\n boardTimerWarnVolume: state.boardTimerWarnVolume,\n }),\n },\n ),\n);\n\nexport { DEFAULTS as SOUND_DEFAULTS };\nexport type { SoundKey };\n","import { create } from 'zustand';\n\nexport type FeatureKey = 'compactView' | 'whiteboard' | 'raiseHand' | 'chat';\n\ntype FeatureMapT = Record<FeatureKey, boolean>;\n\ntype FeaturesState = {\n features: FeatureMapT;\n\n setFeature: (key: FeatureKey, value: boolean) => void;\n setFeatures: (features: Partial<FeatureMapT>) => void;\n};\n\nconst defaultFeatures: FeatureMapT = {\n compactView: true,\n whiteboard: true,\n raiseHand: true,\n chat: true,\n};\n\nexport const useFeaturesStore = create<FeaturesState>((set) => ({\n features: defaultFeatures,\n\n setFeature: (key, value) =>\n set((state) => ({\n features: { ...state.features, [key]: value },\n })),\n\n setFeatures: (features) =>\n set((state) => ({\n features: { ...state.features, ...features },\n })),\n}));\n","import { create } from 'zustand';\n\ninterface FocusModeState {\n focusMode: boolean;\n setFocusMode: (value: boolean) => void;\n toggleFocusMode: () => void;\n}\n\nexport const useFocusModeStore = create<FocusModeState>((set) => ({\n focusMode: false,\n setFocusMode: (value) => set({ focusMode: value }),\n toggleFocusMode: () => set((state) => ({ focusMode: !state.focusMode })),\n}));\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xipkg/calls-store",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"zustand": "5.0.3",
|
|
16
|
-
"@xipkg/calls-types": "^0.
|
|
16
|
+
"@xipkg/calls-types": "^0.1.1"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@tanstack/react-query-devtools": "5.73.3",
|