@panelwave/player 1.0.1 → 1.2.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.
package/index.d.ts CHANGED
@@ -1603,6 +1603,31 @@ interface ExtraImage {
1603
1603
  interface Paywall {
1604
1604
  /** Array of paywall rules */
1605
1605
  rules?: PaywallRule[];
1606
+ /**
1607
+ * Display info for the products / subscription tiers the rules reference by
1608
+ * id (format 1.6) — labels, descriptions and prices of the Buy / Subscribe
1609
+ * options (optional)
1610
+ */
1611
+ products?: PaywallProduct[];
1612
+ }
1613
+ /**
1614
+ * One product or subscription tier from the host's catalogue (format 1.6).
1615
+ * Informational: the rules decide what unlocks what.
1616
+ */
1617
+ interface PaywallProduct {
1618
+ /** Id referenced by requiredProductIds / requireEntitlement / subscriptionTiers */
1619
+ id: string;
1620
+ /** Localized product name (optional) */
1621
+ name?: LocalizedString;
1622
+ /** Localized product description (optional) */
1623
+ description?: LocalizedString;
1624
+ /** Display price (optional) */
1625
+ price?: {
1626
+ amount: number;
1627
+ currency: string;
1628
+ };
1629
+ /** One-time purchase or subscription tier (optional, informational) */
1630
+ type?: 'purchase' | 'subscription';
1606
1631
  }
1607
1632
  /**
1608
1633
  * Paywall rule
@@ -1628,7 +1653,7 @@ interface PaywallRule {
1628
1653
  entitlementType?: string;
1629
1654
  /** Tiers that satisfy a subscription rule; empty/absent = any tier (optional) */
1630
1655
  subscriptionTiers?: string[];
1631
- /** Products that satisfy a purchase rule; empty/absent = any purchase (optional) */
1656
+ /** Products that unlock a purchase rule, any one suffices (format 1.6); absent = requireEntitlement key / any purchase (optional) */
1632
1657
  requiredProductIds?: string[];
1633
1658
  /** Embedded price for display in the paywall overlay (CMS) (optional) */
1634
1659
  price?: {
@@ -1985,6 +2010,26 @@ interface PanelChangeEvent {
1985
2010
  /** Transition used */
1986
2011
  transition?: string;
1987
2012
  }
2013
+ /**
2014
+ * Payload of `<pw-player-shell>`'s `(panelChange)` output.
2015
+ *
2016
+ * Panels are keyed by id in `chapter.panels`; the optional `Panel.id` of the
2017
+ * format is not required and is usually absent, so read the id from
2018
+ * `panelId`, not from `panel`.
2019
+ */
2020
+ interface PlayerPanelChangeEvent {
2021
+ /** The panel that is now current (the manifest object, variants unresolved). */
2022
+ panel: Panel;
2023
+ /** The chapter the panel belongs to. */
2024
+ chapter: Chapter;
2025
+ /** Id of the current panel: its key in `chapter.panels`. */
2026
+ panelId: string;
2027
+ /**
2028
+ * Id of the panel that was current before this change (it may belong to
2029
+ * the previous chapter). Undefined for the first panel after a (re)load.
2030
+ */
2031
+ previousPanelId?: string;
2032
+ }
1988
2033
  /**
1989
2034
  * Decision event payload
1990
2035
  */
@@ -2189,6 +2234,21 @@ interface PaywallGate {
2189
2234
  reason: string;
2190
2235
  /** Preview information (optional) */
2191
2236
  preview?: PreviewInfo;
2237
+ /** Id of the manifest paywall rule that raised the gate (optional) */
2238
+ ruleId?: string;
2239
+ /**
2240
+ * Machine-readable lock reason (optional): `subscription_required`,
2241
+ * `purchase_required`, `age_verification_required` or
2242
+ * `entitlement_required`. The overlay translates it; `reason` stays the
2243
+ * English sentence for hosts.
2244
+ */
2245
+ lockReason?: string;
2246
+ /**
2247
+ * What the reader can buy to pass the gate, derived from the rule
2248
+ * (product ids / subscription tiers, name, price). The built-in overlay
2249
+ * renders them as Buy / Subscribe buttons.
2250
+ */
2251
+ options?: PurchaseInfo[];
2192
2252
  }
2193
2253
  /**
2194
2254
  * Preview information for gated content
@@ -2209,8 +2269,8 @@ interface PurchaseInfo {
2209
2269
  productId: string;
2210
2270
  /** Product name */
2211
2271
  name: string;
2212
- /** Price with currency */
2213
- price: {
2272
+ /** Price with currency (optional: not every rule carries one) */
2273
+ price?: {
2214
2274
  amount: number;
2215
2275
  currency: string;
2216
2276
  };
@@ -4154,12 +4214,22 @@ declare class TrackingService {
4154
4214
  * free preview.
4155
4215
  * - Panel-scoped rules gate exactly their `targetPanelIds` — preview does NOT
4156
4216
  * override an explicit panel gate.
4217
+ * - Chapter-scoped rules gate only the panels of their chapter(s) (`refId`);
4218
+ * their free preview counts panels WITHIN that chapter. They take
4219
+ * precedence over a work gate for those panels.
4220
+ * - Extras-scoped rules never gate panels — they gate the extras block named
4221
+ * by `refId` (see `isExtraLocked`).
4157
4222
  * - A gated panel unlocks when the gating rule's requirement is satisfied by
4158
4223
  * the reader's entitlement snapshot.
4159
4224
  */
4160
4225
 
4161
4226
  type EvaluatorEntitlementType = 'free' | 'subscription' | 'purchase' | 'age_gate';
4162
- type EvaluatorScope = 'global' | 'work' | 'chapter' | 'panel';
4227
+ /**
4228
+ * `global` is NOT in the schema's scope enum (work | chapter | panel |
4229
+ * extras). It is still accepted as an alias of `work` so old manifests and
4230
+ * CMS-internal rules keep gating; nothing in the player emits it.
4231
+ */
4232
+ type EvaluatorScope = 'global' | 'work' | 'chapter' | 'panel' | 'extras';
4163
4233
  /** The rule shape the evaluator needs (a superset of the manifest rule). */
4164
4234
  interface EvaluatorRule {
4165
4235
  id: string;
@@ -4170,12 +4240,28 @@ interface EvaluatorRule {
4170
4240
  subscriptionTiers?: string[];
4171
4241
  /** Products that satisfy a purchase rule; empty/absent = any purchase. */
4172
4242
  requiredProductIds?: string[];
4173
- /** Minimum age for an age_gate rule (default 18). */
4243
+ /**
4244
+ * Minimum age. For an `age_gate` rule it is the whole requirement (default
4245
+ * 18); on any other rule it is an extra check ON TOP OF the entitlement
4246
+ * (schema `ageGate`): the reader needs both.
4247
+ */
4174
4248
  minimumAge?: number;
4175
4249
  /** Free-preview length for work/global rules (panels in reading order). */
4176
4250
  previewPanelCount?: number;
4177
4251
  /** Panels gated by a panel-scoped rule. */
4178
4252
  targetPanelIds?: string[];
4253
+ /** Chapters (chapter scope) or extras blocks (extras scope) the rule gates — the manifest's `refId`. */
4254
+ targetIds?: string[];
4255
+ /** Reader-facing rule name and description (CMS), for purchase options. */
4256
+ name?: string;
4257
+ description?: string;
4258
+ /** Display price (CMS). */
4259
+ price?: {
4260
+ amount: number;
4261
+ currency: string;
4262
+ };
4263
+ /** The manifest's raw `requireEntitlement` key. */
4264
+ entitlementKey?: string;
4179
4265
  }
4180
4266
  /** What the reader "has" — the shape payments produce and the player consumes. */
4181
4267
  interface EntitlementSnapshot {
@@ -4189,6 +4275,10 @@ interface EntitlementSnapshot {
4189
4275
  interface PanelRef {
4190
4276
  id: string;
4191
4277
  index: number;
4278
+ /** Chapter the panel belongs to (enables chapter-scoped rules). */
4279
+ chapterId?: string;
4280
+ /** Reading-order index within its chapter (chapter-rule preview counting). */
4281
+ chapterIndex?: number;
4192
4282
  }
4193
4283
  type LockReason = 'subscription_required' | 'purchase_required' | 'age_verification_required' | null;
4194
4284
  interface AccessDecision {
@@ -4201,7 +4291,10 @@ interface AccessDecision {
4201
4291
  /** True when access exists only because the panel is inside the free preview. */
4202
4292
  preview: boolean;
4203
4293
  }
4204
- /** Does the reader's snapshot satisfy this rule's requirement? */
4294
+ /**
4295
+ * Does the reader's snapshot satisfy this rule's requirement? A rule with a
4296
+ * `minimumAge` needs the age AND its entitlement.
4297
+ */
4205
4298
  declare function satisfiesRule(rule: EvaluatorRule, entitlement: EntitlementSnapshot): boolean;
4206
4299
  /** The active work/global rule (first one wins — mirrors the CMS content map). */
4207
4300
  declare function findWorkGateRule(rules: EvaluatorRule[]): EvaluatorRule | null;
@@ -4209,6 +4302,8 @@ declare function findWorkGateRule(rules: EvaluatorRule[]): EvaluatorRule | null;
4209
4302
  * Evaluate one panel against the rules for a given reader snapshot.
4210
4303
  */
4211
4304
  declare function evaluatePanelAccess(rules: EvaluatorRule[], entitlement: EntitlementSnapshot, panel: PanelRef): AccessDecision;
4305
+ /** Is the extras block `extraId` locked by an extras-scoped rule? */
4306
+ declare function isExtraLocked(rules: EvaluatorRule[], entitlement: EntitlementSnapshot, extraId: string): boolean;
4212
4307
  /** Evaluate a whole work (panels in reading order). */
4213
4308
  declare function evaluateWorkAccess(rules: EvaluatorRule[], entitlement: EntitlementSnapshot, panels: PanelRef[]): AccessDecision[];
4214
4309
  /** A snapshot with no entitlements — what an anonymous first-time reader has. */
@@ -4222,12 +4317,19 @@ declare const ANONYMOUS_READER: EntitlementSnapshot;
4222
4317
  * `minimumAge` written by the CMS exporter. Prefer the CMS names and fall
4223
4318
  * back to the originals, so a manifest from either era gates identically.
4224
4319
  *
4225
- * A rule with `minimumAge`/`ageGate` but no recognised entitlement type is an
4226
- * age gate — that is the only sane reading of a rule that names an age.
4320
+ * `ageGate` / `minimumAge` is an age check ON TOP OF the entitlement (schema
4321
+ * semantics). Only a rule that declares no entitlement at all but names an
4322
+ * age becomes a pure age gate; a custom marker plus an age stays a purchase
4323
+ * (or subscription) gate that also requires the age.
4227
4324
  */
4228
4325
  declare function fromManifestRule(rule: PaywallRule, index: number): EvaluatorRule;
4229
4326
  /** Normalise every rule in a manifest. Returns [] when the work has no paywall. */
4230
4327
  declare function rulesFromManifest(manifest: PanelWaveManifest | null): EvaluatorRule[];
4328
+ /** Chapter id and within-chapter index per panel id (chapter-rule previews). */
4329
+ declare function chapterOrderFromManifest(manifest: PanelWaveManifest | null): Map<string, {
4330
+ chapterId: string;
4331
+ chapterIndex: number;
4332
+ }>;
4231
4333
  /**
4232
4334
  * Global reading order for preview counting: chapters in array order, and
4233
4335
  * within a chapter the panel declaration order.
@@ -4262,11 +4364,15 @@ declare function toEntitlementStatus(decision: AccessDecision, entitlement: Enti
4262
4364
  declare class PaywallService {
4263
4365
  private rules;
4264
4366
  private readingOrder;
4367
+ private chapterOrder;
4265
4368
  private manifest;
4369
+ private products;
4266
4370
  private snapshotSubject;
4267
4371
  readonly snapshot$: Observable<EntitlementSnapshot>;
4268
4372
  /** Load the rules and reading order from a manifest. Safe to call repeatedly. */
4269
4373
  setManifest(manifest: PanelWaveManifest | null): void;
4374
+ /** `paywall.products` by id (format 1.6); the first entry wins on duplicate ids. */
4375
+ static productsFromManifest(manifest: PanelWaveManifest | null): Map<string, PaywallProduct>;
4270
4376
  /** Replace what the reader owns (after sign-in, or a completed purchase). */
4271
4377
  setSnapshot(snapshot: EntitlementSnapshot | null | undefined): void;
4272
4378
  getSnapshot(): EntitlementSnapshot;
@@ -4282,16 +4388,34 @@ declare class PaywallService {
4282
4388
  * must not be handed out as a free sample.
4283
4389
  */
4284
4390
  evaluate(panelId: string): AccessDecision;
4391
+ /** Is this extras block locked by an extras-scoped rule the reader does not satisfy? */
4392
+ isExtraLocked(extraId: string): boolean;
4285
4393
  /** Convenience: may the reader open this panel? */
4286
4394
  canAccess(panelId: string): boolean;
4287
4395
  /**
4288
4396
  * Describe the gate blocking a panel, or null when it is not gated.
4289
4397
  * The shape is the player's existing `PaywallGate`, so the overlay needs
4290
- * no changes to render it.
4398
+ * no changes to render it. `locale` picks the language of product names
4399
+ * and descriptions from `paywall.products` (fallback: the work's default
4400
+ * locale).
4401
+ */
4402
+ gateFor(panelId: string, locale?: LocaleCode): PaywallGate | null;
4403
+ /**
4404
+ * What the reader can buy to pass a rule: one option per required product
4405
+ * (purchase) or per subscription tier (subscription). Without explicit
4406
+ * ids, the rule's `requireEntitlement` key names the product, else the
4407
+ * rule id. Age gates and free rules offer nothing to buy.
4408
+ *
4409
+ * Labels (format 1.6): an option whose id has an entry in
4410
+ * `paywall.products` takes that entry's localized name, description and
4411
+ * price. Otherwise it falls back to the rule's name (a single option) or
4412
+ * the bare id (several options), and to the rule's description and price.
4291
4413
  */
4292
- gateFor(panelId: string): PaywallGate | null;
4414
+ static purchaseOptions(rule: EvaluatorRule, products?: ReadonlyMap<string, PaywallProduct>, locale?: LocaleCode, fallbackLocale?: LocaleCode): PurchaseInfo[];
4293
4415
  /** The rule that gates a panel, for callers that need its price or name. */
4294
4416
  ruleFor(panelId: string): EvaluatorRule | null;
4417
+ /** The work's default locale (product-label fallback). */
4418
+ private get defaultLocale();
4295
4419
  /** Reset to a manifest-less, entitlement-less state. */
4296
4420
  clear(): void;
4297
4421
  /**
@@ -5345,9 +5469,10 @@ declare class PaywallOverlayComponent {
5345
5469
  */
5346
5470
  getMessage(): string;
5347
5471
  /**
5348
- * Handle purchase option selection
5472
+ * Handle purchase option selection: `purchase` carries the product id,
5473
+ * `action` is 'subscribe' for a subscription option, else 'purchase'.
5349
5474
  */
5350
- onPurchaseOption(productId: string): void;
5475
+ onPurchaseOption(option: PurchaseInfo): void;
5351
5476
  /**
5352
5477
  * Handle login action
5353
5478
  */
@@ -5444,6 +5569,8 @@ interface AgeVerificationResult {
5444
5569
  * Modal overlay for age verification
5445
5570
  */
5446
5571
  declare class AgeGateComponent {
5572
+ /** Optional: the gate is a public component and works (in English) without ngx-translate. */
5573
+ private readonly translate;
5447
5574
  /**
5448
5575
  * Visibility state
5449
5576
  */
@@ -5490,6 +5617,8 @@ declare class AgeGateComponent {
5490
5617
  * Get warning message
5491
5618
  */
5492
5619
  getWarningMessage(): string;
5620
+ /** Translate an `age_gate.*` UI string (English fallback). */
5621
+ t(key: string, params?: Record<string, unknown>): string;
5493
5622
  /**
5494
5623
  * Handle verification submit
5495
5624
  */
@@ -5506,8 +5635,9 @@ declare class AgeGateComponent {
5506
5635
  * Calculate age from birth date
5507
5636
  */
5508
5637
  private calculateAge;
5638
+ private monthCache?;
5509
5639
  /**
5510
- * Get month options
5640
+ * Month options, named in the current locale (Intl; cached per locale).
5511
5641
  */
5512
5642
  getMonthOptions(): {
5513
5643
  value: string;
@@ -5537,12 +5667,18 @@ declare class AgeGateComponent {
5537
5667
  interface BranchChoice {
5538
5668
  /** The graph edge this choice traverses. */
5539
5669
  edge: Edge;
5540
- /** Reader-facing label (edge label → target panel title → "Option N"). */
5670
+ /**
5671
+ * Reader-facing label (edge label → target panel title). Empty: the
5672
+ * chooser shows a translated "Option N".
5673
+ */
5541
5674
  label: string;
5542
5675
  /** Position in the offered list (0-based), stable for tracking. */
5543
5676
  index: number;
5544
5677
  }
5545
5678
  declare class BranchChooserComponent {
5679
+ private readonly translate;
5680
+ /** Translate a `branch_chooser.*` UI string (English fallback). */
5681
+ t(key: string, params?: Record<string, unknown>): string;
5546
5682
  /** Visible state */
5547
5683
  visible: boolean;
5548
5684
  /** Current locale (labels are already resolved by the shell). */
@@ -5582,7 +5718,7 @@ interface EntitlementAdapter {
5582
5718
  * Player Shell Component
5583
5719
  * Main orchestrator for the PanelWave player
5584
5720
  */
5585
- declare class PlayerShellComponent implements OnInit, OnDestroy {
5721
+ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
5586
5722
  /**
5587
5723
  * Manifest to load
5588
5724
  */
@@ -5614,12 +5750,16 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
5614
5750
  /** Bearer token identifying the reader to `entitlementEndpoint`. */
5615
5751
  readerToken?: string;
5616
5752
  /**
5617
- * Emitted when a reader acts on the paywall overlay. The host owns
5618
- * checkout — the player never talks to a payment provider itself.
5753
+ * Emitted when a reader acts on the paywall overlay: `purchase` /
5754
+ * `subscribe` (with the chosen option's `productId` — a product id or a
5755
+ * subscription tier), `login` or `dismiss`. The host owns checkout — the
5756
+ * player never talks to a payment provider itself; call
5757
+ * `refreshEntitlements()` (or pass a new `entitlementSnapshot`) afterwards.
5619
5758
  */
5620
5759
  paywallAction: EventEmitter<{
5621
5760
  action: PaywallAction;
5622
5761
  gate: PaywallGate;
5762
+ productId?: string;
5623
5763
  }>;
5624
5764
  /**
5625
5765
  * Emitted after the reader answers an `age_gate` rule's overlay (verified or
@@ -5711,12 +5851,10 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
5711
5851
  */
5712
5852
  ready: EventEmitter<void>;
5713
5853
  /**
5714
- * Panel changed
5854
+ * The current panel changed. Carries the panel's id (`panelId`, its key in
5855
+ * `chapter.panels`) and the id of the panel before it (`previousPanelId`).
5715
5856
  */
5716
- panelChange: EventEmitter<{
5717
- panel: Panel;
5718
- chapter: Chapter;
5719
- }>;
5857
+ panelChange: EventEmitter<PlayerPanelChangeEvent>;
5720
5858
  /**
5721
5859
  * Chapter changed
5722
5860
  */
@@ -5802,6 +5940,8 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
5802
5940
  */
5803
5941
  paywallGate: PaywallGate | null;
5804
5942
  paywallVisible: boolean;
5943
+ /** Product id / tier of the overlay option the reader just picked. */
5944
+ paywallProductId?: string;
5805
5945
  /** Adapter built from `entitlementEndpoint`, when the host supplied one. */
5806
5946
  private httpEntitlement?;
5807
5947
  /**
@@ -5969,6 +6109,8 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
5969
6109
  private analyticsSessionEnded;
5970
6110
  private workCompleteTracked;
5971
6111
  private lastTrackedPanelId?;
6112
+ /** Id of the panel of the last `panelChange` emission (its `previousPanelId` source). */
6113
+ private lastPanelChangeId?;
5972
6114
  /** Bound pagehide handler so add/removeEventListener match. */
5973
6115
  private readonly onPageHide;
5974
6116
  private readonly playerState;
@@ -5978,10 +6120,30 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
5978
6120
  private readonly translationService;
5979
6121
  private readonly canvasCamera;
5980
6122
  private readonly paywallService;
6123
+ /** ngOnInit ran: later input changes are live updates, not initial values. */
6124
+ private initialized;
6125
+ /** The state subscriptions are set up once per instance, not per (re)load. */
6126
+ private stateSubscribed;
5981
6127
  /**
5982
6128
  * Initialize component
5983
6129
  */
5984
6130
  ngOnInit(): void;
6131
+ /**
6132
+ * Inputs changed after init. The first round (before ngOnInit) is skipped:
6133
+ * ngOnInit reads every input itself, so nothing loads twice.
6134
+ */
6135
+ ngOnChanges(changes: SimpleChanges): void;
6136
+ /**
6137
+ * Reload the work from the current `manifest` / `manifestUrl` inputs
6138
+ * (also the error screen's Retry). Story state of the previous load —
6139
+ * position, variables except persistent ones, open overlays, autoplay —
6140
+ * is reset; the analytics session of the previous work is closed.
6141
+ */
6142
+ reload(): Promise<void>;
6143
+ /** Content locale + GUI language follow `locale`. */
6144
+ private applyLocale;
6145
+ /** Apply a changed `viewModeOverride` to the running view. */
6146
+ private applyViewModeOverride;
5985
6147
  /**
5986
6148
  * Cleanup on destroy
5987
6149
  */
@@ -6041,6 +6203,12 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
6041
6203
  * one-time `work_complete` signal.
6042
6204
  */
6043
6205
  private trackPanelView;
6206
+ /**
6207
+ * A panel's id: its key in `chapter.panels`. Panels don't reliably carry
6208
+ * their own id (`Panel.id` is optional in the format), so resolve it by
6209
+ * identity, as getCurrentPanelId() does.
6210
+ */
6211
+ private panelIdOf;
6044
6212
  /** An end panel (no outgoing edges) of the manifest's last chapter. */
6045
6213
  private isEndOfWork;
6046
6214
  /**
@@ -6069,8 +6237,11 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
6069
6237
  * @param transition - Optional transition to render for this panel change
6070
6238
  * (already resolved against the outputPresets default). Omitted for
6071
6239
  * non-adjacent jumps (TOC, initial load), which swap instantly.
6240
+ * @param mutations - Variable mutations of the traversed edge. Applied only
6241
+ * once the navigation is allowed (after the paywall / age gate), so a
6242
+ * blocked attempt never changes story state.
6072
6243
  */
6073
- navigateToPanel(chapterId: string, panelId: string, transition?: Transition, cameraMove?: CameraMove): Promise<void>;
6244
+ navigateToPanel(chapterId: string, panelId: string, transition?: Transition, cameraMove?: CameraMove, mutations?: Mutation[]): Promise<void>;
6074
6245
  /**
6075
6246
  * Rebuild the flat variable context handed to the viewport/canvas for
6076
6247
  * hotspot visibleIf evaluation. New object identity per call so OnPush
@@ -6176,6 +6347,8 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
6176
6347
  * Toolbar event handlers
6177
6348
  */
6178
6349
  onToggleView(): void;
6350
+ /** Land the canvas camera on the current panel (entering canvas view). */
6351
+ private jumpCameraToCurrentPanel;
6179
6352
  /**
6180
6353
  * Tap on a placed panel in canvas view. Traverses the matching out-edge of
6181
6354
  * the current panel when its condition passes (the graph still gates
@@ -6184,6 +6357,12 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
6184
6357
  * state.
6185
6358
  */
6186
6359
  onCanvasPanelTap(panelId: string): void;
6360
+ /**
6361
+ * The manifest actually loaded — from `manifest` or fetched via
6362
+ * `manifestUrl`. Everything that lists the work (ToC, thumbnails) binds to
6363
+ * this, never to the `manifest` input, which is unset for URL loading.
6364
+ */
6365
+ get loadedManifest(): PanelWaveManifest | undefined;
6187
6366
  /** Balloon defaults for the canvas stage (same source as the viewport). */
6188
6367
  get manifestBalloonConfig(): BalloonConfig | null;
6189
6368
  /** Manifest characters for speech-bubble styling in canvas view. */
@@ -6452,9 +6631,15 @@ declare class PlayerShellComponent implements OnInit, OnDestroy {
6452
6631
  private restoreSocialState;
6453
6632
  /** `bookmarked` is true only while the reader is ON the bookmarked panel. */
6454
6633
  private syncBookmarkFlag;
6455
- /** More than one edge leaves the current panel — the toolbar shows "Choices". */
6634
+ /**
6635
+ * At least two paths out of the current panel are open right now (edge
6636
+ * conditions evaluated exactly like the chooser does) — the toolbar shows
6637
+ * "Choices". A closed conditional edge does not count.
6638
+ */
6456
6639
  get hasBranchesAhead(): boolean;
6457
- /** Outgoing edges whose conditions pass right now, with reader-facing labels. */
6640
+ /** Outgoing edges of the current panel whose conditions pass right now. */
6641
+ private openEdges;
6642
+ /** Open outgoing edges with reader-facing labels. */
6458
6643
  private computeBranchChoices;
6459
6644
  private branchLabel;
6460
6645
  private localizedText;
@@ -7185,5 +7370,5 @@ declare class PlayerComponent {
7185
7370
  static ɵcmp: i0.ɵɵComponentDeclaration<PlayerComponent, "pw-player", never, {}, {}, never, never, true, never>;
7186
7371
  }
7187
7372
 
7188
- export { ANONYMOUS_READER, ActionModalComponent, AgeGateComponent, AudioEngineService, BranchChooserComponent, CANVAS_PANEL_BUDGET, CanvasCameraService, CanvasStageComponent, ComicBalloon, DEFAULT_BALLOON_CONFIG, DEFAULT_STALL_TIMEOUT_MS, DEFAULT_VIDEO_MUTED, DEFAULT_VIDEO_PLAY_MODE, DEFAULT_VIDEO_START_MODE, EntitlementError, EntitlementService, ExportService, FlowEngineService, HotspotActionService, HotspotsOverlayComponent, HttpEntitlementAdapter, ImageCacheService, ManifestService, MockEntitlementAdapter, NullEntitlementAdapter, PANEL_AUDIO_LEAVE_FADE_MS, PanelAudioService, PaywallOverlayComponent, PaywallService, PlayerComponent, PlayerEvent, PlayerService, PlayerShellComponent, PlayerStateService, PluginHostService, PluginSandboxComponent, PreloadService, PwIconComponent, RESERVED_NAMESPACES, SpeechBubblesComponent, TrackingService, TranslationService, UserGestureService, VISIBILITY_THRESHOLD, VariableStoreService, VideoControllerService, VideoLayerComponent, VideoSequencerService, VisibilityService, applyVariantOverrides, balloonConfigToRenderOptions, balloonConfigToTailOptions, busForRole, createBalloon, evaluatePanelAccess, evaluateWorkAccess, findWorkGateRule, fromManifestRule, mergeBalloonConfig, readingOrderFromManifest, resolveMuted, resolvePanelVariant, resolvePanels, resolvePlayMode, resolveStartMode, resolveVideoConfig, rulesFromManifest, satisfiesRule, selectVariant, toEntitlementStatus };
7189
- export type { AccessDecision, AgeVerificationResult, AssetBase, AssetCatalogItem, AssetCatalogItemAudio, AssetCatalogItemImage, AssetCatalogItemJson, AssetCatalogItemPluginPayload, AssetCatalogItemSubtitle, AssetCatalogItemVector, AssetCatalogItemVideo, AssetCategory, AssetCommon, AssetRef, AssetReference, AssetVariant, Assets, AudioLayer, AudioRole, AudioTrack, AudioVariant, BalloonConfig, BalloonConfigOverride, BalloonOptions, BalloonRenderResult, BalloonType, Bookmark, BoundingBox, BranchChoice, BubbleStyle, BubbleTail, CameraMove, CameraMovePath, CameraState, CameraZoomProfile, CanvasBackground, CanvasCameraPolicy, CanvasDecoration, CanvasFitMode, CanvasFreeRoam, CanvasLayout, CanvasOverviewPolicy, CanvasPlacement, CanvasRevealMode, Chapter, Character$1 as Character, ContentWarning, Creator, DecisionEvent, DeepLinkTarget, DeviceVariables, Edge, EffectiveVideoConfig, EntitlementAdapter$1 as EntitlementAdapter, EntitlementContext, EntitlementErrorCode, EntitlementSnapshot, EntitlementSnapshotResponse, EntitlementStatus, EntitlementVariables, ErrorEvent$1 as ErrorEvent, EvaluatorEntitlementType, EvaluatorRule, EvaluatorScope, ExtraImage, ExtraItem, Extras, FormatView, Graph, HideBorderConfig, Hotspot, HotspotAction, HotspotCircle, HotspotGoToAction, HotspotOpenExtrasAction, HotspotOpenModalAction, HotspotPluginEventAction, HotspotPolygon, HotspotRect, HotspotSetVariablesAction, HotspotShape, HotspotUiEffect, HttpEntitlementAdapterConfig, ImageLayer, ImageVariant, JsonLogic, JsonLogicExpression, JsonValue, JsonVariant, Layer, LayerKind, LayerViewMode, LocaleCode, LocalizedString, LockReason, Meta, Mutation, MutationOperation, NavigationPath, NodeMetadata, NormalizedPoint, NormalizedRect, OutputFormat, OutputPreset, OverlayState, Page, PageLayout, Panel, PanelAudioRole, PanelAudioTrack, PanelChangeEvent, PanelPartial, PanelPlacement, PanelRef, PanelVariant, PanelWaveManifest, PanelwaveHeader, Paywall, PaywallAction, PaywallEvent, PaywallGate$1 as PaywallGate, PaywallRule, PlaybackState, PlayerError, PlayerErrorCode, PlayerEventData, PlayerOptions, PlayerPreferences, PlayerState, PlayerStatistics, PluginInstance$1 as PluginInstance, PluginLayer, PreferenceVariables, PreloadItem, PreloadPriority, PreloadSettings, PreloadStatus$1 as PreloadStatus, PreviewInfo, PurchaseInfo, ReadingProgress, ResolvedPanel, ResolvedPanelAudio, SequenceAudioTrack, SequencedVideo, SequencedVideoInfo, Settings, SpeechBubble, StagePlacement, SubtitleVariant, TailConfig, TailCurve, TailOptions, TextLayer, TextStyle, Tracking, TrackingConfig$1 as TrackingConfig, TrackingEvent, Transform, Transition, TraversalOptions, TraversalResult, UIDefaults, UISettings, UserInfo, UserVariables, VariableChangeEvent, VariableContext, VariableDefinition, VariableMutation, VariableScope, VariableStore, VariableType, VariableValidationResult, Variables, VariantContext, VectorVariant, VideoEvent, VideoLayer, VideoPlayMode, VideoPoster, VideoStartMode, VideoState, VideoStatus, VideoTrackingPayload, VideoTrigger, VideoVariant, ViewMode, ViewportState, VisibilityChange, WorldPoint, WorldRect };
7373
+ export { ANONYMOUS_READER, ActionModalComponent, AgeGateComponent, AudioEngineService, BranchChooserComponent, CANVAS_PANEL_BUDGET, CanvasCameraService, CanvasStageComponent, ComicBalloon, DEFAULT_BALLOON_CONFIG, DEFAULT_STALL_TIMEOUT_MS, DEFAULT_VIDEO_MUTED, DEFAULT_VIDEO_PLAY_MODE, DEFAULT_VIDEO_START_MODE, EntitlementError, EntitlementService, ExportService, FlowEngineService, HotspotActionService, HotspotsOverlayComponent, HttpEntitlementAdapter, ImageCacheService, ManifestService, MockEntitlementAdapter, NullEntitlementAdapter, PANEL_AUDIO_LEAVE_FADE_MS, PanelAudioService, PaywallOverlayComponent, PaywallService, PlayerComponent, PlayerEvent, PlayerService, PlayerShellComponent, PlayerStateService, PluginHostService, PluginSandboxComponent, PreloadService, PwIconComponent, RESERVED_NAMESPACES, SpeechBubblesComponent, TrackingService, TranslationService, UserGestureService, VISIBILITY_THRESHOLD, VariableStoreService, VideoControllerService, VideoLayerComponent, VideoSequencerService, VisibilityService, applyVariantOverrides, balloonConfigToRenderOptions, balloonConfigToTailOptions, busForRole, chapterOrderFromManifest, createBalloon, evaluatePanelAccess, evaluateWorkAccess, findWorkGateRule, fromManifestRule, isExtraLocked, mergeBalloonConfig, readingOrderFromManifest, resolveMuted, resolvePanelVariant, resolvePanels, resolvePlayMode, resolveStartMode, resolveVideoConfig, rulesFromManifest, satisfiesRule, selectVariant, toEntitlementStatus };
7374
+ export type { AccessDecision, AgeVerificationResult, AssetBase, AssetCatalogItem, AssetCatalogItemAudio, AssetCatalogItemImage, AssetCatalogItemJson, AssetCatalogItemPluginPayload, AssetCatalogItemSubtitle, AssetCatalogItemVector, AssetCatalogItemVideo, AssetCategory, AssetCommon, AssetRef, AssetReference, AssetVariant, Assets, AudioLayer, AudioRole, AudioTrack, AudioVariant, BalloonConfig, BalloonConfigOverride, BalloonOptions, BalloonRenderResult, BalloonType, Bookmark, BoundingBox, BranchChoice, BubbleStyle, BubbleTail, CameraMove, CameraMovePath, CameraState, CameraZoomProfile, CanvasBackground, CanvasCameraPolicy, CanvasDecoration, CanvasFitMode, CanvasFreeRoam, CanvasLayout, CanvasOverviewPolicy, CanvasPlacement, CanvasRevealMode, Chapter, Character$1 as Character, ContentWarning, Creator, DecisionEvent, DeepLinkTarget, DeviceVariables, Edge, EffectiveVideoConfig, EntitlementAdapter$1 as EntitlementAdapter, EntitlementContext, EntitlementErrorCode, EntitlementSnapshot, EntitlementSnapshotResponse, EntitlementStatus, EntitlementVariables, ErrorEvent$1 as ErrorEvent, EvaluatorEntitlementType, EvaluatorRule, EvaluatorScope, ExtraImage, ExtraItem, Extras, FormatView, Graph, HideBorderConfig, Hotspot, HotspotAction, HotspotCircle, HotspotGoToAction, HotspotOpenExtrasAction, HotspotOpenModalAction, HotspotPluginEventAction, HotspotPolygon, HotspotRect, HotspotSetVariablesAction, HotspotShape, HotspotUiEffect, HttpEntitlementAdapterConfig, ImageLayer, ImageVariant, JsonLogic, JsonLogicExpression, JsonValue, JsonVariant, Layer, LayerKind, LayerViewMode, LocaleCode, LocalizedString, LockReason, Meta, Mutation, MutationOperation, NavigationPath, NodeMetadata, NormalizedPoint, NormalizedRect, OutputFormat, OutputPreset, OverlayState, Page, PageLayout, Panel, PanelAudioRole, PanelAudioTrack, PanelChangeEvent, PanelPartial, PanelPlacement, PanelRef, PanelVariant, PanelWaveManifest, PanelwaveHeader, Paywall, PaywallAction, PaywallEvent, PaywallGate$1 as PaywallGate, PaywallProduct, PaywallRule, PlaybackState, PlayerError, PlayerErrorCode, PlayerEventData, PlayerOptions, PlayerPanelChangeEvent, PlayerPreferences, PlayerState, PlayerStatistics, PluginInstance$1 as PluginInstance, PluginLayer, PreferenceVariables, PreloadItem, PreloadPriority, PreloadSettings, PreloadStatus$1 as PreloadStatus, PreviewInfo, PurchaseInfo, ReadingProgress, ResolvedPanel, ResolvedPanelAudio, SequenceAudioTrack, SequencedVideo, SequencedVideoInfo, Settings, SpeechBubble, StagePlacement, SubtitleVariant, TailConfig, TailCurve, TailOptions, TextLayer, TextStyle, Tracking, TrackingConfig$1 as TrackingConfig, TrackingEvent, Transform, Transition, TraversalOptions, TraversalResult, UIDefaults, UISettings, UserInfo, UserVariables, VariableChangeEvent, VariableContext, VariableDefinition, VariableMutation, VariableScope, VariableStore, VariableType, VariableValidationResult, Variables, VariantContext, VectorVariant, VideoEvent, VideoLayer, VideoPlayMode, VideoPoster, VideoStartMode, VideoState, VideoStatus, VideoTrackingPayload, VideoTrigger, VideoVariant, ViewMode, ViewportState, VisibilityChange, WorldPoint, WorldRect };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panelwave/player",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "description": "Open-source Angular library for PanelWave interactive graphic novels",
5
5
  "keywords": [
6
6
  "angular",
@@ -19,9 +19,9 @@
19
19
  "url": "https://github.com/panelwave/player/issues"
20
20
  },
21
21
  "peerDependencies": {
22
- "@angular/common": "^20.0.0",
23
- "@angular/core": "^20.0.0",
24
- "@ngx-translate/core": "^17.0.0",
22
+ "@angular/common": "^20.0.0 || ^21.0.0 || ^22.0.0",
23
+ "@angular/core": "^20.0.0 || ^21.0.0 || ^22.0.0",
24
+ "@ngx-translate/core": "^17.0.0 || ^18.0.0",
25
25
  "rxjs": "^7.8.0"
26
26
  },
27
27
  "dependencies": {
@@ -180,7 +180,11 @@
180
180
  "sign_in": "Anmelden, um fortzufahren",
181
181
  "go_back": "Zurück",
182
182
  "maybe_later": "Vielleicht später",
183
- "secure_payment": "Sichere Zahlungsabwicklung"
183
+ "secure_payment": "Sichere Zahlungsabwicklung",
184
+ "reason_subscription_required": "Dieser Teil der Geschichte ist im Abo enthalten.",
185
+ "reason_purchase_required": "Dieser Teil der Geschichte ist käuflich erhältlich.",
186
+ "reason_age_verification_required": "Dieser Inhalt ist altersbeschränkt. Bestätige dein Alter, um fortzufahren.",
187
+ "reason_entitlement_required": "Für diesen Inhalt ist eine Berechtigung erforderlich."
184
188
  },
185
189
  "loading": {
186
190
  "text": "PanelWave wird geladen..."
@@ -191,5 +195,26 @@
191
195
  },
192
196
  "common": {
193
197
  "esc": "Esc"
198
+ },
199
+ "age_gate": {
200
+ "title": "Altersprüfung erforderlich",
201
+ "close": "Schließen",
202
+ "warning": "Dieser Inhalt ist nur für Personen ab {{age}} Jahren freigegeben.",
203
+ "prompt": "Bitte gib dein Geburtsdatum ein:",
204
+ "month": "Monat",
205
+ "day": "Tag",
206
+ "year": "Jahr",
207
+ "verify": "Alter bestätigen",
208
+ "privacy": "Deine Angaben sind privat und werden nicht gespeichert.",
209
+ "error_incomplete": "Bitte gib dein vollständiges Geburtsdatum ein.",
210
+ "error_month": "Bitte gib einen gültigen Monat ein (1-12).",
211
+ "error_day": "Bitte gib einen gültigen Tag ein (1-{{max}}).",
212
+ "error_year": "Bitte gib ein gültiges Jahr ein (1900-{{max}}).",
213
+ "error_too_young": "Du musst mindestens {{age}} Jahre alt sein, um diesen Inhalt zu sehen."
214
+ },
215
+ "branch_chooser": {
216
+ "title": "Wähle deinen Weg",
217
+ "close": "Schließen",
218
+ "option": "Option {{n}}"
194
219
  }
195
220
  }
@@ -180,7 +180,11 @@
180
180
  "sign_in": "Sign In to Continue",
181
181
  "go_back": "Go Back",
182
182
  "maybe_later": "Maybe Later",
183
- "secure_payment": "Secure payment processing"
183
+ "secure_payment": "Secure payment processing",
184
+ "reason_subscription_required": "This part of the story is included with a subscription.",
185
+ "reason_purchase_required": "This part of the story is available to buy.",
186
+ "reason_age_verification_required": "This content is age-restricted. Confirm your age to continue.",
187
+ "reason_entitlement_required": "This content requires an entitlement to access."
184
188
  },
185
189
  "loading": {
186
190
  "text": "Loading PanelWave..."
@@ -191,5 +195,26 @@
191
195
  },
192
196
  "common": {
193
197
  "esc": "Esc"
198
+ },
199
+ "age_gate": {
200
+ "title": "Age Verification Required",
201
+ "close": "Close",
202
+ "warning": "This content is restricted to users {{age}} years of age or older.",
203
+ "prompt": "Please enter your birth date:",
204
+ "month": "Month",
205
+ "day": "Day",
206
+ "year": "Year",
207
+ "verify": "Verify Age",
208
+ "privacy": "Your information is private and will not be stored.",
209
+ "error_incomplete": "Please enter your complete birth date.",
210
+ "error_month": "Please enter a valid month (1-12).",
211
+ "error_day": "Please enter a valid day (1-{{max}}).",
212
+ "error_year": "Please enter a valid year (1900-{{max}}).",
213
+ "error_too_young": "You must be at least {{age}} years old to access this content."
214
+ },
215
+ "branch_chooser": {
216
+ "title": "Choose your path",
217
+ "close": "Close",
218
+ "option": "Option {{n}}"
194
219
  }
195
220
  }