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.
- package/README.md +832 -1
- package/dist/README.md +832 -1
- package/dist/fesm2022/mediasfu-angular.mjs +9284 -4188
- package/dist/fesm2022/mediasfu-angular.mjs.map +1 -1
- package/dist/lib/@types/types.d.ts +6 -1
- package/dist/lib/@types/ui-overrides.types.d.ts +310 -0
- package/dist/lib/components/background-components/background-modal/background-modal.component.d.ts +1023 -2
- package/dist/lib/components/breakout-components/breakout-rooms-modal.component.d.ts +1069 -45
- package/dist/lib/components/breakout-components/edit-room-modal/edit-room-modal.component.d.ts +1054 -42
- package/dist/lib/components/co-host-components/co-host-modal/co-host-modal.component.d.ts +1067 -56
- package/dist/lib/components/display-components/alert-component/alert.component.component.d.ts +80 -24
- package/dist/lib/components/display-components/audio-grid/audio-grid.component.d.ts +83 -11
- package/dist/lib/components/display-components/flexible-grid/flexible-grid.component.d.ts +96 -33
- package/dist/lib/components/display-components/loading-modal/loading-modal.component.d.ts +16 -26
- package/dist/lib/components/display-components/main-aspect-component/main-aspect-component.component.d.ts +6 -2
- package/dist/lib/components/display-components/main-container-component/main-container-component.component.d.ts +6 -2
- package/dist/lib/components/display-components/main-grid-component/main-grid-component.component.d.ts +7 -13
- package/dist/lib/components/display-components/main-screen-component/main-screen-component.component.d.ts +508 -7
- package/dist/lib/components/display-components/other-grid-component/other-grid-component.component.d.ts +7 -1
- package/dist/lib/components/display-components/sub-aspect-component/sub-aspect-component.component.d.ts +7 -2
- package/dist/lib/components/display-settings-components/display-settings-modal.component.d.ts +1107 -27
- package/dist/lib/components/event-settings-components/event-settings-modal/event-settings-modal.component.d.ts +1134 -49
- package/dist/lib/components/exit-components/confirm-exit-modal/confirm-exit-modal.component.d.ts +94 -32
- package/dist/lib/components/media-settings-components/media-settings-modal/media-settings-modal.component.d.ts +1123 -47
- package/dist/lib/components/mediasfu-components/mediasfu-broadcast.component.d.ts +24914 -73
- package/dist/lib/components/mediasfu-components/mediasfu-chat.component.d.ts +224 -73
- package/dist/lib/components/mediasfu-components/mediasfu-conference.component.d.ts +18068 -93
- package/dist/lib/components/mediasfu-components/mediasfu-generic.component.d.ts +56280 -93
- package/dist/lib/components/mediasfu-components/mediasfu-webinar.component.d.ts +20785 -93
- package/dist/lib/components/menu-components/custom-buttons/custom-buttons.component.d.ts +23 -4
- package/dist/lib/components/menu-components/meeting-id-component/meeting-id-component.component.d.ts +78 -1
- package/dist/lib/components/menu-components/meeting-passcode-component/meeting-passcode-component.component.d.ts +37 -1
- package/dist/lib/components/menu-components/menu-modal/menu-modal.component.d.ts +689 -9
- package/dist/lib/components/menu-components/share-buttons-component/share-buttons-component.component.d.ts +46 -2
- package/dist/lib/components/message-components/messages-modal/messages-modal.component.d.ts +76 -13
- package/dist/lib/components/misc-components/confirm-here-modal/confirm-here-modal.component.d.ts +1113 -17
- package/dist/lib/components/misc-components/share-event-modal/share-event-modal.component.d.ts +1114 -29
- package/dist/lib/components/participants-components/participants-modal/participants-modal.component.d.ts +1084 -6
- package/dist/lib/components/polls-components/poll-modal/poll-modal.component.d.ts +1060 -21
- package/dist/lib/components/recording-components/recording-modal/recording-modal.component.d.ts +1054 -35
- package/dist/lib/components/requests-components/requests-modal/requests-modal.component.d.ts +1117 -45
- package/dist/lib/components/screenboard-components/screenboard-modal/screenboard-modal.component.d.ts +1059 -47
- package/dist/lib/components/waiting-components/waiting-room-modal.component.d.ts +1119 -46
- package/dist/lib/components/whiteboard-components/configure-whiteboard-modal/configure-whiteboard-modal.component.d.ts +1049 -16
- package/dist/lib/consumers/add-videos-grid.service.d.ts +3 -0
- package/dist/lib/consumers/connect-ips.service.d.ts +3 -1
- package/dist/lib/consumers/connect-recv-transport.service.d.ts +4 -1
- package/dist/lib/consumers/connect-send-transport-audio.service.d.ts +5 -1
- package/dist/lib/consumers/connect-send-transport-screen.service.d.ts +6 -1
- package/dist/lib/consumers/connect-send-transport-video.service.d.ts +6 -1
- package/dist/lib/consumers/connect-send-transport.service.d.ts +3 -1
- package/dist/lib/consumers/consumer-resume.service.d.ts +2 -1
- package/dist/lib/consumers/create-send-transport.service.d.ts +4 -1
- package/dist/lib/consumers/disconnect-send-transport-audio.service.d.ts +3 -1
- package/dist/lib/consumers/disconnect-send-transport-screen.service.d.ts +3 -1
- package/dist/lib/consumers/disconnect-send-transport-video.service.d.ts +3 -1
- package/dist/lib/consumers/prepopulate-user-media.service.d.ts +3 -0
- package/dist/lib/consumers/resume-send-transport-audio.service.d.ts +3 -1
- package/dist/lib/consumers/signal-new-consumer-transport.service.d.ts +3 -1
- package/dist/lib/consumers/socket-receive-methods/join-consume-room.service.d.ts +3 -1
- package/dist/lib/consumers/socket-receive-methods/new-pipe-producer.service.d.ts +3 -1
- package/dist/lib/consumers/stream-success-audio-switch.service.d.ts +5 -1
- package/dist/lib/consumers/stream-success-audio.service.d.ts +3 -1
- package/dist/lib/consumers/stream-success-video.service.d.ts +5 -1
- package/dist/lib/directives/with-override.directive.d.ts +76 -0
- package/dist/lib/methods/utils/initial-values.util.d.ts +7 -2
- package/dist/lib/methods/utils/mini-audio-player/mini-audio-player.component.d.ts +3 -1
- package/dist/lib/methods/utils/producer/a-params.service.d.ts +4 -1
- package/dist/lib/methods/utils/producer/h-params.service.d.ts +4 -1
- package/dist/lib/methods/utils/producer/screen-params.service.d.ts +4 -1
- package/dist/lib/methods/utils/producer/v-params.service.d.ts +4 -1
- package/dist/lib/methods/whiteboard-methods/capture-canvas-stream.service.d.ts +3 -1
- package/dist/lib/producer-client/producer-client-emits/create-device-client.service.d.ts +4 -1
- package/dist/lib/producer-client/producer-client-emits/update-room-parameters-client.service.d.ts +3 -1
- package/dist/lib/producers/producer-emits/join-con-room.service.d.ts +3 -1
- package/dist/lib/producers/socket-receive-methods/get-domains.service.d.ts +3 -1
- package/dist/lib/services/ui-override-resolver.service.d.ts +91 -0
- package/dist/public-api.d.ts +4 -0
- 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).
|