@pecb-ui/components 1.1.10 → 1.1.11
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 +257 -70
- package/data-display/index.d.ts +1 -1
- package/fesm2022/pecb-ui-components-data-display.mjs +2 -2
- package/fesm2022/pecb-ui-components-data-display.mjs.map +1 -1
- package/fesm2022/pecb-ui-components.mjs +1818 -5
- package/fesm2022/pecb-ui-components.mjs.map +1 -1
- package/index.d.ts +834 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,21 +49,21 @@ This library requires the following peer dependencies:
|
|
|
49
49
|
|
|
50
50
|
```typescript
|
|
51
51
|
// app.module.ts
|
|
52
|
-
import { NgModule } from
|
|
53
|
-
import { BrowserModule } from
|
|
54
|
-
import { PecbComponentsModule } from
|
|
52
|
+
import { NgModule } from "@angular/core";
|
|
53
|
+
import { BrowserModule } from "@angular/platform-browser";
|
|
54
|
+
import { PecbComponentsModule } from "@pecb-ui/components";
|
|
55
55
|
|
|
56
|
-
import { AppComponent } from
|
|
56
|
+
import { AppComponent } from "./app.component";
|
|
57
57
|
|
|
58
58
|
@NgModule({
|
|
59
59
|
declarations: [AppComponent],
|
|
60
60
|
imports: [
|
|
61
61
|
BrowserModule,
|
|
62
|
-
PecbComponentsModule
|
|
62
|
+
PecbComponentsModule, // Import the PECB UI components module
|
|
63
63
|
],
|
|
64
|
-
bootstrap: [AppComponent]
|
|
64
|
+
bootstrap: [AppComponent],
|
|
65
65
|
})
|
|
66
|
-
export class AppModule {
|
|
66
|
+
export class AppModule {}
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
### 2. Import Global Styles (Optional)
|
|
@@ -72,15 +72,15 @@ If you want to use the PECB design system variables in your application:
|
|
|
72
72
|
|
|
73
73
|
```scss
|
|
74
74
|
// styles.scss
|
|
75
|
-
@import
|
|
75
|
+
@import "@pecb-ui/components/styles/main";
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
Or import specific abstracts:
|
|
79
79
|
|
|
80
80
|
```scss
|
|
81
81
|
// In your component SCSS
|
|
82
|
-
@import
|
|
83
|
-
@import
|
|
82
|
+
@import "@pecb-ui/components/styles/abstracts/variables";
|
|
83
|
+
@import "@pecb-ui/components/styles/abstracts/mixins";
|
|
84
84
|
|
|
85
85
|
.my-component {
|
|
86
86
|
color: $primary-color;
|
|
@@ -93,9 +93,7 @@ Or import specific abstracts:
|
|
|
93
93
|
|
|
94
94
|
```html
|
|
95
95
|
<!-- app.component.html -->
|
|
96
|
-
<pecb-button variant="primary" size="medium" (clicked)="handleClick()">
|
|
97
|
-
Click Me
|
|
98
|
-
</pecb-button>
|
|
96
|
+
<pecb-button variant="primary" size="medium" (clicked)="handleClick()"> Click Me </pecb-button>
|
|
99
97
|
|
|
100
98
|
<pecb-card elevation="md">
|
|
101
99
|
<pecb-card-header>
|
|
@@ -115,67 +113,49 @@ A versatile button component with multiple variants, sizes, and accessibility fe
|
|
|
115
113
|
|
|
116
114
|
```html
|
|
117
115
|
<!-- Basic button -->
|
|
118
|
-
<pecb-button variant="primary" (clicked)="onClick()">
|
|
119
|
-
Submit
|
|
120
|
-
</pecb-button>
|
|
116
|
+
<pecb-button variant="primary" (clicked)="onClick()"> Submit </pecb-button>
|
|
121
117
|
|
|
122
118
|
<!-- With loading state -->
|
|
123
|
-
<pecb-button variant="primary" [loading]="isLoading">
|
|
124
|
-
Save
|
|
125
|
-
</pecb-button>
|
|
119
|
+
<pecb-button variant="primary" [loading]="isLoading"> Save </pecb-button>
|
|
126
120
|
|
|
127
121
|
<!-- Disabled button -->
|
|
128
|
-
<pecb-button variant="danger" [disabled]="true">
|
|
129
|
-
Delete
|
|
130
|
-
</pecb-button>
|
|
122
|
+
<pecb-button variant="danger" [disabled]="true"> Delete </pecb-button>
|
|
131
123
|
|
|
132
124
|
<!-- Full width button -->
|
|
133
|
-
<pecb-button variant="success" [fullWidth]="true">
|
|
134
|
-
Continue
|
|
135
|
-
</pecb-button>
|
|
125
|
+
<pecb-button variant="success" [fullWidth]="true"> Continue </pecb-button>
|
|
136
126
|
|
|
137
127
|
<!-- Icon button with accessibility label -->
|
|
138
|
-
<pecb-button variant="secondary" ariaLabel="Close dialog" iconLeft="✕">
|
|
139
|
-
</pecb-button>
|
|
128
|
+
<pecb-button variant="secondary" ariaLabel="Close dialog" iconLeft="✕"> </pecb-button>
|
|
140
129
|
|
|
141
130
|
<!-- Toggle button -->
|
|
142
|
-
<pecb-button variant="secondary" [ariaPressed]="isActive" (clicked)="toggle()">
|
|
143
|
-
Toggle
|
|
144
|
-
</pecb-button>
|
|
131
|
+
<pecb-button variant="secondary" [ariaPressed]="isActive" (clicked)="toggle()"> Toggle </pecb-button>
|
|
145
132
|
|
|
146
133
|
<!-- Button that controls a dropdown -->
|
|
147
|
-
<pecb-button
|
|
148
|
-
variant="primary"
|
|
149
|
-
[ariaExpanded]="isOpen"
|
|
150
|
-
ariaHasPopup="menu"
|
|
151
|
-
ariaControls="dropdown-menu"
|
|
152
|
-
(clicked)="toggleDropdown()">
|
|
153
|
-
Menu
|
|
154
|
-
</pecb-button>
|
|
134
|
+
<pecb-button variant="primary" [ariaExpanded]="isOpen" ariaHasPopup="menu" ariaControls="dropdown-menu" (clicked)="toggleDropdown()"> Menu </pecb-button>
|
|
155
135
|
```
|
|
156
136
|
|
|
157
137
|
**Properties:**
|
|
158
138
|
|
|
159
|
-
| Property
|
|
160
|
-
|
|
161
|
-
| `variant`
|
|
162
|
-
| `size`
|
|
163
|
-
| `disabled`
|
|
164
|
-
| `loading`
|
|
165
|
-
| `fullWidth`
|
|
166
|
-
| `type`
|
|
167
|
-
| `iconLeft`
|
|
168
|
-
| `iconRight`
|
|
169
|
-
| `ariaLabel`
|
|
170
|
-
| `ariaExpanded` | `boolean`
|
|
171
|
-
| `ariaPressed`
|
|
172
|
-
| `ariaHasPopup` | `boolean \| 'menu' \| 'listbox' \| 'tree' \| 'grid' \| 'dialog'`
|
|
173
|
-
| `ariaControls` | `string`
|
|
139
|
+
| Property | Type | Default | Description |
|
|
140
|
+
| -------------- | ------------------------------------------------------------------------------------ | ----------- | ----------------------------------- |
|
|
141
|
+
| `variant` | `'primary' \| 'secondary' \| 'success' \| 'danger' \| 'warning' \| 'info' \| 'text'` | `'primary'` | Visual style variant |
|
|
142
|
+
| `size` | `'small' \| 'medium' \| 'large'` | `'medium'` | Button size |
|
|
143
|
+
| `disabled` | `boolean` | `false` | Disable the button |
|
|
144
|
+
| `loading` | `boolean` | `false` | Show loading spinner |
|
|
145
|
+
| `fullWidth` | `boolean` | `false` | Make button full width |
|
|
146
|
+
| `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | HTML button type |
|
|
147
|
+
| `iconLeft` | `string` | - | Icon before text |
|
|
148
|
+
| `iconRight` | `string` | - | Icon after text |
|
|
149
|
+
| `ariaLabel` | `string` | - | Accessible label |
|
|
150
|
+
| `ariaExpanded` | `boolean` | - | ARIA expanded state |
|
|
151
|
+
| `ariaPressed` | `boolean` | - | ARIA pressed state (toggle buttons) |
|
|
152
|
+
| `ariaHasPopup` | `boolean \| 'menu' \| 'listbox' \| 'tree' \| 'grid' \| 'dialog'` | - | Popup type |
|
|
153
|
+
| `ariaControls` | `string` | - | ID of controlled element |
|
|
174
154
|
|
|
175
155
|
**Events:**
|
|
176
156
|
|
|
177
|
-
| Event
|
|
178
|
-
|
|
157
|
+
| Event | Type | Description |
|
|
158
|
+
| --------- | -------------------------- | ----------------------- |
|
|
179
159
|
| `clicked` | `EventEmitter<MouseEvent>` | Emitted on button click |
|
|
180
160
|
|
|
181
161
|
### Card Component
|
|
@@ -223,15 +203,218 @@ A container component for displaying content with optional header, body, and foo
|
|
|
223
203
|
|
|
224
204
|
**Properties:**
|
|
225
205
|
|
|
226
|
-
| Property
|
|
227
|
-
|
|
228
|
-
| `elevation`
|
|
229
|
-
| `hoverable`
|
|
230
|
-
| `noPadding`
|
|
231
|
-
| `role`
|
|
232
|
-
| `ariaLabel`
|
|
233
|
-
| `ariaLabelledBy`
|
|
234
|
-
| `ariaDescribedBy` | `string`
|
|
206
|
+
| Property | Type | Default | Description |
|
|
207
|
+
| ----------------- | ---------------------------------------------------------- | -------- | ------------------------ |
|
|
208
|
+
| `elevation` | `'none' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Shadow depth |
|
|
209
|
+
| `hoverable` | `boolean` | `false` | Enable hover effect |
|
|
210
|
+
| `noPadding` | `boolean` | `false` | Remove default padding |
|
|
211
|
+
| `role` | `'article' \| 'region' \| 'group' \| 'listitem' \| 'none'` | `'none'` | Semantic role |
|
|
212
|
+
| `ariaLabel` | `string` | - | Accessible label |
|
|
213
|
+
| `ariaLabelledBy` | `string` | - | ID of labelling element |
|
|
214
|
+
| `ariaDescribedBy` | `string` | - | ID of describing element |
|
|
215
|
+
|
|
216
|
+
### Video Player Component
|
|
217
|
+
|
|
218
|
+
The PECB course video player — a fully custom-skinned, accessible HTML5 `<video>` wrapper
|
|
219
|
+
that reproduces the _Course Player — Content Redesign_ stage: rounded dark 16:9 surface,
|
|
220
|
+
poster, brand watermark + section label, centre play button and a bottom control bar
|
|
221
|
+
(seek bar, play/pause, rewind, volume, time, captions, playback-speed settings, fullscreen).
|
|
222
|
+
|
|
223
|
+
It is standalone (no icon-registry or service dependencies), responsive through container
|
|
224
|
+
queries (it adapts to the width of its slot, not the viewport), keyboard operable, touch
|
|
225
|
+
friendly and themable through CSS custom properties — so it can be dropped into any Angular
|
|
226
|
+
17+ project.
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
import { VideoPlayerComponent } from "@pecb-ui/components";
|
|
230
|
+
// or: import { VideoPlayerComponent } from '@pecb-ui/components/data-display';
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```html
|
|
234
|
+
<!-- Minimal -->
|
|
235
|
+
<pecb-video-player src="https://cdn.example.com/lesson.mp4" poster="https://cdn.example.com/lesson.jpg" title="Introduction to management systems — Part 3" label="SECTION 2"> </pecb-video-player>
|
|
236
|
+
|
|
237
|
+
<!-- Multiple sources + captions -->
|
|
238
|
+
<pecb-video-player [src]="[{ src: 'lesson.webm', type: 'video/webm' }, { src: 'lesson.mp4', type: 'video/mp4' }]" [tracks]="[{ src: 'lesson.en.vtt', srclang: 'en', label: 'English', default: true }]" crossOrigin="anonymous" label="SECTION 2"> </pecb-video-player>
|
|
239
|
+
|
|
240
|
+
<!-- Driven from outside (transcript / lesson list) with two-way bindings -->
|
|
241
|
+
<pecb-video-player [src]="lesson.src" [(playing)]="playing" [(currentTime)]="at" [(captionsEnabled)]="captions" (playbackEnded)="markLessonComplete()" (timeUpdate)="saveProgress($event.currentTime)"> </pecb-video-player>
|
|
242
|
+
|
|
243
|
+
<!-- Project custom overlays (quiz, end-screen…) on top of the stage -->
|
|
244
|
+
<pecb-video-player [src]="src">
|
|
245
|
+
<div pecbVideoOverlay class="my-quiz-overlay">…</div>
|
|
246
|
+
</pecb-video-player>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Properties:**
|
|
250
|
+
|
|
251
|
+
| Property | Type | Default | Description |
|
|
252
|
+
| ---------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------ | ---------------------------------------------------------- |
|
|
253
|
+
| `src` | `string \| VideoPlayerSource[]` | – | Media URL or list of `<source>` candidates |
|
|
254
|
+
| `poster` | `string` | – | Poster image |
|
|
255
|
+
| `tracks` | `VideoPlayerTrack[]` | `[]` | Caption/subtitle tracks (CC button appears when non-empty) |
|
|
256
|
+
| `title` | `string` | – | Accessible title (part of the region label) |
|
|
257
|
+
| `crossOrigin` | `'anonymous' \| 'use-credentials'` | – | Needed for cross-origin caption files |
|
|
258
|
+
| `preload` | `'none' \| 'metadata' \| 'auto'` | `'metadata'` | Preload hint |
|
|
259
|
+
| `autoplay` / `loop` / `playsInline` | `boolean` | `false` / `false` / `true` | Native media flags |
|
|
260
|
+
| `startTime` | `number` | `0` | Initial position in seconds |
|
|
261
|
+
| `watermark` | `string` | `'PECB'` | Bottom-left brand mark (`''` hides it) |
|
|
262
|
+
| `label` | `string` | – | Bottom-right label, e.g. `SECTION 2` |
|
|
263
|
+
| `aspectRatio` | `string` | `'16 / 9'` | CSS aspect ratio of the stage |
|
|
264
|
+
| `seekStep` | `number` | `10` | Seconds for rewind button / arrow keys |
|
|
265
|
+
| `playbackRates` | `number[]` | `[0.5, 0.75, 1, 1.25, 1.5, 2]` | Entries of the speed menu |
|
|
266
|
+
| `showCenterButton`, `showSkipBack`, `showVolume`, `showTime`, `showSettings`, `showFullscreen` | `boolean` | `true` | Toggle individual controls |
|
|
267
|
+
| `showCaptions` | `boolean \| undefined` | `undefined` | Force the CC button on/off (auto by default) |
|
|
268
|
+
| `labels` | `Partial<VideoPlayerLabels>` | `{}` | Override user-visible strings (i18n) |
|
|
269
|
+
|
|
270
|
+
**Two-way models** (`[(…)]`): `playing`, `currentTime`, `volume`, `muted`, `playbackRate`, `captionsEnabled`.
|
|
271
|
+
|
|
272
|
+
**Outputs:** `timeUpdate`, `loadedMetadata`, `seekEnd` (`VideoPlayerTimeEvent`), `playbackEnded`,
|
|
273
|
+
`fullscreenChange` (`boolean`), `playerError` (`VideoPlayerError`) — plus the `…Change` output of every model.
|
|
274
|
+
|
|
275
|
+
**Public methods:** `play()`, `pause()`, `togglePlay()`, `seek(s)`, `seekBy(Δs)`, `skipBack()`,
|
|
276
|
+
`toggleMute()`, `setVolume(v)`, `setPlaybackRate(r)`, `toggleCaptions()`, `toggleFullscreen()`.
|
|
277
|
+
|
|
278
|
+
**Keyboard:** `Space`/`K` play-pause · `←`/`→` or `J`/`L` seek ±`seekStep` · `↑`/`↓` volume ·
|
|
279
|
+
`M` mute · `C` captions · `F` fullscreen · `Home`/`End` · `Esc` closes the speed menu.
|
|
280
|
+
The seek bar is a `role="slider"` with arrow/Page/Home/End support.
|
|
281
|
+
|
|
282
|
+
**Theming** (CSS custom properties on the host):
|
|
283
|
+
|
|
284
|
+
```css
|
|
285
|
+
pecb-video-player {
|
|
286
|
+
--pecb-video-radius: 12px; /* stage corner radius */
|
|
287
|
+
--pecb-video-bg: #0b0b0d; /* stage background */
|
|
288
|
+
--pecb-video-accent: #fff; /* progress fill, knob, slider */
|
|
289
|
+
--pecb-video-controls-color: rgba(255, 255, 255, 0.92);
|
|
290
|
+
--pecb-video-font-display: "Plus Jakarta Sans", sans-serif;
|
|
291
|
+
--pecb-video-font-body: "Inter", sans-serif;
|
|
292
|
+
--pecb-video-focus-ring: #fff;
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Course Content Panel Component
|
|
297
|
+
|
|
298
|
+
The **Content sidebar** from the _Course Player — Content Redesign_ — the list that sits beside the
|
|
299
|
+
course video. It reproduces the design exactly: Content / Transcript tabs, lesson search, the
|
|
300
|
+
collapsible **Section** accordion (one section open at a time, auto-opening the section that owns
|
|
301
|
+
the active lesson), status discs (completed · now playing · in-progress ring · not started · locked),
|
|
302
|
+
quiz rows with badge and score, per-lesson progress bars, the connected "Part 1 / Part 2 …" rail for
|
|
303
|
+
multi-part lessons, and a searchable transcript with click-to-seek, live cue highlighting and an
|
|
304
|
+
autoscroll toggle.
|
|
305
|
+
|
|
306
|
+
It is standalone and data-driven — no player dependency — and sizes itself with container queries,
|
|
307
|
+
so it works in a 408px sidebar, a drawer or a phone-width column.
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
import { CourseContentPanelComponent } from "@pecb-ui/components";
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
```html
|
|
314
|
+
<pecb-course-content-panel [modules]="modules" [transcript]="cues" [(activeLessonId)]="lessonId" [playing]="playing()" [currentTime]="currentTime()" (lessonSelect)="openLesson($event)" (transcriptSeek)="player.seek($event)"> </pecb-course-content-panel>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
const modules: CourseModule[] = [
|
|
319
|
+
{
|
|
320
|
+
id: "m2",
|
|
321
|
+
title: "Introduction to management systems",
|
|
322
|
+
lessons: [
|
|
323
|
+
// A "Base — Part n" title makes the panel group consecutive lessons under one
|
|
324
|
+
// sub-heading and list them as Part 1, Part 2, … on a connected rail.
|
|
325
|
+
{ id: "l2", title: "Introduction … — Part 1", durationSeconds: 1204, status: "completed" },
|
|
326
|
+
{ id: "l3", title: "Introduction … — Part 2", durationSeconds: 925, status: "completed" },
|
|
327
|
+
{ id: "l4", title: "Introduction … — Part 3", durationSeconds: 612, status: "playing", resumeSeconds: 440, src: "lesson-3.mp4", poster: "lesson-3.jpg", stageLabel: "SECTION 2" },
|
|
328
|
+
{ id: "q1", type: "quiz", title: "Introduction …", questionCount: 5, correctCount: 4, status: "completed" },
|
|
329
|
+
],
|
|
330
|
+
},
|
|
331
|
+
];
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Properties:**
|
|
335
|
+
|
|
336
|
+
| Property | Type | Default | Description |
|
|
337
|
+
| ------------------------------------------------------------------ | ----------------------------------- | --------------- | -------------------------------------------------------------------------------------- |
|
|
338
|
+
| `modules` | `CourseModule[]` | `[]` | Course structure |
|
|
339
|
+
| `transcript` | `CourseTranscriptCue[]` | `[]` | Fallback cues (a lesson's own `transcript` wins) |
|
|
340
|
+
| `playing` | `boolean` | `false` | Live playback state — drives the "now playing" row |
|
|
341
|
+
| `currentTime` | `number` | – | Live playhead: highlights the transcript cue and draws live progress on the active row |
|
|
342
|
+
| `layout` | `'grouped' \| 'timeline'` | `'grouped'` | Section accordion, or one flat connected timeline |
|
|
343
|
+
| `density` | `'comfortable' \| 'compact'` | `'comfortable'` | Row spacing |
|
|
344
|
+
| `accent` | `'charcoal' \| 'red'` | `'charcoal'` | Colour of the "now playing" treatment |
|
|
345
|
+
| `showTabs`, `showSearch`, `showTranscriptSearch`, `showAutoscroll` | `boolean` | `true` | Toggle chrome |
|
|
346
|
+
| `showProgress` | `boolean` | `false` | Circular course-progress header + certificate pill |
|
|
347
|
+
| `showCertificate` | `boolean` | `true` | The pill inside that header |
|
|
348
|
+
| `soloSingleLessonModules` | `boolean` | `false` | Render one-lesson sections as direct-play rows |
|
|
349
|
+
| `labels` | `Partial<CourseContentPanelLabels>` | `{}` | Override user-visible strings (i18n) |
|
|
350
|
+
|
|
351
|
+
**Two-way models** (`[(…)]`): `activeLessonId`, `tab`, `openModuleId`, `autoscroll`, `query`, `transcriptQuery`.
|
|
352
|
+
|
|
353
|
+
**Outputs:** `lessonSelect` (`CourseLesson`), `transcriptSeek` (seconds), `moduleToggle`
|
|
354
|
+
(`{ module, open }`), `certificateClick`.
|
|
355
|
+
|
|
356
|
+
**Lesson status:** `completed` · `playing` · `started` · `available` · `locked`. Only the _active_
|
|
357
|
+
lesson can render as "now playing", and a `locked` lesson is disabled and not selectable.
|
|
358
|
+
|
|
359
|
+
**Accessibility:** tabs are a real `tablist` (arrow keys switch), section headers are
|
|
360
|
+
`aria-expanded` buttons with arrow/Home/End navigation, and collapsed sections are `inert`, so their
|
|
361
|
+
lessons stay out of the tab order.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
### Course Player Component
|
|
366
|
+
|
|
367
|
+
The video stage with the Content sidebar **attached** — the full design composition, ready to drop in.
|
|
368
|
+
|
|
369
|
+
It wires [`pecb-video-player`](#video-player-component) and `pecb-course-content-panel` together:
|
|
370
|
+
picking a lesson loads its media and resumes where it left off, clicking a transcript cue seeks the
|
|
371
|
+
video, and the sidebar follows playback live. Below ~900px of available width the two columns
|
|
372
|
+
collapse into a stacked layout (container queries — it also works inside a drawer or split view).
|
|
373
|
+
|
|
374
|
+
```ts
|
|
375
|
+
import { CoursePlayerComponent } from "@pecb-ui/components";
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
```html
|
|
379
|
+
<pecb-course-player [modules]="modules" [(activeLessonId)]="lessonId" [(playing)]="playing" [(currentTime)]="at" (lessonSelect)="track($event)" (lessonEnded)="markComplete($event)" (timeUpdate)="saveProgress($event.currentTime)"> </pecb-course-player>
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Properties:** `modules`, `transcript`, plus the video options `src`, `poster`, `tracks`,
|
|
383
|
+
`stageLabel` (all used as fallbacks when the active lesson doesn't carry its own), `watermark`,
|
|
384
|
+
`aspectRatio`, `preload`, `crossOrigin`, `seekStep`, `videoLabels`, `autoPlayOnSelect`,
|
|
385
|
+
`showLessonTitle`; and the panel options `panelPosition` (`'end' | 'start'`), `layout`, `density`,
|
|
386
|
+
`accent`, `showTabs`, `showSearch`, `showProgress`, `soloSingleLessonModules`, `panelLabels`.
|
|
387
|
+
|
|
388
|
+
**Two-way models:** `activeLessonId`, `playing`, `currentTime`, `panelTab`.
|
|
389
|
+
|
|
390
|
+
**Outputs:** `lessonSelect`, `lessonEnded`, `timeUpdate`, `certificateClick`, `playerError`.
|
|
391
|
+
|
|
392
|
+
**Layout hooks:**
|
|
393
|
+
|
|
394
|
+
```css
|
|
395
|
+
pecb-course-player {
|
|
396
|
+
--pecb-course-player-panel-width: 408px; /* side column width */
|
|
397
|
+
--pecb-course-player-gap: 20px; /* column gap */
|
|
398
|
+
--pecb-course-player-panel-stacked-height: 460px; /* panel height once stacked */
|
|
399
|
+
--pecb-course-player-radius: 12px; /* panel corner radius */
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Side by side, the sidebar takes its height from the video stage and scrolls internally — give the
|
|
404
|
+
player a height (or let the stage define it) and the columns stay aligned. Once stacked, the player
|
|
405
|
+
grows to fit, so don't pin it to a fixed height in that range.
|
|
406
|
+
|
|
407
|
+
**Theming** the panel (both components):
|
|
408
|
+
|
|
409
|
+
```css
|
|
410
|
+
pecb-course-content-panel {
|
|
411
|
+
--pecb-course-panel-accent: #a11e29; /* "now playing" colour */
|
|
412
|
+
--pecb-course-panel-bg: #fff;
|
|
413
|
+
--pecb-course-panel-border: #ececec;
|
|
414
|
+
--pecb-course-panel-font-display: "Plus Jakarta Sans", sans-serif;
|
|
415
|
+
--pecb-course-panel-font-body: "Inter", sans-serif;
|
|
416
|
+
}
|
|
417
|
+
```
|
|
235
418
|
|
|
236
419
|
## Services
|
|
237
420
|
|
|
@@ -370,8 +553,8 @@ import {
|
|
|
370
553
|
// Error handling
|
|
371
554
|
createError,
|
|
372
555
|
wrapError,
|
|
373
|
-
tryAsync
|
|
374
|
-
} from
|
|
556
|
+
tryAsync,
|
|
557
|
+
} from "@pecb-ui/components";
|
|
375
558
|
```
|
|
376
559
|
|
|
377
560
|
## Types & Interfaces
|
|
@@ -394,8 +577,8 @@ import {
|
|
|
394
577
|
// Service interfaces
|
|
395
578
|
NotificationConfig,
|
|
396
579
|
ThemeConfig,
|
|
397
|
-
LoadingState
|
|
398
|
-
} from
|
|
580
|
+
LoadingState,
|
|
581
|
+
} from "@pecb-ui/components";
|
|
399
582
|
```
|
|
400
583
|
|
|
401
584
|
## SCSS Design System
|
|
@@ -418,7 +601,11 @@ $spacing-lg: 24px;
|
|
|
418
601
|
$spacing-xl: 32px;
|
|
419
602
|
|
|
420
603
|
// Typography
|
|
421
|
-
$font-family-base:
|
|
604
|
+
$font-family-base:
|
|
605
|
+
"Inter",
|
|
606
|
+
-apple-system,
|
|
607
|
+
BlinkMacSystemFont,
|
|
608
|
+
sans-serif;
|
|
422
609
|
$font-size-sm: 0.875rem;
|
|
423
610
|
$font-size-md: 1rem;
|
|
424
611
|
$font-size-lg: 1.125rem;
|
|
@@ -433,7 +620,7 @@ $border-radius-lg: 12px;
|
|
|
433
620
|
|
|
434
621
|
```scss
|
|
435
622
|
// Responsive breakpoints
|
|
436
|
-
@include respond-to(
|
|
623
|
+
@include respond-to("md") {
|
|
437
624
|
// Styles for medium screens and up
|
|
438
625
|
}
|
|
439
626
|
|
package/data-display/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { CodeSnippetComponent, CodeSnippetTheme, CodeSnippetVariant, MediaComponent, MediaGroup, MediaItem, MediaSize, MediaType, MetricsCardBadgeStatus, MetricsCardComponent, MetricsCardIconBg, MetricsCardOrientation, MetricsCardType, MetricsCardVariation, NoteGroup, NoteItem, NotesPanelComponent, ProfileBadge, ProfileComponent, ProfileGroupComponent, ProfileGroupItem, ProfileGroupSize, ProfileIndicator, ProfileSize, TestimonialComponent, TestimonialData, TestimonialVariant, ToolbarBarComponent, ToolbarButton, ToolbarTab, ToolbarVariant } from '@pecb-ui/components';
|
|
1
|
+
export { CodeSnippetComponent, CodeSnippetTheme, CodeSnippetVariant, CourseContentPanelAccent, CourseContentPanelComponent, CourseContentPanelDensity, CourseContentPanelLabels, CourseContentPanelLayout, CourseContentPanelTab, CourseLesson, CourseLessonStatus, CourseLessonType, CourseModule, CourseModuleStats, CoursePlayerComponent, CoursePlayerPanelPosition, CourseProgressStats, CourseTranscriptCue, DEFAULT_COURSE_CONTENT_PANEL_LABELS, DEFAULT_VIDEO_PLAYER_LABELS, DEFAULT_VIDEO_PLAYER_RATES, MediaComponent, MediaGroup, MediaItem, MediaSize, MediaType, MetricsCardBadgeStatus, MetricsCardComponent, MetricsCardIconBg, MetricsCardOrientation, MetricsCardType, MetricsCardVariation, NoteGroup, NoteItem, NotesPanelComponent, ProfileBadge, ProfileComponent, ProfileGroupComponent, ProfileGroupItem, ProfileGroupSize, ProfileIndicator, ProfileSize, TestimonialComponent, TestimonialData, TestimonialVariant, ToolbarBarComponent, ToolbarButton, ToolbarTab, ToolbarVariant, VideoPlayerComponent, VideoPlayerError, VideoPlayerLabels, VideoPlayerPreload, VideoPlayerSource, VideoPlayerTimeEvent, VideoPlayerTrack, courseModuleStats, courseProgress, findCourseLesson, findCourseModule, formatCourseDuration, formatCourseTime, formatVideoTime, parseLessonPartTitle, resolveLessonStatus } from '@pecb-ui/components';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { CodeSnippetComponent, MediaComponent, MetricsCardComponent, NotesPanelComponent, ProfileComponent, ProfileGroupComponent, TestimonialComponent, ToolbarBarComponent } from '@pecb-ui/components';
|
|
1
|
+
export { CodeSnippetComponent, CourseContentPanelComponent, CoursePlayerComponent, DEFAULT_COURSE_CONTENT_PANEL_LABELS, DEFAULT_VIDEO_PLAYER_LABELS, DEFAULT_VIDEO_PLAYER_RATES, MediaComponent, MetricsCardComponent, NotesPanelComponent, ProfileComponent, ProfileGroupComponent, TestimonialComponent, ToolbarBarComponent, VideoPlayerComponent, courseModuleStats, courseProgress, findCourseLesson, findCourseModule, formatCourseDuration, formatCourseTime, formatVideoTime, parseLessonPartTitle, resolveLessonStatus } from '@pecb-ui/components';
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
* @pecb-ui/components/data-display — secondary entry point (audit F18).
|
|
5
5
|
*
|
|
6
|
-
* Re-exports data-display components (profile, media,
|
|
6
|
+
* Re-exports data-display components (profile, media, video-player, course player,
|
|
7
7
|
* testimonial, code-snippet, notes-panel, toolbar-bar) from the primary
|
|
8
8
|
* entry point:
|
|
9
9
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pecb-ui-components-data-display.mjs","sources":["../../../projects/ui-components/data-display/src/public-api.ts","../../../projects/ui-components/data-display/src/pecb-ui-components-data-display.ts"],"sourcesContent":["/*\n * @pecb-ui/components/data-display — secondary entry point (audit F18).\n *\n * Re-exports data-display components (profile, media,
|
|
1
|
+
{"version":3,"file":"pecb-ui-components-data-display.mjs","sources":["../../../projects/ui-components/data-display/src/public-api.ts","../../../projects/ui-components/data-display/src/pecb-ui-components-data-display.ts"],"sourcesContent":["/*\n * @pecb-ui/components/data-display — secondary entry point (audit F18).\n *\n * Re-exports data-display components (profile, media, video-player, course player,\n * testimonial, code-snippet, notes-panel, toolbar-bar) from the primary\n * entry point:\n *\n * import { MetricsCardComponent } from '@pecb-ui/components/data-display';\n *\n * Existing imports from '@pecb-ui/components' continue to work unchanged.\n */\nexport {\n ProfileComponent,\n ProfileGroupComponent,\n MediaComponent,\n VideoPlayerComponent,\n DEFAULT_VIDEO_PLAYER_LABELS,\n DEFAULT_VIDEO_PLAYER_RATES,\n formatVideoTime,\n CourseContentPanelComponent,\n CoursePlayerComponent,\n DEFAULT_COURSE_CONTENT_PANEL_LABELS,\n formatCourseDuration,\n formatCourseTime,\n parseLessonPartTitle,\n resolveLessonStatus,\n courseModuleStats,\n courseProgress,\n findCourseModule,\n findCourseLesson,\n MetricsCardComponent,\n TestimonialComponent,\n CodeSnippetComponent,\n NotesPanelComponent,\n ToolbarBarComponent\n} from '@pecb-ui/components';\n\nexport type {\n // Profile\n ProfileBadge,\n ProfileIndicator,\n ProfileSize,\n ProfileGroupItem,\n ProfileGroupSize,\n // Media\n MediaGroup,\n MediaItem,\n MediaSize,\n MediaType,\n // Video player\n VideoPlayerSource,\n VideoPlayerTrack,\n VideoPlayerPreload,\n VideoPlayerTimeEvent,\n VideoPlayerError,\n VideoPlayerLabels,\n // Course panel / player\n CourseLesson,\n CourseLessonType,\n CourseLessonStatus,\n CourseModule,\n CourseModuleStats,\n CourseProgressStats,\n CourseTranscriptCue,\n CourseContentPanelTab,\n CourseContentPanelLayout,\n CourseContentPanelDensity,\n CourseContentPanelAccent,\n CourseContentPanelLabels,\n CoursePlayerPanelPosition,\n // Metrics card\n MetricsCardBadgeStatus,\n MetricsCardIconBg,\n MetricsCardOrientation,\n MetricsCardType,\n MetricsCardVariation,\n // Testimonial\n TestimonialData,\n TestimonialVariant,\n // Code snippet\n CodeSnippetTheme,\n CodeSnippetVariant,\n // Notes panel\n NoteGroup,\n NoteItem,\n // Toolbar\n ToolbarButton,\n ToolbarTab,\n ToolbarVariant\n} from '@pecb-ui/components';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;;;;;;AAUG;;ACVH;;AAEG"}
|