@dereekb/dbx-form 13.3.0 → 13.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,665 @@
1
+ import { DbxInjectionComponentConfig, DbxActionSuccessHandlerFunction } from '@dereekb/dbx-core';
2
+ import { IndexNumber, Maybe, RangeInput, MaybeMap } from '@dereekb/util';
3
+ import * as rxjs from 'rxjs';
4
+ import { Observable, Subscription } from 'rxjs';
5
+ import * as _dereekb_dbx_form_quiz from '@dereekb/dbx-form/quiz';
6
+ import { ComponentStore } from '@ngrx/component-store';
7
+ import { ObservableOrValue, Work } from '@dereekb/rxjs';
8
+ import * as _angular_core from '@angular/core';
9
+ import { Provider, Signal } from '@angular/core';
10
+
11
+ /**
12
+ * Unique identifier for a quiz instance.
13
+ */
14
+ type QuizId = string;
15
+ /**
16
+ * Unique identifier for a question within a quiz.
17
+ */
18
+ type QuizQuestionId = string;
19
+ /**
20
+ * Zero-based index of the currently selected question.
21
+ */
22
+ type QuestionIndex = IndexNumber;
23
+ /**
24
+ * Full quiz definition including metadata, questions, and injection configs for pre/post views.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const quiz: Quiz = {
29
+ * id: 'onboarding',
30
+ * titleDetails: { title: 'Onboarding Quiz' },
31
+ * questions: [{ id: 'q1', questionComponentConfig: { ... }, answerComponentConfig: { ... } }],
32
+ * resultsComponentConfig: { componentClass: MyResultsComponent }
33
+ * };
34
+ * ```
35
+ */
36
+ interface Quiz {
37
+ readonly id: QuizId;
38
+ /**
39
+ * Title details for the quiz.
40
+ */
41
+ readonly titleDetails: QuizTitleDetails;
42
+ /**
43
+ * Questions to display. The questions are displayed in order.
44
+ */
45
+ readonly questions: QuizQuestion[];
46
+ /**
47
+ * Component config for the pre-quiz view.
48
+ */
49
+ readonly preQuizComponentConfig?: DbxInjectionComponentConfig<any>;
50
+ /**
51
+ * Component config for the results view.
52
+ */
53
+ readonly resultsComponentConfig: DbxInjectionComponentConfig<any>;
54
+ }
55
+ /**
56
+ * Display metadata for a quiz header area.
57
+ */
58
+ interface QuizTitleDetails {
59
+ /**
60
+ * Name/title of the quiz
61
+ */
62
+ readonly title: string;
63
+ /**
64
+ * Subtitle of the quiz
65
+ */
66
+ readonly subtitle?: string;
67
+ /**
68
+ * Description of the quiz
69
+ */
70
+ readonly description?: string;
71
+ }
72
+ /**
73
+ * Pairs a question id with the user's typed answer data.
74
+ */
75
+ interface QuizAnswer<T = unknown> {
76
+ /**
77
+ * Id of the question this answer belongs to.
78
+ */
79
+ readonly id: QuizQuestionId;
80
+ /**
81
+ * The answer payload, typed per-question component.
82
+ */
83
+ readonly data: T;
84
+ }
85
+ /**
86
+ * Lightweight pair linking a question id to its positional index in the quiz.
87
+ */
88
+ interface QuizQuestionIdIndexPair {
89
+ readonly id: QuizQuestionId;
90
+ readonly index: QuestionIndex;
91
+ }
92
+ /**
93
+ * Single question definition within a quiz, pairing a display component with an answer component.
94
+ */
95
+ interface QuizQuestion {
96
+ /**
97
+ * Question id. Should be unique in the quiz.
98
+ */
99
+ readonly id: QuizQuestionId;
100
+ /**
101
+ * Question component config
102
+ */
103
+ readonly questionComponentConfig: DbxInjectionComponentConfig<any>;
104
+ /**
105
+ * Answer component config
106
+ */
107
+ readonly answerComponentConfig: DbxInjectionComponentConfig<any>;
108
+ }
109
+ /**
110
+ * A QuizQuestion enriched with its positional index, used by the store to track the current question.
111
+ */
112
+ interface QuizQuestionWithIndex extends QuizQuestion, QuizQuestionIdIndexPair {
113
+ }
114
+
115
+ /**
116
+ * Internal state shape managed by QuizStore.
117
+ */
118
+ interface QuizStoreState {
119
+ /**
120
+ * Map of questions, keyed by id.
121
+ *
122
+ * Unset if the quiz is not yet set.
123
+ */
124
+ readonly questionMap?: Maybe<ReadonlyMap<QuizQuestionId, QuizQuestion>>;
125
+ /**
126
+ * Started quiz
127
+ */
128
+ readonly startedQuiz: boolean;
129
+ /**
130
+ * Questions that have been answered, sorted by index.
131
+ */
132
+ readonly completedQuestions: QuizQuestionIdIndexPair[];
133
+ /**
134
+ * Questions that are remaining to be answered, sorted by index.
135
+ */
136
+ readonly unansweredQuestions: QuizQuestionIdIndexPair[];
137
+ /**
138
+ * Map of current answers.
139
+ */
140
+ readonly answers: ReadonlyMap<QuizQuestionId, QuizAnswer>;
141
+ /**
142
+ * The current index that corresponds with the selected question.
143
+ *
144
+ * If null, defaults to the first question.
145
+ *
146
+ * If greater than the total number of questions, then the quiz is considered complete.
147
+ */
148
+ readonly questionIndex?: Maybe<QuestionIndex>;
149
+ /**
150
+ * If true, the quiz is locked from navigation.
151
+ *
152
+ * Typically used while submitting the quiz.
153
+ */
154
+ readonly lockQuizNavigation?: boolean;
155
+ /**
156
+ * If true, the quiz has been marked as submitted.
157
+ */
158
+ readonly submittedQuiz?: boolean;
159
+ /**
160
+ * The current/active quiz.
161
+ */
162
+ readonly quiz?: Maybe<Quiz>;
163
+ /**
164
+ * If true, allows going back to visit previous questions.
165
+ */
166
+ readonly allowVisitingPreviousQuestion: boolean;
167
+ /**
168
+ * If true, automatically advances to the next question when an answer is set.
169
+ */
170
+ readonly autoAdvanceToNextQuestion: boolean;
171
+ /**
172
+ * Whether or not skipping questions is allowed.
173
+ *
174
+ * Defaults to false.
175
+ */
176
+ readonly allowSkipQuestion: boolean;
177
+ }
178
+ /**
179
+ * Lookup input for retrieving an answer by question id, index, or the current question.
180
+ * Provide exactly one of `id`, `index`, or `currentIndex`.
181
+ */
182
+ interface QuizStoreAnswerLookupInput extends Partial<QuizQuestionIdIndexPair> {
183
+ readonly currentIndex?: boolean;
184
+ }
185
+ /**
186
+ * NgRx ComponentStore that manages quiz lifecycle: question navigation, answer tracking,
187
+ * submission state, and navigation locking.
188
+ *
189
+ * Provided at the component level by `QuizComponent`.
190
+ *
191
+ * @example
192
+ * ```ts
193
+ * // Access from a child component via DI:
194
+ * readonly quizStore = inject(QuizStore);
195
+ * this.quizStore.startQuiz();
196
+ * this.quizStore.updateAnswerForCurrentQuestion(5);
197
+ * ```
198
+ */
199
+ declare class QuizStore extends ComponentStore<QuizStoreState> {
200
+ constructor();
201
+ readonly quiz$: Observable<Maybe<Quiz>>;
202
+ readonly titleDetails$: Observable<_dereekb_dbx_form_quiz.QuizTitleDetails | undefined>;
203
+ readonly questions$: Observable<QuizQuestion[]>;
204
+ readonly startedQuiz$: Observable<boolean>;
205
+ readonly lockQuizNavigation$: Observable<boolean | undefined>;
206
+ readonly submittedQuiz$: Observable<boolean | undefined>;
207
+ readonly answers$: Observable<ReadonlyMap<string, QuizAnswer<unknown>>>;
208
+ readonly questionIndex$: Observable<number>;
209
+ readonly completedQuestions$: Observable<QuizQuestionIdIndexPair[]>;
210
+ readonly unansweredQuestions$: Observable<QuizQuestionIdIndexPair[]>;
211
+ readonly hasAnswerForEachQuestion$: Observable<boolean>;
212
+ readonly isAtEndOfQuestions$: Observable<boolean>;
213
+ readonly canGoToPreviousQuestion$: Observable<boolean>;
214
+ readonly canGoToNextQuestion$: Observable<boolean>;
215
+ readonly currentQuestion$: Observable<Maybe<QuizQuestionWithIndex>>;
216
+ /**
217
+ * Returns a reactive observable of the answer for a given question, looked up by id, index, or the current question.
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * // By current question:
222
+ * store.answerForQuestion({ currentIndex: true }).subscribe(answer => console.log(answer));
223
+ * // By question id:
224
+ * store.answerForQuestion({ id: 'q1' }).subscribe(answer => console.log(answer));
225
+ * ```
226
+ */
227
+ answerForQuestion(lookupInput: ObservableOrValue<QuizStoreAnswerLookupInput>): Observable<Maybe<QuizAnswer>>;
228
+ readonly startQuiz: () => void;
229
+ readonly setQuiz: (() => void) | ((observableOrValue: Maybe<Quiz> | Observable<Maybe<Quiz>>) => rxjs.Subscription);
230
+ /**
231
+ * Resets the quiz entirely, back to the pre-quiz state.
232
+ */
233
+ readonly resetQuiz: () => void;
234
+ /**
235
+ * Restarts the quiz to the first question.
236
+ */
237
+ readonly restartQuizToFirstQuestion: () => void;
238
+ readonly setAnswers: (() => void) | ((observableOrValue: Maybe<QuizAnswer<unknown>[]> | Observable<Maybe<QuizAnswer<unknown>[]>>) => rxjs.Subscription);
239
+ readonly updateAnswers: (() => void) | ((observableOrValue: Maybe<QuizAnswer<unknown>[]> | Observable<Maybe<QuizAnswer<unknown>[]>>) => rxjs.Subscription);
240
+ readonly updateAnswerForCurrentQuestion: (observableOrValue: unknown) => rxjs.Subscription;
241
+ readonly setQuestionIndex: (observableOrValue: number | Observable<number>) => rxjs.Subscription;
242
+ readonly setAutoAdvanceToNextQuestion: (observableOrValue: boolean | Observable<boolean>) => rxjs.Subscription;
243
+ readonly setAllowSkipQuestion: (observableOrValue: boolean | Observable<boolean>) => rxjs.Subscription;
244
+ readonly setAllowVisitingPreviousQuestion: (observableOrValue: boolean | Observable<boolean>) => rxjs.Subscription;
245
+ readonly goToNextQuestion: () => void;
246
+ readonly goToPreviousQuestion: () => void;
247
+ readonly setLockQuizNavigation: (observableOrValue: boolean | Observable<boolean>) => rxjs.Subscription;
248
+ readonly setSubmittedQuiz: (observableOrValue: boolean | Observable<boolean>) => rxjs.Subscription;
249
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuizStore, never>;
250
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<QuizStore>;
251
+ }
252
+
253
+ /**
254
+ * Abstract accessor injected into answer/question child components to read the current question
255
+ * and write answers back to the QuizStore without coupling to it directly.
256
+ *
257
+ * Use `provideCurrentQuestionQuizQuestionAccessor()` to bind this to the store's current question.
258
+ */
259
+ declare abstract class QuizQuestionAccessor<T = unknown> {
260
+ /**
261
+ * The active quiz definition.
262
+ */
263
+ abstract readonly quiz$: Observable<Maybe<Quiz>>;
264
+ /**
265
+ * The question this accessor is bound to.
266
+ */
267
+ abstract readonly question$: Observable<Maybe<QuizQuestion>>;
268
+ /**
269
+ * The current answer for this question, or undefined if unanswered.
270
+ */
271
+ abstract readonly answer$: Observable<Maybe<QuizAnswer<T>>>;
272
+ /**
273
+ * Submits an answer value for this question.
274
+ */
275
+ abstract setAnswer(answer: T): void;
276
+ /**
277
+ * Binds an observable source whose emissions are forwarded as answer updates.
278
+ */
279
+ abstract setAnswerSource(answer: Observable<T>): Subscription;
280
+ }
281
+ /**
282
+ * Provides QuizQuestionAccessor bound to the current question in QuizStore.
283
+ *
284
+ * @usage
285
+ * ```typescript
286
+ * @Component({
287
+ * providers: [QuizStore, provideCurrentQuestionQuizQuestionAccessor()]
288
+ * })
289
+ * ```
290
+ */
291
+ declare function provideCurrentQuestionQuizQuestionAccessor<T = unknown>(): Provider;
292
+
293
+ /**
294
+ * Lifecycle state of the quiz container view.
295
+ */
296
+ type QuizComponentState = 'init' | 'pre-quiz' | 'quiz' | 'post-quiz';
297
+ /**
298
+ * Discriminated union of view configs, one per quiz lifecycle state.
299
+ */
300
+ type QuizComponentViewConfig = QuizComponentViewInitConfig | QuizComponentViewPreQuizConfig | QuizComponentViewQuizConfig | QuizComponentViewPostQuizConfig;
301
+ interface QuizComponentViewInitConfig {
302
+ readonly state: 'init';
303
+ }
304
+ interface QuizComponentViewPreQuizConfig {
305
+ readonly state: 'pre-quiz';
306
+ readonly preQuizComponent?: Maybe<DbxInjectionComponentConfig>;
307
+ }
308
+ interface QuizComponentViewQuizConfig {
309
+ readonly state: 'quiz';
310
+ readonly questionComponent?: Maybe<DbxInjectionComponentConfig>;
311
+ readonly answerComponent?: Maybe<DbxInjectionComponentConfig>;
312
+ }
313
+ interface QuizComponentViewPostQuizConfig {
314
+ readonly state: 'post-quiz';
315
+ readonly resultsComponent?: Maybe<DbxInjectionComponentConfig>;
316
+ }
317
+ /**
318
+ * Top-level quiz container that orchestrates pre-quiz, active quiz, and post-quiz views.
319
+ *
320
+ * Provides its own `QuizStore` and `QuizQuestionAccessor`, so child components injected via
321
+ * `DbxInjectionComponent` can access quiz state directly through DI.
322
+ *
323
+ * Supports keyboard navigation: Enter (start / next), ArrowLeft (previous), ArrowRight (next).
324
+ *
325
+ * @example
326
+ * ```html
327
+ * <dbx-quiz [quiz]="myQuiz"></dbx-quiz>
328
+ * ```
329
+ */
330
+ declare class QuizComponent {
331
+ readonly quizStore: QuizStore;
332
+ readonly quiz: _angular_core.InputSignal<Maybe<Quiz>>;
333
+ readonly keysFilter: string[];
334
+ readonly quizEffect: _angular_core.EffectRef;
335
+ readonly quiz$: Observable<Maybe<Quiz>>;
336
+ readonly quizTitleSignal: Signal<string | undefined>;
337
+ readonly currentQuestionSignal: Signal<Maybe<_dereekb_dbx_form_quiz.QuizQuestionWithIndex>>;
338
+ readonly questionTitleSignal: Signal<string>;
339
+ readonly startedQuiz$: Observable<boolean>;
340
+ readonly currentQuestion$: Observable<Maybe<_dereekb_dbx_form_quiz.QuizQuestionWithIndex>>;
341
+ readonly canGoToPreviousQuestionSignal: Signal<boolean>;
342
+ readonly canGoToNextQuestionSignal: Signal<boolean>;
343
+ readonly viewConfig$: Observable<QuizComponentViewConfig>;
344
+ readonly viewConfigSignal: Signal<QuizComponentViewConfig>;
345
+ readonly viewStateSignal: Signal<QuizComponentState>;
346
+ readonly preQuizComponentConfigSignal: Signal<Maybe<DbxInjectionComponentConfig>>;
347
+ readonly questionComponentConfigSignal: Signal<Maybe<DbxInjectionComponentConfig>>;
348
+ readonly answerComponentConfigSignal: Signal<Maybe<DbxInjectionComponentConfig>>;
349
+ readonly resultsComponentConfigSignal: Signal<Maybe<DbxInjectionComponentConfig>>;
350
+ handleKeyDown(event: KeyboardEvent): void;
351
+ clickPreviousQuestion(): void;
352
+ clickNextQuestion(): void;
353
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuizComponent, never>;
354
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<QuizComponent, "dbx-quiz", never, { "quiz": { "alias": "quiz"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
355
+ }
356
+
357
+ /**
358
+ * Named preset for common number ranges.
359
+ */
360
+ type QuizAnswerNumberComponentPreset = 'oneToFive';
361
+ /**
362
+ * Configuration for the number answer component. Provide a preset, explicit range, or arbitrary numbers.
363
+ */
364
+ interface QuizAnswerNumberComponentConfig {
365
+ /**
366
+ * Uses a preset to compute the range/numbers.
367
+ */
368
+ readonly preset?: QuizAnswerNumberComponentPreset;
369
+ /**
370
+ * Range configuration
371
+ */
372
+ readonly range?: RangeInput;
373
+ /**
374
+ * Arbitrary array of numbers
375
+ */
376
+ readonly numbers?: number[];
377
+ }
378
+ interface QuizAnswerNumberChoice {
379
+ readonly number: number;
380
+ readonly selected?: boolean;
381
+ }
382
+ /**
383
+ * Answer component that displays configurable number buttons.
384
+ *
385
+ * @usage
386
+ * Used as an answer component in a QuizQuestion's answerComponentConfig.
387
+ * Defaults to 1-5 range if no config is provided.
388
+ *
389
+ * ```typescript
390
+ * answerComponentConfig: {
391
+ * componentClass: QuizAnswerNumberComponent,
392
+ * init: (instance: QuizAnswerNumberComponent) => {
393
+ * instance.config.set({ range: { start: 1, end: 11 } });
394
+ * }
395
+ * }
396
+ * ```
397
+ */
398
+ declare class QuizAnswerNumberComponent {
399
+ readonly questionAccessor: QuizQuestionAccessor<number>;
400
+ readonly config: _angular_core.ModelSignal<Maybe<QuizAnswerNumberComponentConfig>>;
401
+ readonly currentAnswerSignal: _angular_core.Signal<Maybe<_dereekb_dbx_form_quiz.QuizAnswer<number>>>;
402
+ readonly currentAnswerValueSignal: _angular_core.Signal<number | undefined>;
403
+ readonly choicesSignal: _angular_core.Signal<QuizAnswerNumberChoice[]>;
404
+ readonly relevantKeysSignal: _angular_core.Signal<string[]>;
405
+ clickedAnswer(answer: number): void;
406
+ handleKeyDown(event: KeyboardEvent): void;
407
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuizAnswerNumberComponent, never>;
408
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<QuizAnswerNumberComponent, "ng-component", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, { "config": "configChange"; }, never, never, true, never>;
409
+ }
410
+
411
+ /**
412
+ * Upper-case letter label for a multiple choice option (e.g. "A", "B").
413
+ */
414
+ type MultipleChoiceLetter = string;
415
+ /**
416
+ * Display text for a single multiple choice option.
417
+ */
418
+ type MultipleChoiceText = string;
419
+ /**
420
+ * Answer data stored when a multiple choice option is selected.
421
+ */
422
+ interface MultipleChoiceAnswer {
423
+ readonly isCorrectAnswer: boolean;
424
+ readonly letter: MultipleChoiceLetter;
425
+ readonly text: MultipleChoiceText;
426
+ }
427
+ /**
428
+ * Configuration for the multiple choice answer component.
429
+ */
430
+ interface QuizAnswerMultipleChoiceComponentConfig {
431
+ /**
432
+ * Ordered list of answer option texts. Letters are auto-assigned A, B, C, etc.
433
+ */
434
+ readonly answerText: readonly MultipleChoiceText[];
435
+ /**
436
+ * Zero-based index of the correct answer, used to set `isCorrectAnswer` on the stored answer.
437
+ */
438
+ readonly correctAnswerIndex?: number;
439
+ }
440
+ interface QuizAnswerMultipleChoice extends MultipleChoiceAnswer {
441
+ readonly selected?: boolean;
442
+ }
443
+ /**
444
+ * Answer component that displays multiple choice letter-labeled buttons.
445
+ *
446
+ * @usage
447
+ * Used as an answer component in a QuizQuestion's answerComponentConfig.
448
+ * Supports keyboard shortcuts (pressing the letter key selects that answer).
449
+ *
450
+ * ```typescript
451
+ * answerComponentConfig: {
452
+ * componentClass: QuizAnswerMultipleChoiceComponent,
453
+ * init: (instance: QuizAnswerMultipleChoiceComponent) => {
454
+ * instance.config.set({
455
+ * answerText: ['Option A', 'Option B', 'Option C'],
456
+ * correctAnswerIndex: 1
457
+ * });
458
+ * }
459
+ * }
460
+ * ```
461
+ */
462
+ declare class QuizAnswerMultipleChoiceComponent {
463
+ readonly questionAccessor: QuizQuestionAccessor<QuizAnswerMultipleChoice>;
464
+ readonly config: _angular_core.ModelSignal<Maybe<QuizAnswerMultipleChoiceComponentConfig>>;
465
+ readonly currentAnswerSignal: _angular_core.Signal<Maybe<_dereekb_dbx_form_quiz.QuizAnswer<QuizAnswerMultipleChoice>>>;
466
+ readonly currentAnswerValueSignal: _angular_core.Signal<QuizAnswerMultipleChoice | undefined>;
467
+ readonly choicesSignal: _angular_core.Signal<QuizAnswerMultipleChoice[]>;
468
+ readonly relevantKeysSignal: _angular_core.Signal<string[]>;
469
+ clickedAnswer(answer: QuizAnswerMultipleChoice): void;
470
+ handleKeyDown(event: KeyboardEvent): void;
471
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuizAnswerMultipleChoiceComponent, never>;
472
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<QuizAnswerMultipleChoiceComponent, "ng-component", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, { "config": "configChange"; }, never, never, true, never>;
473
+ }
474
+
475
+ /**
476
+ * Config for the pre-quiz intro component.
477
+ *
478
+ * Overrides the title details.
479
+ */
480
+ type QuizPreQuizIntroConfig = Partial<MaybeMap<QuizTitleDetails>>;
481
+ /**
482
+ * Pre-quiz intro component that displays the quiz title, subtitle, description, and a start button.
483
+ *
484
+ * @usage
485
+ * Used as a preQuizComponentConfig in a Quiz definition.
486
+ * Inherits title details from the quiz unless overridden via config.
487
+ *
488
+ * ```typescript
489
+ * preQuizComponentConfig: {
490
+ * componentClass: QuizPreQuizIntroComponent,
491
+ * init: (instance: QuizPreQuizIntroComponent) => {
492
+ * instance.config.set({ subtitle: 'Custom subtitle' });
493
+ * }
494
+ * }
495
+ * ```
496
+ */
497
+ declare class QuizPreQuizIntroComponent {
498
+ readonly quizStore: QuizStore;
499
+ readonly config: _angular_core.ModelSignal<Maybe<Partial<MaybeMap<QuizTitleDetails>>>>;
500
+ readonly quizTitleDetailsSignal: _angular_core.Signal<QuizTitleDetails | undefined>;
501
+ readonly configSignal: _angular_core.Signal<{
502
+ title: string | undefined;
503
+ subtitle: string | undefined;
504
+ description: string | undefined;
505
+ }>;
506
+ readonly titleSignal: _angular_core.Signal<string | undefined>;
507
+ readonly subtitleSignal: _angular_core.Signal<string | undefined>;
508
+ readonly descriptionSignal: _angular_core.Signal<string | undefined>;
509
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuizPreQuizIntroComponent, never>;
510
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<QuizPreQuizIntroComponent, "ng-component", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, { "config": "configChange"; }, never, never, true, never>;
511
+ }
512
+
513
+ /**
514
+ * Configuration for the text-based question display. Used with `quizAgreementPrompt()` and
515
+ * `quizFrequencyPrompt()` helpers for Likert-scale questions.
516
+ */
517
+ interface QuizQuestionTextComponentConfig {
518
+ /**
519
+ * Instructional prompt displayed above the main text (e.g. "Rate how much you agree:").
520
+ */
521
+ readonly prompt?: string;
522
+ /**
523
+ * The primary question or statement text.
524
+ */
525
+ readonly text: string;
526
+ /**
527
+ * Scale guidance displayed below the text (e.g. "1 = Strongly Disagree, 5 = Strongly Agree").
528
+ */
529
+ readonly guidance?: string;
530
+ }
531
+ /**
532
+ * Question component that displays text with optional prompt and guidance.
533
+ *
534
+ * @usage
535
+ * Used as a questionComponentConfig in a QuizQuestion definition.
536
+ *
537
+ * ```typescript
538
+ * questionComponentConfig: {
539
+ * componentClass: QuizQuestionTextComponent,
540
+ * init: (instance: QuizQuestionTextComponent) => {
541
+ * instance.config.set({ text: 'How do you handle ambiguity?', prompt: 'Rate yourself:', guidance: '1=Never, 5=Always' });
542
+ * }
543
+ * }
544
+ * ```
545
+ */
546
+ declare class QuizQuestionTextComponent {
547
+ readonly config: _angular_core.ModelSignal<Maybe<QuizQuestionTextComponentConfig>>;
548
+ readonly promptSignal: _angular_core.Signal<string | undefined>;
549
+ readonly textSignal: _angular_core.Signal<string | undefined>;
550
+ readonly guidanceSignal: _angular_core.Signal<string | undefined>;
551
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuizQuestionTextComponent, never>;
552
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<QuizQuestionTextComponent, "ng-component", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, { "config": "configChange"; }, never, never, true, never>;
553
+ }
554
+
555
+ /**
556
+ * Submission lifecycle state within the post-quiz view.
557
+ */
558
+ type DbxQuizPostQuizState = 'presubmit' | 'postsubmit';
559
+ /**
560
+ * Post-quiz component that handles quiz submission and displays pre/post submit content.
561
+ *
562
+ * @usage
563
+ * Use as a wrapper in your results component template:
564
+ *
565
+ * ```html
566
+ * <dbx-quiz-post-quiz [handleSubmitQuiz]="handleSubmitQuiz">
567
+ * <div presubmit>Pre-submit content...</div>
568
+ * <div postsubmit>Post-submit content (scores, etc.)...</div>
569
+ * </dbx-quiz-post-quiz>
570
+ * ```
571
+ */
572
+ declare class DbxQuizPostQuizComponent {
573
+ readonly quizStore: QuizStore;
574
+ readonly quizSubmittedSignal: _angular_core.Signal<boolean | undefined>;
575
+ readonly stateSignal: _angular_core.Signal<"presubmit" | "postsubmit">;
576
+ readonly handleSubmitQuiz: _angular_core.InputSignal<Work<void> | undefined>;
577
+ readonly handleSubmitQuizButton: Work<void>;
578
+ readonly handleSubmitQuizSuccess: DbxActionSuccessHandlerFunction;
579
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DbxQuizPostQuizComponent, never>;
580
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DbxQuizPostQuizComponent, "dbx-quiz-post-quiz", never, { "handleSubmitQuiz": { "alias": "handleSubmitQuiz"; "required": false; "isSignal": true; }; }, {}, never, ["[presubmit]", "[postsubmit]", "*"], true, never>;
581
+ }
582
+
583
+ /**
584
+ * Button component that restarts the quiz to the first question.
585
+ *
586
+ * @usage
587
+ * ```html
588
+ * <dbx-quiz-reset-button buttonText="Try Again"></dbx-quiz-reset-button>
589
+ * ```
590
+ */
591
+ declare class DbxQuizResetButtonComponent {
592
+ readonly quizStore: QuizStore;
593
+ readonly buttonText: _angular_core.InputSignal<string>;
594
+ readonly handleResetQuizButton: Work<void>;
595
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DbxQuizResetButtonComponent, never>;
596
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DbxQuizResetButtonComponent, "dbx-quiz-reset-button", never, { "buttonText": { "alias": "buttonText"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
597
+ }
598
+
599
+ /**
600
+ * Input data for rendering the quiz score display.
601
+ */
602
+ interface DbxQuizScoreInput {
603
+ /**
604
+ * Whether to show the retake/reset button.
605
+ */
606
+ readonly showRetakeButton?: boolean;
607
+ /**
608
+ * Feedback text to display.
609
+ */
610
+ readonly feedbackText: string;
611
+ /**
612
+ * Optional subtitle text.
613
+ */
614
+ readonly subtitle?: Maybe<string>;
615
+ /**
616
+ * The score achieved.
617
+ */
618
+ readonly score: number;
619
+ /**
620
+ * The maximum possible score.
621
+ */
622
+ readonly maxScore: number;
623
+ }
624
+ /**
625
+ * Generic quiz score display component.
626
+ *
627
+ * @usage
628
+ * ```html
629
+ * <dbx-quiz-score [input]="scoreInput"></dbx-quiz-score>
630
+ * ```
631
+ */
632
+ declare class DbxQuizScoreComponent {
633
+ readonly input: _angular_core.InputSignal<Maybe<DbxQuizScoreInput>>;
634
+ readonly scoreSignal: _angular_core.Signal<number | undefined>;
635
+ readonly maxScoreSignal: _angular_core.Signal<number | undefined>;
636
+ readonly feedbackTextSignal: _angular_core.Signal<string>;
637
+ readonly subtitleSignal: _angular_core.Signal<Maybe<string>>;
638
+ readonly showRetakeButtonSignal: _angular_core.Signal<boolean | undefined>;
639
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DbxQuizScoreComponent, never>;
640
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DbxQuizScoreComponent, "dbx-quiz-score", never, { "input": { "alias": "input"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
641
+ }
642
+
643
+ /**
644
+ * Creates a Likert scale question config with agreement prompt (Strongly Disagree to Strongly Agree).
645
+ *
646
+ * @example
647
+ * ```ts
648
+ * instance.config.set(quizAgreementPrompt('I feel confident leading under pressure.'));
649
+ * // { prompt: 'Please rate how much you agree...', text: '...', guidance: '1 = Strongly Disagree, 5 = Strongly Agree' }
650
+ * ```
651
+ */
652
+ declare function quizAgreementPrompt(text: string): QuizQuestionTextComponentConfig;
653
+ /**
654
+ * Creates a Likert scale question config with frequency prompt (Never to Always).
655
+ *
656
+ * @example
657
+ * ```ts
658
+ * instance.config.set(quizFrequencyPrompt('I break vague direction into first steps.'));
659
+ * // { prompt: 'Please rate how much you agree...', text: '...', guidance: '1 = Never, 5 = Always' }
660
+ * ```
661
+ */
662
+ declare function quizFrequencyPrompt(text: string): QuizQuestionTextComponentConfig;
663
+
664
+ export { DbxQuizPostQuizComponent, DbxQuizResetButtonComponent, DbxQuizScoreComponent, QuizAnswerMultipleChoiceComponent, QuizAnswerNumberComponent, QuizComponent, QuizPreQuizIntroComponent, QuizQuestionAccessor, QuizQuestionTextComponent, QuizStore, provideCurrentQuestionQuizQuestionAccessor, quizAgreementPrompt, quizFrequencyPrompt };
665
+ export type { DbxQuizPostQuizState, DbxQuizScoreInput, MultipleChoiceAnswer, MultipleChoiceLetter, MultipleChoiceText, QuestionIndex, Quiz, QuizAnswer, QuizAnswerMultipleChoiceComponentConfig, QuizAnswerNumberComponentConfig, QuizAnswerNumberComponentPreset, QuizComponentState, QuizComponentViewConfig, QuizComponentViewInitConfig, QuizComponentViewPostQuizConfig, QuizComponentViewPreQuizConfig, QuizComponentViewQuizConfig, QuizId, QuizPreQuizIntroConfig, QuizQuestion, QuizQuestionId, QuizQuestionIdIndexPair, QuizQuestionTextComponentConfig, QuizQuestionWithIndex, QuizStoreAnswerLookupInput, QuizStoreState, QuizTitleDetails };