mediasfu-angular 2.2.1 → 2.2.2

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.
Files changed (79) hide show
  1. package/README.md +832 -1
  2. package/dist/README.md +832 -1
  3. package/dist/fesm2022/mediasfu-angular.mjs +9284 -4188
  4. package/dist/fesm2022/mediasfu-angular.mjs.map +1 -1
  5. package/dist/lib/@types/types.d.ts +6 -1
  6. package/dist/lib/@types/ui-overrides.types.d.ts +310 -0
  7. package/dist/lib/components/background-components/background-modal/background-modal.component.d.ts +1023 -2
  8. package/dist/lib/components/breakout-components/breakout-rooms-modal.component.d.ts +1069 -45
  9. package/dist/lib/components/breakout-components/edit-room-modal/edit-room-modal.component.d.ts +1054 -42
  10. package/dist/lib/components/co-host-components/co-host-modal/co-host-modal.component.d.ts +1067 -56
  11. package/dist/lib/components/display-components/alert-component/alert.component.component.d.ts +80 -24
  12. package/dist/lib/components/display-components/audio-grid/audio-grid.component.d.ts +83 -11
  13. package/dist/lib/components/display-components/flexible-grid/flexible-grid.component.d.ts +96 -33
  14. package/dist/lib/components/display-components/loading-modal/loading-modal.component.d.ts +16 -26
  15. package/dist/lib/components/display-components/main-aspect-component/main-aspect-component.component.d.ts +6 -2
  16. package/dist/lib/components/display-components/main-container-component/main-container-component.component.d.ts +6 -2
  17. package/dist/lib/components/display-components/main-grid-component/main-grid-component.component.d.ts +7 -13
  18. package/dist/lib/components/display-components/main-screen-component/main-screen-component.component.d.ts +508 -7
  19. package/dist/lib/components/display-components/other-grid-component/other-grid-component.component.d.ts +7 -1
  20. package/dist/lib/components/display-components/sub-aspect-component/sub-aspect-component.component.d.ts +7 -2
  21. package/dist/lib/components/display-settings-components/display-settings-modal.component.d.ts +1107 -27
  22. package/dist/lib/components/event-settings-components/event-settings-modal/event-settings-modal.component.d.ts +1134 -49
  23. package/dist/lib/components/exit-components/confirm-exit-modal/confirm-exit-modal.component.d.ts +94 -32
  24. package/dist/lib/components/media-settings-components/media-settings-modal/media-settings-modal.component.d.ts +1123 -47
  25. package/dist/lib/components/mediasfu-components/mediasfu-broadcast.component.d.ts +24914 -73
  26. package/dist/lib/components/mediasfu-components/mediasfu-chat.component.d.ts +224 -73
  27. package/dist/lib/components/mediasfu-components/mediasfu-conference.component.d.ts +18068 -93
  28. package/dist/lib/components/mediasfu-components/mediasfu-generic.component.d.ts +56280 -93
  29. package/dist/lib/components/mediasfu-components/mediasfu-webinar.component.d.ts +20785 -93
  30. package/dist/lib/components/menu-components/custom-buttons/custom-buttons.component.d.ts +23 -4
  31. package/dist/lib/components/menu-components/meeting-id-component/meeting-id-component.component.d.ts +78 -1
  32. package/dist/lib/components/menu-components/meeting-passcode-component/meeting-passcode-component.component.d.ts +37 -1
  33. package/dist/lib/components/menu-components/menu-modal/menu-modal.component.d.ts +689 -9
  34. package/dist/lib/components/menu-components/share-buttons-component/share-buttons-component.component.d.ts +46 -2
  35. package/dist/lib/components/message-components/messages-modal/messages-modal.component.d.ts +76 -13
  36. package/dist/lib/components/misc-components/confirm-here-modal/confirm-here-modal.component.d.ts +1113 -17
  37. package/dist/lib/components/misc-components/share-event-modal/share-event-modal.component.d.ts +1114 -29
  38. package/dist/lib/components/participants-components/participants-modal/participants-modal.component.d.ts +1084 -6
  39. package/dist/lib/components/polls-components/poll-modal/poll-modal.component.d.ts +1060 -21
  40. package/dist/lib/components/recording-components/recording-modal/recording-modal.component.d.ts +1054 -35
  41. package/dist/lib/components/requests-components/requests-modal/requests-modal.component.d.ts +1117 -45
  42. package/dist/lib/components/screenboard-components/screenboard-modal/screenboard-modal.component.d.ts +1059 -47
  43. package/dist/lib/components/waiting-components/waiting-room-modal.component.d.ts +1119 -46
  44. package/dist/lib/components/whiteboard-components/configure-whiteboard-modal/configure-whiteboard-modal.component.d.ts +1049 -16
  45. package/dist/lib/consumers/add-videos-grid.service.d.ts +3 -0
  46. package/dist/lib/consumers/connect-ips.service.d.ts +3 -1
  47. package/dist/lib/consumers/connect-recv-transport.service.d.ts +4 -1
  48. package/dist/lib/consumers/connect-send-transport-audio.service.d.ts +5 -1
  49. package/dist/lib/consumers/connect-send-transport-screen.service.d.ts +6 -1
  50. package/dist/lib/consumers/connect-send-transport-video.service.d.ts +6 -1
  51. package/dist/lib/consumers/connect-send-transport.service.d.ts +3 -1
  52. package/dist/lib/consumers/consumer-resume.service.d.ts +2 -1
  53. package/dist/lib/consumers/create-send-transport.service.d.ts +4 -1
  54. package/dist/lib/consumers/disconnect-send-transport-audio.service.d.ts +3 -1
  55. package/dist/lib/consumers/disconnect-send-transport-screen.service.d.ts +3 -1
  56. package/dist/lib/consumers/disconnect-send-transport-video.service.d.ts +3 -1
  57. package/dist/lib/consumers/prepopulate-user-media.service.d.ts +3 -0
  58. package/dist/lib/consumers/resume-send-transport-audio.service.d.ts +3 -1
  59. package/dist/lib/consumers/signal-new-consumer-transport.service.d.ts +3 -1
  60. package/dist/lib/consumers/socket-receive-methods/join-consume-room.service.d.ts +3 -1
  61. package/dist/lib/consumers/socket-receive-methods/new-pipe-producer.service.d.ts +3 -1
  62. package/dist/lib/consumers/stream-success-audio-switch.service.d.ts +5 -1
  63. package/dist/lib/consumers/stream-success-audio.service.d.ts +3 -1
  64. package/dist/lib/consumers/stream-success-video.service.d.ts +5 -1
  65. package/dist/lib/directives/with-override.directive.d.ts +76 -0
  66. package/dist/lib/methods/utils/initial-values.util.d.ts +7 -2
  67. package/dist/lib/methods/utils/mini-audio-player/mini-audio-player.component.d.ts +3 -1
  68. package/dist/lib/methods/utils/producer/a-params.service.d.ts +4 -1
  69. package/dist/lib/methods/utils/producer/h-params.service.d.ts +4 -1
  70. package/dist/lib/methods/utils/producer/screen-params.service.d.ts +4 -1
  71. package/dist/lib/methods/utils/producer/v-params.service.d.ts +4 -1
  72. package/dist/lib/methods/whiteboard-methods/capture-canvas-stream.service.d.ts +3 -1
  73. package/dist/lib/producer-client/producer-client-emits/create-device-client.service.d.ts +4 -1
  74. package/dist/lib/producer-client/producer-client-emits/update-room-parameters-client.service.d.ts +3 -1
  75. package/dist/lib/producers/producer-emits/join-con-room.service.d.ts +3 -1
  76. package/dist/lib/producers/socket-receive-methods/get-domains.service.d.ts +3 -1
  77. package/dist/lib/services/ui-override-resolver.service.d.ts +91 -0
  78. package/dist/public-api.d.ts +4 -0
  79. package/package.json +2 -2
package/README.md CHANGED
@@ -80,7 +80,7 @@ Coming soon! Watch this space for our comprehensive video tutorial on setting up
80
80
  ---
81
81
 
82
82
  ## Table of Contents
83
-
83
+ - [Quick Reference: Component Props & UI Overrides](#quick-reference-component-props--ui-overrides)
84
84
  - [Features](#features)
85
85
  - [Getting Started](#getting-started)
86
86
  - [📘 Angular SDK Guide](#angular-sdk-guide)
@@ -94,6 +94,339 @@ Coming soon! Watch this space for our comprehensive video tutorial on setting up
94
94
  - [Troubleshooting](#troubleshooting)
95
95
  - [Contributing](#contributing)
96
96
 
97
+
98
+ ---
99
+
100
+ ## Quick Reference: Component Props & UI Overrides
101
+
102
+ > **New:** UI override parity now extends across Webinar and Chat layouts, unifying customization for every MediaSFU interface.
103
+
104
+ Every primary MediaSFU UI export—`MediasfuGeneric`, `MediasfuBroadcast`, `MediasfuConference`, `MediasfuWebinar`, and `MediasfuChat`—now ships with a consistent prop surface and a powerful `uiOverrides` input, so you can bend the bundled experience to match your product without losing MediaSFU's hardened real-time logic.
105
+
106
+ ### Shared component inputs (applies to every MediaSFU UI component)
107
+
108
+ | Input | Type | Default | What it does |
109
+ | --- | --- | --- | --- |
110
+ | `PrejoinPage` | `ComponentType` | `WelcomePage` | Swap in a custom pre-join experience. Receives unified pre-join options so you can add branding, legal copy, or warm-up flows. |
111
+ | `localLink` | `string` | `""` | Point the SDK at your self-hosted MediaSFU server. Leave empty when using MediaSFU Cloud. |
112
+ | `connectMediaSFU` | `boolean` | `true` | Toggle automatic socket/WebRTC connections. Set to `false` when you only need the UI shell. |
113
+ | `credentials` | `{ apiUserName: string; apiKey: string }` | `{ apiUserName: "", apiKey: "" }` | Supply cloud credentials without hard-coding them elsewhere. |
114
+ | `useLocalUIMode` | `boolean` | `false` | Run the interface in local/demo mode with no remote signaling. |
115
+ | `seedData`, `useSeed` | `SeedData`, `boolean` | `{}`, `false` | Pre-populate the UI for demos, snapshot tests, or onboarding tours. |
116
+ | `imgSrc` | `string` | `https://mediasfu.com/images/logo192.png` | Default artwork used across pre-join and modal flows. |
117
+ | `sourceParameters` | `Record<string, unknown>` | `undefined` | Shared helper bag (media devices, participant helpers, layout handlers). Pair with `updateSourceParameters` to mirror the SDK's internal utilities. |
118
+ | `updateSourceParameters` | `EventEmitter` | `undefined` | Receive the latest helper bundle so you can bridge MediaSFU logic into your own components. |
119
+ | `returnUI` | `boolean` | `true` | When `false`, mount the logic only—a perfect stepping stone to a fully bespoke interface. |
120
+ | `noUIPreJoinOptions` | `CreateJoinRoomParameters \| JoinLocalEventRoomParameters` | `undefined` | Feed pre-join data when `returnUI` is `false` and you want to bypass the on-screen wizard. |
121
+ | `joinRoom`, `createRoom` | `Function` | `undefined` | Inject your own networking layers for joining or creating rooms. |
122
+ | `customComponent` | `ComponentType` | `undefined` | Replace the entire UI while retaining transports, sockets, and helpers. |
123
+ | `customVideoCard`, `customAudioCard`, `customMiniCard` | `ComponentType` | `undefined` | Override participant card renders to add metadata, CTAs, or badges. |
124
+ | `[customStyles]` | `Record<string, any>` | `undefined` | Apply inline styles to the root wrapper (dashboards, split views, etc.). |
125
+ | `[uiOverrides]` | `MediasfuUICustomOverrides` | `undefined` | Targeted component/function overrides described below. |
126
+
127
+ > **Power combo:** Set `returnUI="false"` to run MediaSFU logic headless, capture helpers via `updateSourceParameters` output, and selectively bring UI pieces back with `uiOverrides`. That gives you progressive migration with minimal code churn.
128
+
129
+ ```typescript
130
+ import type { MediasfuUICustomOverrides } from 'mediasfu-angular';
131
+
132
+ const overrides: MediasfuUICustomOverrides = { /* ... */ };
133
+ ```
134
+
135
+ Bring the types into your project to unlock full IntelliSense for every override slot.
136
+
137
+ ### Custom UI Playbook
138
+
139
+ Use a toggle-driven "playbook" component to experiment with MediaSFU's customization layers. Flip a couple of booleans and you can watch the SDK jump between prebuilt layouts, headless logic, or a fully bespoke workspace driven by `customComponent`.
140
+
141
+ #### What the playbook demonstrates
142
+
143
+ - **Connection presets**: toggle `connectionScenario` between `cloud`, `hybrid`, or `ce` to swap credentials, local links, and connection modes in one place.
144
+ - **Experience selector**: the `selectedExperience` switch renders `MediasfuGeneric`, `MediasfuBroadcast`, `MediasfuWebinar`, `MediasfuConference`, or `MediasfuChat` without touching the rest of your stack.
145
+ - **UI strategy flags**: booleans like `showPrebuiltUI`, `enableFullCustomUI`, and `enableNoUIPreJoin` demonstrate how to run the MediaSFU logic with or without the bundled UI.
146
+ - **Layered overrides**: toggles enable the custom video/audio/mini cards, drop-in `uiOverrides` for layout and modal surfaces, container styling, and backend proxy helpers.
147
+ - **Custom workspace demo**: a `customComponent` receives live MediaSFU helpers so you can build dashboards, CRM surfaces, or any bespoke host interface.
148
+ - **Debug panel & helpers**: optional JSON panel exposes the `updateSourceParameters` payload so you can see exactly what to wire into your own components.
149
+
150
+ #### Try it quickly
151
+
152
+ ```typescript
153
+ @Component({
154
+ selector: 'app-custom-ui-playbook',
155
+ template: `
156
+ <ng-container [ngSwitch]="selectedExperience">
157
+ <app-mediasfu-generic *ngSwitchCase="'generic'"
158
+ [credentials]="currentPreset.credentials"
159
+ [localLink]="currentPreset.localLink"
160
+ [connectMediaSFU]="currentPreset.connectMediaSFU"
161
+ [returnUI]="showPrebuiltUI"
162
+ [uiOverrides]="overrides"
163
+ [customStyles]="containerStyles">
164
+ </app-mediasfu-generic>
165
+
166
+ <app-mediasfu-broadcast *ngSwitchCase="'broadcast'"
167
+ [credentials]="currentPreset.credentials"
168
+ [localLink]="currentPreset.localLink"
169
+ [connectMediaSFU]="currentPreset.connectMediaSFU"
170
+ [returnUI]="showPrebuiltUI"
171
+ [uiOverrides]="overrides">
172
+ </app-mediasfu-broadcast>
173
+
174
+ <!-- Similar for webinar, conference, chat -->
175
+ </ng-container>
176
+ `
177
+ })
178
+ export class CustomUIPlaybookComponent {
179
+ connectionScenario: 'cloud' | 'hybrid' | 'ce' = 'cloud';
180
+ selectedExperience: 'generic' | 'broadcast' | 'webinar' | 'conference' | 'chat' = 'generic';
181
+ showPrebuiltUI = true;
182
+ enableFullCustomUI = false;
183
+
184
+ connectionPresets = {
185
+ cloud: {
186
+ credentials: { apiUserName: 'demo', apiKey: 'demo' },
187
+ localLink: '',
188
+ connectMediaSFU: true
189
+ },
190
+ hybrid: {
191
+ credentials: { apiUserName: 'demo', apiKey: 'demo' },
192
+ localLink: 'http://localhost:3000',
193
+ connectMediaSFU: true
194
+ },
195
+ ce: {
196
+ credentials: undefined,
197
+ localLink: 'http://localhost:3000',
198
+ connectMediaSFU: false
199
+ },
200
+ };
201
+
202
+ get currentPreset() {
203
+ return this.connectionPresets[this.connectionScenario];
204
+ }
205
+
206
+ overrides: MediasfuUICustomOverrides = {
207
+ mainContainer: this.enableFullCustomUI ? {
208
+ component: CustomMainContainerComponent
209
+ } : undefined,
210
+ };
211
+
212
+ containerStyles = {
213
+ background: 'linear-gradient(135deg, #0f172a, #1e3a8a)',
214
+ minHeight: '100vh'
215
+ };
216
+ }
217
+ ```
218
+
219
+ Toggle the configuration values at the top of the playbook and watch the UI reconfigure instantly. It's the fastest path to understand MediaSFU's override surface before you fold the patterns into your production entrypoint.
220
+
221
+ #### Passing custom props and UI overrides
222
+
223
+ Use the same playbook to validate bespoke cards, override bundles, and fully custom workspaces before you move them into production code:
224
+
225
+ ```typescript
226
+ @Component({
227
+ selector: 'app-advanced-playbook',
228
+ template: `
229
+ <app-mediasfu-generic
230
+ [credentials]="credentials"
231
+ [customVideoCard]="videoCard"
232
+ [customAudioCard]="audioCard"
233
+ [customMiniCard]="miniCard"
234
+ [customComponent]="enableFullCustomUI ? customWorkspace : undefined"
235
+ [customStyles]="containerStyles"
236
+ [uiOverrides]="uiOverrides">
237
+ </app-mediasfu-generic>
238
+ `
239
+ })
240
+ export class AdvancedPlaybookComponent {
241
+ credentials = { apiUserName: 'demo', apiKey: 'demo' };
242
+ enableFullCustomUI = false;
243
+
244
+ // Custom card components with themed styling
245
+ videoCard = VideoCardComponent; // Pass component class
246
+ audioCard = AudioCardComponent;
247
+ miniCard = MiniCardComponent;
248
+ customWorkspace = CustomWorkspaceComponent;
249
+
250
+ containerStyles = {
251
+ background: '#0f172a',
252
+ borderRadius: '32px',
253
+ overflow: 'hidden'
254
+ };
255
+
256
+ uiOverrides: MediasfuUICustomOverrides = {
257
+ mainContainer: {
258
+ component: CustomMainContainerComponent
259
+ },
260
+ menuModal: {
261
+ component: CustomMenuModalComponent
262
+ },
263
+ consumerResume: {
264
+ wrap: (original) => async (params) => {
265
+ const startedAt = performance.now();
266
+ const result = await original(params);
267
+ console.log('consumer_resume', {
268
+ durationMs: performance.now() - startedAt,
269
+ consumerId: params?.consumer?.id,
270
+ });
271
+ return result;
272
+ },
273
+ },
274
+ };
275
+ }
276
+ ```
277
+
278
+ Because the playbook surfaces `updateSourceParameters`, you can also log or snapshot the helper bundle (`getParticipantMedia`, `toggleMenuModal`, `showAlert`, and more) to ensure your custom UI always receives the hooks it expects.
279
+
280
+ ### `uiOverrides` input — override keys at a glance
281
+
282
+ Each key accepts a `CustomComponentOverride<Props>` or `CustomFunctionOverride<Fn>` object with optional `component` and `wrap` fields. You can fully replace the default implementation or wrap it while forwarding props.
283
+
284
+ #### Layout & control surfaces
285
+
286
+ | Key | Default component | Typical use |
287
+ | --- | --- | --- |
288
+ | `mainContainer` | `MainContainerComponent` | Inject theming providers or dashboard layouts. |
289
+ | `mainAspect` | `MainAspectComponent` | Tune how the main region splits space. |
290
+ | `mainScreen` | `MainScreenComponent` | Orchestrate hero video + gallery interplay. |
291
+ | `mainGrid` | `MainGridComponent` | Modify layout or layering of primary participants. |
292
+ | `subAspect` | `SubAspectComponent` | Restyle fixed control strips in webinar/conference modes. |
293
+ | `otherGrid` | `OtherGridComponent` | Change presentation of off-stage attendees. |
294
+ | `flexibleGrid`, `flexibleGridAlt` | `FlexibleGrid` | Implement AI-driven or branded array layouts. |
295
+ | `flexibleVideo` | `FlexibleVideo` | Add captions, watermarks, or overlays to highlighted speakers. |
296
+ | `audioGrid` | `AudioGrid` | Customise audio-only attendee presentation. |
297
+ | `pagination` | `Pagination` | Introduce infinite scroll or auto-cycling carousels. |
298
+ | `controlButtons` | `ControlButtonsComponent` | Rebrand the primary action bar. |
299
+ | `controlButtonsAlt` | `ControlButtonsAltComponent` | Control secondary button clusters. |
300
+ | `controlButtonsTouch` | `ControlButtonsComponentTouch` | Deliver mobile-first controls (used heavily by `MediasfuChat`). |
301
+
302
+ #### Participant cards & widgets
303
+
304
+ | Key | Default component | Typical use |
305
+ | --- | --- | --- |
306
+ | `videoCard` | `VideoCard` | Add host badges, reactions, or CRM overlays. |
307
+ | `audioCard` | `AudioCard` | Swap avatars or expose spoken-language info. |
308
+ | `miniCard` | `MiniCard` | Customize thumbnails in picture-in-picture modes. |
309
+ | `miniAudio` | `MiniAudio` | Re-style the audio-only mini indicators. |
310
+ | `meetingProgressTimer` | `MeetingProgressTimer` | Replace the elapsed-time widget with countdowns or milestones. |
311
+ | `miniAudioPlayer` | `MiniAudioPlayer` | Provide alternative UI for recorded clip playback. |
312
+
313
+ #### Modals, dialogs, and collaboration surfaces
314
+
315
+ | Key | Default component | Typical use |
316
+ | --- | --- | --- |
317
+ | `loadingModal` | `LoadingModal` | Show branded skeletons while connecting. |
318
+ | `alert` | `AlertComponent` | Route alerts through your notification system. |
319
+ | `menuModal` | `MenuModal` | Redesign quick-action trays. |
320
+ | `eventSettingsModal` | `EventSettingsModal` | Extend host tools with your own settings. |
321
+ | `requestsModal` | `RequestsModal` | Build moderation queues tailored to your workflows. |
322
+ | `waitingRoomModal` | `WaitingRoomModal` | Deliver custom waiting-room experiences. |
323
+ | `coHostModal` | `CoHostModal` | Manage co-hosts with bespoke UX. |
324
+ | `mediaSettingsModal` | `MediaSettingsModal` | Embed device tests or instructions. |
325
+ | `participantsModal` | `ParticipantsModal` | Introduce advanced filters, search, or notes. |
326
+ | `messagesModal` | `MessagesModal` | Drop in your full-featured chat module. |
327
+ | `displaySettingsModal` | `DisplaySettingsModal` | Let users pick layouts, themes, or captions. |
328
+ | `confirmExitModal` | `ConfirmExitModal` | Meet compliance wording requirements. |
329
+ | `confirmHereModal` | `ConfirmHereModal` | Customize attendance confirmations for webinars. |
330
+ | `shareEventModal` | `ShareEventModal` | Add referral codes or QR sharing. |
331
+ | `recordingModal` | `RecordingModal` | Tailor recording confirmation flows. |
332
+ | `pollModal` | `PollModal` | Integrate your polling/quiz engine. |
333
+ | `backgroundModal` | `BackgroundModal` | Hook AI background replacement or brand presets. |
334
+ | `breakoutRoomsModal` | `BreakoutRoomsModal` | Implement drag-and-drop or AI room suggestions. |
335
+ | `configureWhiteboardModal` | `ConfigureWhiteboardModal` | Adjust collaboration permissions before launch. |
336
+ | `whiteboard` | `Whiteboard` | Replace with your whiteboard provider. |
337
+ | `screenboard` | `Screenboard` | Modify shared-screen annotation layers. |
338
+ | `screenboardModal` | `ScreenboardModal` | Reimagine how users enable shared annotations. |
339
+
340
+ #### Entry flows & custom renderers
341
+
342
+ | Key | Default component | Typical use |
343
+ | --- | --- | --- |
344
+ | `welcomePage` | `WelcomePage` | Provide a fully branded welcome/marketing splash. |
345
+ | `preJoinPage` | `PrejoinPage` | Override the wizard used before joining live sessions. |
346
+ | `customMenuButtonsRenderer` | `ControlButtonsAltComponent` | Supply a bespoke renderer for menu button groups without overriding each button. |
347
+
348
+ #### Function overrides
349
+
350
+ | Key | Default function | Typical use |
351
+ | --- | --- | --- |
352
+ | `consumerResume` | `consumerResume` | Wrap errors, capture analytics, or rate-limit consumer resume behavior. |
353
+ | `addVideosGrid` | `addVideosGrid` | Replace participant ordering or layout heuristics on the fly. |
354
+ | `prepopulateUserMedia` | `prepopulateUserMedia` | Customize initial media setup with custom video/audio/mini cards. |
355
+
356
+ > Function overrides support `{ implementation, wrap }`. Provide `implementation` for a full replacement, or `wrap` to intercept the default behavior before/after it runs.
357
+
358
+ ### Example: swap the chat modal and theme the controls
359
+
360
+ ```typescript
361
+ import { Component } from '@angular/core';
362
+ import { MediasfuGeneric } from 'mediasfu-angular';
363
+ import { MyChatModalComponent } from './ui/my-chat-modal.component';
364
+ import { MyControlsComponent } from './ui/my-controls.component';
365
+
366
+ @Component({
367
+ selector: 'app-my-meeting',
368
+ template: `
369
+ <app-mediasfu-generic
370
+ [credentials]="credentials"
371
+ [uiOverrides]="uiOverrides">
372
+ </app-mediasfu-generic>
373
+ `
374
+ })
375
+ export class MyMeetingComponent {
376
+ credentials = { apiUserName: 'your-api-user', apiKey: 'your-api-key' };
377
+
378
+ uiOverrides = {
379
+ messagesModal: {
380
+ component: MyChatModalComponent,
381
+ },
382
+ controlButtons: {
383
+ component: MyControlsComponent,
384
+ },
385
+ };
386
+ }
387
+ ```
388
+
389
+ ### Example: wrap a MediaSFU helper instead of replacing it
390
+
391
+ ```typescript
392
+ import { Component } from '@angular/core';
393
+ import { MediasfuConference } from 'mediasfu-angular';
394
+
395
+ @Component({
396
+ selector: 'app-analytics-meeting',
397
+ template: `
398
+ <app-mediasfu-conference
399
+ [credentials]="credentials"
400
+ [uiOverrides]="uiOverrides">
401
+ </app-mediasfu-conference>
402
+ `
403
+ })
404
+ export class AnalyticsMeetingComponent {
405
+ credentials = { apiUserName: 'your-api-user', apiKey: 'your-api-key' };
406
+
407
+ uiOverrides = {
408
+ consumerResume: {
409
+ wrap: (original) => async (params) => {
410
+ const startedAt = performance.now();
411
+ const result = await original(params);
412
+
413
+ // Send analytics
414
+ this.analytics.track('consumer_resume', {
415
+ durationMs: performance.now() - startedAt,
416
+ consumerId: params?.consumer?.id,
417
+ });
418
+
419
+ return result;
420
+ },
421
+ },
422
+ };
423
+
424
+ constructor(private analytics: AnalyticsService) {}
425
+ }
426
+ ```
427
+
428
+ ---
429
+
97
430
  # Features <a name="features"></a>
98
431
 
99
432
  MediaSFU's Angular SDK comes with a host of powerful features out of the box:
@@ -4002,6 +4335,504 @@ Once your custom components are built, modify the imports of `prepopulateUserMed
4002
4335
  This allows for full flexibility in how media is displayed in both the main and mini grids, giving you the ability to tailor the user experience to your specific needs.
4003
4336
 
4004
4337
 
4338
+
4339
+ ---
4340
+
4341
+ ## UI Component Customization & Override System
4342
+
4343
+ MediaSFU provides comprehensive customization capabilities for all UI components through a powerful override system. You can customize styling, inject custom templates, or completely replace components with your own implementations.
4344
+
4345
+ ### Overview
4346
+
4347
+ The customization system operates at three levels:
4348
+
4349
+ 1. **Style Overrides**: Apply custom CSS styles to containers, overlays, and content areas
4350
+ 2. **Template Injection**: Replace default component templates with custom Angular templates
4351
+ 3. **Component Replacement**: Completely replace MediaSFU components with your own using the `WithOverrideDirective`
4352
+
4353
+ ### 1. Style Customization
4354
+
4355
+ All display and modal components support style customization through Input properties:
4356
+
4357
+ #### Display Components (MainContainer, MainAspect, MainScreen, MainGrid, OtherGrid, SubAspect, FlexibleGrid, AudioGrid)
4358
+
4359
+ ```typescript
4360
+ @Component({
4361
+ selector: 'app-my-meeting',
4362
+ template: `
4363
+ <app-main-container
4364
+ [containerStyle]="{
4365
+ backgroundColor: '#1a1a1a',
4366
+ border: '2px solid #333',
4367
+ borderRadius: '12px',
4368
+ padding: '20px'
4369
+ }"
4370
+ [backgroundColor]="'transparent'">
4371
+ </app-main-container>
4372
+
4373
+ <app-flexible-grid
4374
+ [containerStyle]="{
4375
+ display: 'grid',
4376
+ gridTemplateColumns: 'repeat(3, 1fr)',
4377
+ gap: '16px'
4378
+ }">
4379
+ </app-flexible-grid>
4380
+ `
4381
+ })
4382
+ export class MyMeetingComponent {
4383
+ // Custom styles can also be dynamic
4384
+ mainGridStyle: Partial<CSSStyleDeclaration> = {
4385
+ backgroundColor: '#2a2a2a',
4386
+ maxWidth: '1400px',
4387
+ margin: '0 auto'
4388
+ };
4389
+ }
4390
+ ```
4391
+
4392
+ #### Modal Components (All modals support overlayStyle, contentStyle)
4393
+
4394
+ ```typescript
4395
+ @Component({
4396
+ selector: 'app-custom-modal-example',
4397
+ template: `
4398
+ <!-- Participants Modal with custom styling -->
4399
+ <app-participants-modal
4400
+ [isParticipantsModalVisible]="true"
4401
+ [overlayStyle]="{
4402
+ backgroundColor: 'rgba(0, 0, 0, 0.85)',
4403
+ backdropFilter: 'blur(8px)'
4404
+ }"
4405
+ [contentStyle]="{
4406
+ backgroundColor: '#ffffff',
4407
+ borderRadius: '16px',
4408
+ boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3)',
4409
+ maxWidth: '600px',
4410
+ padding: '24px'
4411
+ }">
4412
+ </app-participants-modal>
4413
+
4414
+ <!-- Recording Modal with custom theme -->
4415
+ <app-recording-modal
4416
+ [isRecordingModalVisible]="true"
4417
+ [contentStyle]="{
4418
+ backgroundColor: '#f5f5f5',
4419
+ border: '3px solid #007bff',
4420
+ fontFamily: 'Inter, sans-serif'
4421
+ }">
4422
+ </app-recording-modal>
4423
+ `
4424
+ })
4425
+ export class CustomModalExample {
4426
+ // Styles can be computed or conditional
4427
+ get modalOverlay(): Partial<CSSStyleDeclaration> {
4428
+ return {
4429
+ backgroundColor: this.isDarkMode ? 'rgba(0,0,0,0.9)' : 'rgba(0,0,0,0.5)'
4430
+ };
4431
+ }
4432
+ }
4433
+ ```
4434
+
4435
+ ### 2. Template Injection
4436
+
4437
+ Replace default component templates with custom Angular templates using `TemplateRef`:
4438
+
4439
+ ```typescript
4440
+ import { Component, TemplateRef, ViewChild } from '@angular/core';
4441
+
4442
+ @Component({
4443
+ selector: 'app-custom-template-demo',
4444
+ template: `
4445
+ <!-- Define custom template -->
4446
+ <ng-template #customMainGridTemplate let-components="components">
4447
+ <div class="my-custom-grid">
4448
+ <div class="grid-header">
4449
+ <h3>Active Participants</h3>
4450
+ <span class="count">{{ components?.length || 0 }}</span>
4451
+ </div>
4452
+ <div class="grid-content">
4453
+ <!-- Custom rendering logic -->
4454
+ <div *ngFor="let component of components" class="participant-tile">
4455
+ <ng-container *ngComponentOutlet="component"></ng-container>
4456
+ </div>
4457
+ </div>
4458
+ </div>
4459
+ </ng-template>
4460
+
4461
+ <!-- Use custom template -->
4462
+ <app-main-grid
4463
+ [customTemplate]="customMainGridTemplate"
4464
+ [mainGridStream]="streams">
4465
+ </app-main-grid>
4466
+
4467
+ <!-- Custom modal template -->
4468
+ <ng-template #customAlertTemplate let-message="message" let-type="type">
4469
+ <div class="custom-alert" [class.error]="type === 'error'">
4470
+ <i class="alert-icon"></i>
4471
+ <p>{{ message }}</p>
4472
+ <button (click)="closeAlert()">Dismiss</button>
4473
+ </div>
4474
+ </ng-template>
4475
+
4476
+ <app-alert-component
4477
+ [customTemplate]="customAlertTemplate"
4478
+ [visible]="showAlert"
4479
+ [message]="alertMessage">
4480
+ </app-alert-component>
4481
+ `,
4482
+ styles: [`
4483
+ .my-custom-grid {
4484
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
4485
+ border-radius: 12px;
4486
+ padding: 20px;
4487
+ }
4488
+
4489
+ .grid-header {
4490
+ display: flex;
4491
+ justify-content: space-between;
4492
+ color: white;
4493
+ margin-bottom: 16px;
4494
+ }
4495
+
4496
+ .participant-tile {
4497
+ background: rgba(255, 255, 255, 0.1);
4498
+ border-radius: 8px;
4499
+ padding: 12px;
4500
+ margin: 8px 0;
4501
+ }
4502
+ `]
4503
+ })
4504
+ export class CustomTemplateDemo {
4505
+ @ViewChild('customMainGridTemplate') customMainGridTemplate!: TemplateRef<any>;
4506
+ @ViewChild('customAlertTemplate') customAlertTemplate!: TemplateRef<any>;
4507
+
4508
+ streams: any[] = [];
4509
+ showAlert = false;
4510
+ alertMessage = '';
4511
+
4512
+ closeAlert() {
4513
+ this.showAlert = false;
4514
+ }
4515
+ }
4516
+ ```
4517
+
4518
+ ### 3. Component Replacement with UI Overrides
4519
+
4520
+ Use the `uiOverrides` system to completely replace MediaSFU components with your own:
4521
+
4522
+ ```typescript
4523
+ import { Component, Type } from '@angular/core';
4524
+ import { MediasfuUICustomOverrides } from 'mediasfu-angular';
4525
+
4526
+ // Your custom replacement components
4527
+ @Component({
4528
+ selector: 'app-my-custom-video-card',
4529
+ template: `
4530
+ <div class="premium-video-card">
4531
+ <video [srcObject]="videoStream" autoplay></video>
4532
+ <div class="overlay">
4533
+ <span class="name">{{ participant.name }}</span>
4534
+ <button class="pin-btn" (click)="togglePin()">📌</button>
4535
+ </div>
4536
+ </div>
4537
+ `,
4538
+ styles: [`
4539
+ .premium-video-card {
4540
+ position: relative;
4541
+ border-radius: 16px;
4542
+ overflow: hidden;
4543
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
4544
+ }
4545
+ .overlay {
4546
+ position: absolute;
4547
+ bottom: 0;
4548
+ left: 0;
4549
+ right: 0;
4550
+ background: linear-gradient(transparent, rgba(0,0,0,0.8));
4551
+ padding: 12px;
4552
+ display: flex;
4553
+ justify-content: space-between;
4554
+ align-items: center;
4555
+ }
4556
+ `]
4557
+ })
4558
+ export class MyCustomVideoCard {
4559
+ // Your custom implementation
4560
+ }
4561
+
4562
+ @Component({
4563
+ selector: 'app-my-custom-control-buttons',
4564
+ template: `
4565
+ <div class="modern-controls">
4566
+ <button class="control-btn mic" [class.active]="!isMuted" (click)="toggleMic()">
4567
+ <i class="icon-mic"></i>
4568
+ </button>
4569
+ <button class="control-btn camera" [class.active]="!isVideoOff" (click)="toggleVideo()">
4570
+ <i class="icon-camera"></i>
4571
+ </button>
4572
+ <button class="control-btn screen" (click)="toggleScreen()">
4573
+ <i class="icon-screen"></i>
4574
+ </button>
4575
+ <button class="control-btn leave danger" (click)="leaveMeeting()">
4576
+ <i class="icon-leave"></i>
4577
+ </button>
4578
+ </div>
4579
+ `,
4580
+ styles: [`
4581
+ .modern-controls {
4582
+ display: flex;
4583
+ gap: 12px;
4584
+ padding: 16px;
4585
+ background: rgba(0, 0, 0, 0.8);
4586
+ border-radius: 24px;
4587
+ }
4588
+ .control-btn {
4589
+ width: 48px;
4590
+ height: 48px;
4591
+ border-radius: 50%;
4592
+ border: none;
4593
+ cursor: pointer;
4594
+ transition: all 0.2s;
4595
+ }
4596
+ .control-btn.active {
4597
+ background: #4CAF50;
4598
+ color: white;
4599
+ }
4600
+ .control-btn.danger {
4601
+ background: #f44336;
4602
+ color: white;
4603
+ }
4604
+ `]
4605
+ })
4606
+ export class MyCustomControlButtons {
4607
+ // Your custom implementation
4608
+ }
4609
+
4610
+ @Component({
4611
+ selector: 'app-meeting-room',
4612
+ template: `
4613
+ <app-mediasfu-generic
4614
+ [credentials]="credentials"
4615
+ [uiOverrides]="customUIOverrides"
4616
+ [returnUI]="false">
4617
+ </app-mediasfu-generic>
4618
+ `
4619
+ })
4620
+ export class MeetingRoomComponent {
4621
+ credentials = { apiUserName: 'user', apiKey: 'key' };
4622
+
4623
+ // Define your UI overrides
4624
+ customUIOverrides: Partial<MediasfuUICustomOverrides> = {
4625
+ // Replace video cards
4626
+ VideoCard: MyCustomVideoCard as Type<any>,
4627
+
4628
+ // Replace control buttons
4629
+ ControlButtonsComponent: MyCustomControlButtons as Type<any>,
4630
+
4631
+ // Replace modals
4632
+ ParticipantsModal: MyCustomParticipantsModal as Type<any>,
4633
+
4634
+ // Replace other display components
4635
+ MainGrid: MyCustomMainGrid as Type<any>,
4636
+ FlexibleGrid: MyCustomFlexibleGrid as Type<any>,
4637
+
4638
+ // ... any other components you want to replace
4639
+ };
4640
+ }
4641
+ ```
4642
+
4643
+ ### 4. Using WithOverrideDirective
4644
+
4645
+ The `*appWithOverride` directive enables conditional component replacement:
4646
+
4647
+ ```typescript
4648
+ import { Component } from '@angular/core';
4649
+ import { WithOverrideDirective } from 'mediasfu-angular';
4650
+
4651
+ @Component({
4652
+ selector: 'app-conditional-override',
4653
+ imports: [WithOverrideDirective, /* other imports */],
4654
+ template: `
4655
+ <!-- Use default or custom component based on condition -->
4656
+ <app-video-card
4657
+ *appWithOverride="useCustomCard ? MyCustomVideoCard : null"
4658
+ [participant]="currentParticipant">
4659
+ </app-video-card>
4660
+
4661
+ <!-- Override with custom component when premium feature enabled -->
4662
+ <app-control-buttons
4663
+ *appWithOverride="isPremiumUser ? PremiumControlButtons : null">
4664
+ </app-control-buttons>
4665
+ `
4666
+ })
4667
+ export class ConditionalOverrideComponent {
4668
+ useCustomCard = false;
4669
+ isPremiumUser = false;
4670
+
4671
+ MyCustomVideoCard = MyCustomVideoCard;
4672
+ PremiumControlButtons = PremiumControlButtons;
4673
+ }
4674
+ ```
4675
+
4676
+ ### 5. Complete Example: Themed Meeting Room
4677
+
4678
+ Here's a comprehensive example combining all customization approaches:
4679
+
4680
+ ```typescript
4681
+ import { Component, TemplateRef, ViewChild, Type } from '@angular/core';
4682
+ import { MediasfuUICustomOverrides } from 'mediasfu-angular';
4683
+
4684
+ @Component({
4685
+ selector: 'app-themed-meeting-room',
4686
+ template: `
4687
+ <!-- Custom alert template -->
4688
+ <ng-template #brandedAlertTemplate let-message="message">
4689
+ <div class="branded-alert">
4690
+ <img src="/assets/logo.png" alt="Logo" class="alert-logo">
4691
+ <p>{{ message }}</p>
4692
+ </div>
4693
+ </ng-template>
4694
+
4695
+ <app-mediasfu-conference
4696
+ [credentials]="credentials"
4697
+ [returnUI]="true"
4698
+ [uiOverrides]="themeOverrides"
4699
+ [containerStyle]="meetingContainerStyle">
4700
+
4701
+ <!-- Customize individual components -->
4702
+ <app-main-grid
4703
+ [containerStyle]="gridStyle"
4704
+ [customTemplate]="customGridTemplate">
4705
+ </app-main-grid>
4706
+
4707
+ <app-control-buttons-component
4708
+ [containerStyle]="controlsStyle">
4709
+ </app-control-buttons-component>
4710
+
4711
+ <app-participants-modal
4712
+ [overlayStyle]="modalOverlayStyle"
4713
+ [contentStyle]="modalContentStyle">
4714
+ </app-participants-modal>
4715
+
4716
+ <app-alert-component
4717
+ [customTemplate]="brandedAlertTemplate">
4718
+ </app-alert-component>
4719
+ </app-mediasfu-conference>
4720
+ `,
4721
+ styles: [`
4722
+ .branded-alert {
4723
+ display: flex;
4724
+ align-items: center;
4725
+ gap: 12px;
4726
+ padding: 16px;
4727
+ background: white;
4728
+ border-left: 4px solid #007bff;
4729
+ }
4730
+ `]
4731
+ })
4732
+ export class ThemedMeetingRoomComponent {
4733
+ @ViewChild('brandedAlertTemplate') brandedAlertTemplate!: TemplateRef<any>;
4734
+
4735
+ credentials = {
4736
+ apiUserName: 'your-api-username',
4737
+ apiKey: 'your-api-key'
4738
+ };
4739
+
4740
+ // Container styling
4741
+ meetingContainerStyle: Partial<CSSStyleDeclaration> = {
4742
+ backgroundColor: '#0f0f0f',
4743
+ fontFamily: 'Inter, system-ui, sans-serif'
4744
+ };
4745
+
4746
+ // Grid styling
4747
+ gridStyle: Partial<CSSStyleDeclaration> = {
4748
+ display: 'grid',
4749
+ gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
4750
+ gap: '16px',
4751
+ padding: '20px'
4752
+ };
4753
+
4754
+ // Controls styling
4755
+ controlsStyle: Partial<CSSStyleDeclaration> = {
4756
+ position: 'fixed',
4757
+ bottom: '24px',
4758
+ left: '50%',
4759
+ transform: 'translateX(-50%)',
4760
+ backgroundColor: 'rgba(0, 0, 0, 0.9)',
4761
+ borderRadius: '32px',
4762
+ padding: '12px 24px'
4763
+ };
4764
+
4765
+ // Modal styling
4766
+ modalOverlayStyle: Partial<CSSStyleDeclaration> = {
4767
+ backgroundColor: 'rgba(0, 0, 0, 0.85)',
4768
+ backdropFilter: 'blur(10px)'
4769
+ };
4770
+
4771
+ modalContentStyle: Partial<CSSStyleDeclaration> = {
4772
+ backgroundColor: '#1a1a1a',
4773
+ color: '#ffffff',
4774
+ borderRadius: '16px',
4775
+ border: '1px solid #333'
4776
+ };
4777
+
4778
+ // Component overrides
4779
+ themeOverrides: Partial<MediasfuUICustomOverrides> = {
4780
+ VideoCard: BrandedVideoCard as Type<any>,
4781
+ ControlButtonsComponent: ModernControls as Type<any>
4782
+ };
4783
+ }
4784
+ ```
4785
+
4786
+ ### Customizable Components Reference
4787
+
4788
+ #### Display Components
4789
+ - `MainContainer` - Main viewport container
4790
+ - `MainAspect` - Aspect ratio container
4791
+ - `MainScreen` - Screen share display
4792
+ - `MainGrid` - Primary participant grid
4793
+ - `OtherGrid` - Secondary participant grid
4794
+ - `SubAspect` - Sub-aspect ratio container
4795
+ - `FlexibleGrid` - Flexible layout grid
4796
+ - `AudioGrid` - Audio-only participants grid
4797
+
4798
+ Each accepts: `containerStyle?: Partial<CSSStyleDeclaration>`, `customTemplate?: TemplateRef<any>`
4799
+
4800
+ #### Modal Components
4801
+ - `LoadingModal` - Loading indicator
4802
+ - `ConfirmExitModal` - Exit confirmation
4803
+ - `ConfirmHereModal` - Presence confirmation
4804
+ - `ShareEventModal` - Event sharing
4805
+ - `AlertComponent` - Alert notifications
4806
+ - `MenuModal` - Main menu
4807
+ - `ParticipantsModal` - Participants list
4808
+ - `RecordingModal` - Recording controls
4809
+ - `RequestsModal` - Media requests
4810
+ - `WaitingRoomModal` - Waiting room management
4811
+ - `CoHostModal` - Co-host management
4812
+ - `DisplaySettingsModal` - Display settings
4813
+ - `EventSettingsModal` - Event settings
4814
+ - `MediaSettingsModal` - Media device settings
4815
+ - `MessagesModal` - Chat messages
4816
+ - `PollModal` - Polls interface
4817
+ - `BackgroundModal` - Background effects
4818
+ - `BreakoutRoomsModal` - Breakout rooms
4819
+ - `ConfigureWhiteboardModal` - Whiteboard settings
4820
+ - `ScreenboardModal` - Screen annotation
4821
+
4822
+ Each accepts: `overlayStyle?: Partial<CSSStyleDeclaration>`, `contentStyle?: Partial<CSSStyleDeclaration>`, `customTemplate?: TemplateRef<any>`
4823
+
4824
+ ### Best Practices
4825
+
4826
+ 1. **Type Safety**: Always use `Partial<CSSStyleDeclaration>` for style properties
4827
+ 2. **Template Context**: Ensure your custom templates accept the correct context variables
4828
+ 3. **Component Lifecycle**: Custom replacement components should implement the same interface as the original
4829
+ 4. **Performance**: Avoid inline style objects in templates; define them in the component class
4830
+ 5. **Responsive Design**: Use CSS Grid and Flexbox for responsive layouts
4831
+ 6. **Accessibility**: Maintain ARIA attributes and keyboard navigation in custom components
4832
+ 7. **Testing**: Test custom components in isolation before integration
4833
+
4834
+ ---
4835
+
4005
4836
  # API Reference <a name="api-reference"></a>
4006
4837
 
4007
4838
  For detailed information on the API methods and usage, please refer to the [MediaSFU API Documentation](https://mediasfu.com/developers).