@candy-kingdom/bonnie 0.26.16 → 0.27.1

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.
@@ -1,9 +1,294 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, signal, inject, ChangeDetectorRef, effect, Output, Directive, ElementRef, Input, Component, Pipe, ViewChild, ViewContainerRef, ChangeDetectionStrategy } from '@angular/core';
3
- import { Subject, takeUntil, NEVER, fromEvent, merge, BehaviorSubject, filter } from 'rxjs';
2
+ import { Injectable, Pipe, output, input, inject, ElementRef, signal, effect, DestroyRef, Component, Directive, model, viewChild, ViewContainerRef, ChangeDetectionStrategy } from '@angular/core';
3
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
+ import { Subject, NEVER, takeUntil, fromEvent, merge } from 'rxjs';
4
5
  import { DomSanitizer } from '@angular/platform-browser';
5
- import * as i1 from '@angular/common';
6
- import { CommonModule, AsyncPipe, JsonPipe } from '@angular/common';
6
+ import { NgTemplateOutlet, JsonPipe } from '@angular/common';
7
+
8
+ class DeviceService {
9
+ devicePixelRatio = typeof window === "undefined" ? 1 : window.devicePixelRatio;
10
+ isSSR = typeof window === "undefined";
11
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DeviceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
12
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DeviceService });
13
+ }
14
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DeviceService, decorators: [{
15
+ type: Injectable
16
+ }] });
17
+
18
+ class DeviceServiceBase {
19
+ }
20
+
21
+ function emptyBone() {
22
+ return {
23
+ style: "",
24
+ mediaQuery: "",
25
+ enabled: true,
26
+ type: "",
27
+ };
28
+ }
29
+
30
+ function emptyImage() {
31
+ return {
32
+ $type: "image", // todo: remove
33
+ type: "image",
34
+ sources: [],
35
+ };
36
+ }
37
+
38
+ function emptyLocalizedString() {
39
+ return {};
40
+ }
41
+
42
+ function emptyVideo() {
43
+ return {
44
+ $type: "video", // todo: remove
45
+ type: "video",
46
+ sources: [],
47
+ };
48
+ }
49
+
50
+ class EncodeURIComponentPipe {
51
+ transform(value) {
52
+ return encodeURIComponent(value);
53
+ }
54
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EncodeURIComponentPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
55
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: EncodeURIComponentPipe, isStandalone: true, name: "encodeURIComponent" });
56
+ }
57
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EncodeURIComponentPipe, decorators: [{
58
+ type: Pipe,
59
+ args: [{ name: "encodeURIComponent", pure: true }]
60
+ }] });
61
+
62
+ class IntersectionComponent {
63
+ intersected = output();
64
+ session = input(...(ngDevMode ? [undefined, { debugName: "session" }] : []));
65
+ _hostRef = inject(ElementRef);
66
+ _intersectionObserver;
67
+ _isIntersected = signal(false, ...(ngDevMode ? [{ debugName: "_isIntersected" }] : []));
68
+ isIntersected = this._isIntersected.asReadonly();
69
+ _session; // todo: remove
70
+ constructor() {
71
+ if (typeof window === "undefined" || typeof IntersectionObserver === "undefined") {
72
+ return;
73
+ }
74
+ this._intersectionObserver = new IntersectionObserver(this.onIntersection.bind(this));
75
+ effect(() => {
76
+ if (this._isIntersected()) {
77
+ this.intersected.emit();
78
+ }
79
+ });
80
+ effect(() => {
81
+ const newSession = this.session();
82
+ if (this._session === newSession) {
83
+ return;
84
+ }
85
+ console.log("reset intersection Observer");
86
+ this._session = newSession;
87
+ this.reset();
88
+ });
89
+ inject(DestroyRef).onDestroy(() => this._intersectionObserver?.disconnect());
90
+ }
91
+ reset() {
92
+ if (this._intersectionObserver === undefined || this._intersectionObserver === null) {
93
+ return;
94
+ }
95
+ this._intersectionObserver.unobserve(this._hostRef.nativeElement);
96
+ this._isIntersected.set(false);
97
+ this._intersectionObserver.observe(this._hostRef.nativeElement);
98
+ }
99
+ onIntersection(entries, observer) {
100
+ if (entries.length > 1) {
101
+ console.warn("multi entries!");
102
+ }
103
+ const isIntersecting = entries[0].isIntersecting;
104
+ this._isIntersected.set(isIntersecting);
105
+ console.log(`intersected ${isIntersecting}`, this._hostRef.nativeElement);
106
+ // only once will recieve intersection
107
+ if (isIntersecting) {
108
+ observer.unobserve(this._hostRef.nativeElement);
109
+ }
110
+ }
111
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: IntersectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
112
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: IntersectionComponent, isStandalone: true, selector: "bon-intersection", inputs: { session: { classPropertyName: "session", publicName: "session", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { intersected: "intersected" }, ngImport: i0, template: "<ng-content></ng-content>", isInline: true, styles: [":host{display:block}\n"] });
113
+ }
114
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: IntersectionComponent, decorators: [{
115
+ type: Component,
116
+ args: [{ selector: "bon-intersection", template: "<ng-content></ng-content>", styles: [":host{display:block}\n"] }]
117
+ }], ctorParameters: () => [], propDecorators: { intersected: [{ type: i0.Output, args: ["intersected"] }], session: [{ type: i0.Input, args: [{ isSignal: true, alias: "session", required: false }] }] } });
118
+
119
+ var MediaObjectFit;
120
+ (function (MediaObjectFit) {
121
+ MediaObjectFit["Original"] = "Original";
122
+ MediaObjectFit["Cover"] = "Cover";
123
+ MediaObjectFit["Contain"] = "Contain";
124
+ })(MediaObjectFit || (MediaObjectFit = {}));
125
+
126
+ var MediaStatus;
127
+ (function (MediaStatus) {
128
+ MediaStatus["NotSet"] = "NotSet";
129
+ MediaStatus["NotLoaded"] = "NotLoaded";
130
+ MediaStatus["Loading"] = "Loading";
131
+ MediaStatus["Loaded"] = "Loaded";
132
+ })(MediaStatus || (MediaStatus = {}));
133
+
134
+ // https://stackoverflow.com/questions/42136098/array-groupby-in-typescript
135
+ const groupBy = (arr, key) => arr.reduce((groups, item) => {
136
+ (groups[key(item)] ||= []).push(item);
137
+ return groups;
138
+ }, {});
139
+ function distinct(value, index, array) {
140
+ return array.indexOf(value) === index;
141
+ }
142
+ function ascending(a, b) {
143
+ return a - b;
144
+ }
145
+ function ascendingT(sel) {
146
+ return (a, b) => ascending(sel(a), sel(b));
147
+ }
148
+ function descending(a, b) {
149
+ return b - a;
150
+ }
151
+ function descendingT(sel) {
152
+ return (a, b) => descending(sel(a), sel(b));
153
+ }
154
+ function generateSizesString(sizes) {
155
+ const sizesString = sizes
156
+ .sort((x) => x.width)
157
+ .map((x) => `${x.mediaQuery} ${x.width}${x.unit.toLowerCase()}`.trim())
158
+ .join(",");
159
+ return sizesString;
160
+ }
161
+ function matchesMediaQuery(mediaQuery) {
162
+ const isEmptyQuery = mediaQuery === null || mediaQuery === undefined || mediaQuery.trim().length === 0;
163
+ // work for SSR and browser
164
+ if (isEmptyQuery) {
165
+ return true;
166
+ }
167
+ // other queries disallowed in SSR
168
+ if (typeof window === "undefined") {
169
+ return false;
170
+ }
171
+ const mediaQueryList = window.matchMedia(mediaQuery);
172
+ return mediaQueryList.matches;
173
+ }
174
+ function isLocalUrlString(url) {
175
+ if (url === undefined || url === null || url.trim().length === 0) {
176
+ return true;
177
+ }
178
+ if (url.startsWith("//")) {
179
+ return false;
180
+ }
181
+ if (url.startsWith("./") || url.startsWith("/")) {
182
+ return true;
183
+ }
184
+ return false;
185
+ }
186
+
187
+ class SrcBaseDirective {
188
+ ratioChange = output();
189
+ _ratio = signal(0, ...(ngDevMode ? [{ debugName: "_ratio" }] : []));
190
+ ratio = this._ratio.asReadonly();
191
+ _queryChangeClearSubject = new Subject();
192
+ _destroyRef = inject(DestroyRef);
193
+ constructor() {
194
+ effect(() => {
195
+ const ratio = this._ratio();
196
+ this.ratioChange.emit(ratio);
197
+ });
198
+ effect(() => {
199
+ const val = this.data();
200
+ this.onSrcChange(val);
201
+ });
202
+ }
203
+ onSrcChange(val) {
204
+ if (val !== undefined && val !== null && val.sources.length === 0) {
205
+ console.warn("image should have sources!");
206
+ this.data.set(undefined);
207
+ return;
208
+ }
209
+ // clear mediaQuery subscriptions
210
+ this._queryChangeClearSubject.next();
211
+ // ratio
212
+ this._ratio.set(0);
213
+ if (val === undefined || val.sources.length === 0) {
214
+ return;
215
+ }
216
+ const allRatios = val.sources
217
+ .flatMap((x) => x.srcSet)
218
+ .map((x) => x.meta.ratio)
219
+ .filter(distinct);
220
+ if (allRatios.length === 1) {
221
+ // same ratio for all
222
+ this._ratio.set(allRatios[0]);
223
+ return;
224
+ }
225
+ // todo: check if this needed to be unsubscribed
226
+ this.watchMediaQueries().subscribe(() => {
227
+ this.calcRatio();
228
+ console.log("watchMediaQueries calcRatio");
229
+ });
230
+ this.calcRatio();
231
+ }
232
+ calcRatio() {
233
+ const data = this.data();
234
+ if (data === undefined || data === null || data.sources.length === 0) {
235
+ return;
236
+ }
237
+ for (let i = 0; i < data.sources.length; i++) {
238
+ const source = data.sources[i];
239
+ const srcRatios = source.srcSet
240
+ .sort(descendingT((x) => x.meta.width))
241
+ .map((x) => x.meta.ratio)
242
+ .filter(distinct);
243
+ if (srcRatios.length === 0) {
244
+ return;
245
+ }
246
+ if (srcRatios.length > 1) {
247
+ console.warn(`each source should have srcSet with same ratio. founded: ${srcRatios.join(", ")}`);
248
+ }
249
+ const ratio = srcRatios[0]; // most accurate ratio in biggest image
250
+ if (source.mediaQuery.length === 0) {
251
+ this._ratio.set(ratio);
252
+ return;
253
+ }
254
+ if (typeof window === "undefined" || typeof window.matchMedia === "undefined") {
255
+ return;
256
+ }
257
+ const mediaQueryList = window.matchMedia(source.mediaQuery);
258
+ if (mediaQueryList.matches) {
259
+ this._ratio.set(ratio);
260
+ return;
261
+ }
262
+ }
263
+ }
264
+ watchMediaQueries() {
265
+ console.log("watchMediaQueries");
266
+ const src = this.data();
267
+ if (src === undefined ||
268
+ src === null ||
269
+ typeof window === "undefined" ||
270
+ typeof window.matchMedia === "undefined") {
271
+ return NEVER.pipe(takeUntilDestroyed(this._destroyRef), takeUntil(this._queryChangeClearSubject));
272
+ }
273
+ const mediaQueries = src.sources
274
+ .map((x) => x.mediaQuery)
275
+ .filter(distinct)
276
+ .filter((x) => x.length > 0);
277
+ console.log("watchMediaQueries mediaQueries", mediaQueries);
278
+ const queryObservables = mediaQueries.map((media) => {
279
+ const queryList = window.matchMedia(media);
280
+ const observable = fromEvent(queryList, "change").pipe(takeUntilDestroyed(this._destroyRef), takeUntil(this._queryChangeClearSubject));
281
+ return observable;
282
+ });
283
+ const combinedObservable = merge(...queryObservables);
284
+ return combinedObservable;
285
+ }
286
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SrcBaseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
287
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.6", type: SrcBaseDirective, isStandalone: true, outputs: { ratioChange: "ratioChange" }, ngImport: i0 });
288
+ }
289
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SrcBaseDirective, decorators: [{
290
+ type: Directive
291
+ }], ctorParameters: () => [], propDecorators: { ratioChange: [{ type: i0.Output, args: ["ratioChange"] }] } });
7
292
 
8
293
  /**
9
294
  * This is a TypeGen auto-generated file.
@@ -178,348 +463,18 @@ var SizesWidthUnit;
178
463
  * Any changes made to this file can be lost when this file is regenerated.
179
464
  */
180
465
 
181
- // https://stackoverflow.com/questions/42136098/array-groupby-in-typescript
182
- const groupBy = (arr, key) => arr.reduce((groups, item) => {
183
- (groups[key(item)] ||= []).push(item);
184
- return groups;
185
- }, {});
186
- function distinct(value, index, array) {
187
- return array.indexOf(value) === index;
188
- }
189
- function ascending(a, b) {
190
- return a - b;
191
- }
192
- function ascendingT(sel) {
193
- return function (a, b) { return ascending(sel(a), sel(b)); };
194
- }
195
- function descending(a, b) {
196
- return b - a;
197
- }
198
- function descendingT(sel) {
199
- return function (a, b) { return descending(sel(a), sel(b)); };
200
- }
201
- function generateSizesString(sizes) {
202
- const sizesString = sizes
203
- .sort(x => x.width)
204
- .map(x => `${x.mediaQuery} ${x.width}${x.unit.toLowerCase()}`.trim())
205
- .join(',');
206
- return sizesString;
207
- }
208
- function matchesMediaQuery(mediaQuery) {
209
- const isEmptyQuery = mediaQuery === null || mediaQuery === undefined || mediaQuery.trim().length === 0;
210
- // work for SSR and browser
211
- if (isEmptyQuery)
212
- return true;
213
- // other queries disallowed in SSR
214
- if (typeof window === 'undefined')
215
- return false;
216
- const mediaQueryList = window.matchMedia(mediaQuery);
217
- return mediaQueryList.matches;
218
- }
219
- function isLocalUrlString(url) {
220
- if (url === undefined || url === null || url.trim().length === 0)
221
- return true;
222
- if (url.startsWith('//'))
223
- return false;
224
- if (url.startsWith('./') || url.startsWith('/'))
225
- return true;
226
- return false;
227
- }
228
-
229
- class UnsubscriberService {
230
- _destroy$ = new Subject();
231
- takeUntilDestroy = (origin) => origin.pipe(takeUntil(this._destroy$));
232
- ngOnDestroy() {
233
- this._destroy$.next();
234
- this._destroy$.complete();
235
- }
236
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: UnsubscriberService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
237
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: UnsubscriberService });
238
- }
239
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: UnsubscriberService, decorators: [{
240
- type: Injectable
241
- }] });
242
-
243
- class SrcBaseDirective {
244
- ratioChange = new EventEmitter();
245
- srcChange = new EventEmitter();
246
- _ratio = signal(0, ...(ngDevMode ? [{ debugName: "_ratio" }] : []));
247
- ratio = this._ratio.asReadonly();
248
- _queryChangeClearSubject = new Subject();
249
- _data;
250
- _u = inject(UnsubscriberService);
251
- cd = inject(ChangeDetectorRef);
252
- _effectCleanup;
253
- constructor() {
254
- console.log('SrcBaseDirective ctor');
255
- this.cd.detach();
256
- // Watch for ratio changes and emit
257
- this._effectCleanup = effect(() => {
258
- const ratio = this._ratio();
259
- this.ratioChange.next(ratio);
260
- this.cd.detectChanges(); // todo: verify, do i need it here
261
- }, ...(ngDevMode ? [{ debugName: "_effectCleanup" }] : []));
262
- }
263
- ngOnInit() {
264
- console.log('SrcBaseDirective ngOnInit');
265
- this.cd.detectChanges();
266
- }
267
- get data() {
268
- return this._data;
269
- }
270
- set data(val) {
271
- console.log('set data', val);
272
- if (val !== undefined && val !== null && val.sources.length === 0) {
273
- console.warn(`image should have sources!`);
274
- val = undefined;
275
- }
276
- this._data = val;
277
- console.log('calling src change ', this._data);
278
- // clear mediaQuery subscriptions
279
- this._queryChangeClearSubject.next();
280
- // ratio
281
- this._ratio.set(0);
282
- this.srcChange.next(this._data);
283
- if (this._data === undefined || this._data.sources.length === 0) {
284
- return;
285
- }
286
- const allRatios = this._data.sources
287
- .flatMap((x) => x.srcSet)
288
- .map((x) => x.meta.ratio)
289
- .filter(distinct);
290
- if (allRatios.length === 1) {
291
- // same ratio for all
292
- this._ratio.set(allRatios[0]);
293
- return;
294
- }
295
- this.watchMediaQueries().subscribe(() => {
296
- this.calcRatio();
297
- console.log('watchMediaQueries calcRatio');
298
- });
299
- this.calcRatio();
300
- }
301
- calcRatio() {
302
- if (this._data === undefined ||
303
- this._data === null ||
304
- this._data.sources.length === 0)
305
- return;
306
- for (let i = 0; i < this._data.sources.length; i++) {
307
- const source = this._data.sources[i];
308
- const srcRatios = source.srcSet
309
- .sort(descendingT((x) => x.meta.width))
310
- .map((x) => x.meta.ratio)
311
- .filter(distinct);
312
- if (srcRatios.length === 0) {
313
- // console.warn(`each source should have srcSet with same ratio. founded: ${srcRatios.join(', ')}`);
314
- return;
315
- }
316
- if (srcRatios.length > 1) {
317
- console.warn(`each source should have srcSet with same ratio. founded: ${srcRatios.join(', ')}`);
318
- }
319
- const ratio = srcRatios[0]; // most accurate ratio in biggest image
320
- if (source.mediaQuery.length === 0) {
321
- this._ratio.set(ratio);
322
- return;
323
- }
324
- if (typeof window === 'undefined' ||
325
- typeof window.matchMedia === 'undefined')
326
- return;
327
- const mediaQueryList = window.matchMedia(source.mediaQuery);
328
- if (mediaQueryList.matches) {
329
- this._ratio.set(ratio);
330
- return;
331
- }
332
- }
333
- }
334
- watchMediaQueries() {
335
- console.log('watchMediaQueries');
336
- if (this._data === undefined ||
337
- this._data === null ||
338
- typeof window === 'undefined' ||
339
- typeof window.matchMedia === 'undefined')
340
- return NEVER.pipe(this._u.takeUntilDestroy, takeUntil(this._queryChangeClearSubject));
341
- const mediaQueries = this._data.sources
342
- .map((x) => x.mediaQuery)
343
- .filter(distinct)
344
- .filter((x) => x.length > 0);
345
- console.log('watchMediaQueries mediaQueries', mediaQueries);
346
- const queryObservables = mediaQueries.map((media) => {
347
- const queryList = window.matchMedia(media);
348
- const observable = fromEvent(queryList, 'change').pipe(this._u.takeUntilDestroy, takeUntil(this._queryChangeClearSubject));
349
- return observable;
350
- });
351
- const combinedObservable = merge(...queryObservables);
352
- return combinedObservable;
353
- }
354
- ngOnDestroy() {
355
- this._effectCleanup?.destroy();
356
- }
357
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SrcBaseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
358
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.6", type: SrcBaseDirective, isStandalone: true, selector: "[bonSrcBase]", outputs: { ratioChange: "ratioChange", srcChange: "srcChange" }, providers: [UnsubscriberService], ngImport: i0 });
359
- }
360
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SrcBaseDirective, decorators: [{
361
- type: Directive,
362
- args: [{
363
- standalone: true,
364
- selector: '[bonSrcBase]',
365
- providers: [UnsubscriberService],
366
- }]
367
- }], ctorParameters: () => [], propDecorators: { ratioChange: [{
368
- type: Output
369
- }], srcChange: [{
370
- type: Output
371
- }] } });
372
-
373
- var MediaStatus;
374
- (function (MediaStatus) {
375
- MediaStatus["NotSet"] = "NotSet";
376
- MediaStatus["NotLoaded"] = "NotLoaded";
377
- MediaStatus["Loading"] = "Loading";
378
- MediaStatus["Loaded"] = "Loaded";
379
- })(MediaStatus || (MediaStatus = {}));
380
-
381
- var MediaObjectFit;
382
- (function (MediaObjectFit) {
383
- MediaObjectFit["Original"] = "Original";
384
- MediaObjectFit["Cover"] = "Cover";
385
- MediaObjectFit["Contain"] = "Contain";
386
- })(MediaObjectFit || (MediaObjectFit = {}));
387
-
388
- class DeviceService {
389
- devicePixelRatio = typeof window === 'undefined' ? 1 : window.devicePixelRatio;
390
- isSSR = typeof window === 'undefined';
391
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DeviceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
392
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DeviceService });
393
- }
394
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DeviceService, decorators: [{
395
- type: Injectable
396
- }] });
397
-
398
- class DeviceServiceBase {
399
- }
400
-
401
- class IntersectionComponent {
402
- intersected = new EventEmitter();
403
- _hostRef = inject(ElementRef);
404
- _u = inject(UnsubscriberService);
405
- _cd = inject(ChangeDetectorRef);
406
- intersectionObserver;
407
- _intersected = signal(false, ...(ngDevMode ? [{ debugName: "_intersected" }] : []));
408
- intersectedOnce = this._intersected.asReadonly();
409
- _session;
410
- _effectCleanup;
411
- constructor() {
412
- this._cd.detach();
413
- // no template with variables, so we don't need to call changeDetection
414
- if (typeof window === 'undefined' || typeof IntersectionObserver === 'undefined') {
415
- // call intersection without any
416
- return;
417
- }
418
- this.intersectionObserver = new IntersectionObserver(this.onIntersection.bind(this));
419
- // Watch for intersection changes and emit when it becomes true
420
- this._effectCleanup = effect(() => {
421
- if (this._intersected()) {
422
- this.intersected.next();
423
- }
424
- }, ...(ngDevMode ? [{ debugName: "_effectCleanup" }] : []));
425
- }
426
- ngOnInit() {
427
- }
428
- set session(newSession) {
429
- if (this._session === newSession)
430
- return;
431
- console.log('reset intersection Observer');
432
- this._session = newSession;
433
- this.reset();
434
- }
435
- reset() {
436
- if (this.intersectionObserver === undefined || this.intersectionObserver === null)
437
- return;
438
- this.intersectionObserver.unobserve(this._hostRef.nativeElement);
439
- this._intersected.set(false);
440
- this.intersectionObserver.observe(this._hostRef.nativeElement);
441
- }
442
- onIntersection(entries, observer) {
443
- if (entries.length > 1) {
444
- console.warn('multi entries!');
445
- }
446
- const isIntersecting = entries[0].isIntersecting;
447
- this._intersected.set(isIntersecting);
448
- console.log(`intersected ${isIntersecting}`, this._hostRef.nativeElement);
449
- // only once will recieve intersection
450
- if (isIntersecting) {
451
- observer.unobserve(this._hostRef.nativeElement);
452
- }
453
- }
454
- ngOnDestroy() {
455
- this._effectCleanup?.destroy();
456
- this.intersectionObserver?.disconnect();
457
- }
458
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: IntersectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
459
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: IntersectionComponent, isStandalone: true, selector: "bon-intersection", inputs: { session: "session" }, outputs: { intersected: "intersected" }, providers: [UnsubscriberService], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{display:block}\n"] });
460
- }
461
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: IntersectionComponent, decorators: [{
462
- type: Component,
463
- args: [{ selector: 'bon-intersection', standalone: true, template: '<ng-content></ng-content>', providers: [UnsubscriberService], styles: [":host{display:block}\n"] }]
464
- }], ctorParameters: () => [], propDecorators: { intersected: [{
465
- type: Output
466
- }], session: [{
467
- type: Input
468
- }] } });
469
-
470
- class EncodeURIComponentPipe {
471
- transform(value) {
472
- return encodeURIComponent(value);
473
- }
474
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EncodeURIComponentPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
475
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: EncodeURIComponentPipe, isStandalone: true, name: "encodeURIComponent" });
476
- }
477
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EncodeURIComponentPipe, decorators: [{
478
- type: Pipe,
479
- args: [{ name: 'encodeURIComponent', standalone: true, pure: true }]
480
- }] });
481
-
482
- function emptyImage() {
483
- return {
484
- $type: 'image', // todo: remove
485
- type: 'image',
486
- sources: [],
487
- };
488
- }
489
-
490
- function emptyVideo() {
491
- return {
492
- $type: 'video', // todo: remove
493
- type: 'video',
494
- sources: [],
495
- };
496
- }
497
-
498
- function emptyBone() {
499
- return {
500
- style: '',
501
- mediaQuery: '',
502
- enabled: true,
503
- type: ''
504
- };
505
- }
506
-
507
- function emptyLocalizedString() {
508
- return {};
509
- }
510
-
511
466
  class LocalizeServiceBase {
512
467
  getLocalized(value, defaultValue, locale) {
513
- if (value === undefined)
468
+ if (value === undefined) {
514
469
  return defaultValue;
470
+ }
515
471
  locale = locale ?? this.locale();
516
472
  const obj = value[locale] ?? defaultValue;
517
473
  return obj;
518
474
  }
519
475
  getLocalizedText(value, locale) {
520
- return this.getLocalized(value, '', locale);
476
+ return this.getLocalized(value, "", locale);
521
477
  }
522
- ;
523
478
  isLocalUrl(value, locale) {
524
479
  const url = this.getLocalizedText(value, locale);
525
480
  return isLocalUrlString(url);
@@ -527,39 +482,42 @@ class LocalizeServiceBase {
527
482
  }
528
483
 
529
484
  class LocalizePipe {
530
- localizeService = inject(LocalizeServiceBase);
485
+ _localizeService = inject(LocalizeServiceBase);
531
486
  transform(value, locale) {
532
- if (value === undefined || value === null)
533
- return '';
534
- return this.localizeService.getLocalizedText(value, locale);
487
+ if (value === undefined || value === null) {
488
+ return "";
489
+ }
490
+ return this._localizeService.getLocalizedText(value, locale);
535
491
  }
536
492
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocalizePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
537
493
  static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: LocalizePipe, isStandalone: true, name: "localize", pure: false });
538
494
  }
539
495
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocalizePipe, decorators: [{
540
496
  type: Pipe,
541
- args: [{ name: 'localize', standalone: true, pure: false }]
497
+ args: [{ name: "localize", pure: false }]
542
498
  }] });
543
499
  class LocalizeObjectPipe {
544
- localizeService = inject(LocalizeServiceBase);
500
+ _localizeService = inject(LocalizeServiceBase);
545
501
  transform(object, locale) {
546
- if (object === undefined || object === null)
502
+ if (object === undefined || object === null) {
547
503
  return undefined;
548
- return this.localizeService.getLocalized(object, undefined, locale);
504
+ }
505
+ return this._localizeService.getLocalized(object, undefined, locale);
549
506
  }
550
507
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocalizeObjectPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
551
508
  static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: LocalizeObjectPipe, isStandalone: true, name: "localizeObject", pure: false });
552
509
  }
553
510
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocalizeObjectPipe, decorators: [{
554
511
  type: Pipe,
555
- args: [{ name: 'localizeObject', standalone: true, pure: false }]
512
+ args: [{ name: "localizeObject", pure: false }]
556
513
  }] });
557
514
  class LocalizationIsNotEmptyPipe {
558
- localizeService = inject(LocalizeServiceBase);
515
+ _localizeService = inject(LocalizeServiceBase);
559
516
  transform(value, locale) {
560
- if (value === undefined || value === null)
517
+ if (value === undefined || value === null) {
561
518
  return false;
562
- const text = this.localizeService.getLocalizedText(value, locale);
519
+ }
520
+ const text = this._localizeService.getLocalizedText(value, locale);
563
521
  const isNotEmpty = text.trim().length > 0;
564
522
  return isNotEmpty;
565
523
  }
@@ -568,14 +526,15 @@ class LocalizationIsNotEmptyPipe {
568
526
  }
569
527
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocalizationIsNotEmptyPipe, decorators: [{
570
528
  type: Pipe,
571
- args: [{ name: 'localizationIsNotEmpty', standalone: true, pure: false }]
529
+ args: [{ name: "localizationIsNotEmpty", pure: false }]
572
530
  }] });
573
531
  class LocalizationIsEmptyPipe {
574
- localizeService = inject(LocalizeServiceBase);
532
+ _localizeService = inject(LocalizeServiceBase);
575
533
  transform(value, locale) {
576
- if (value === undefined || value === null)
534
+ if (value === undefined || value === null) {
577
535
  return true;
578
- const text = this.localizeService.getLocalizedText(value, locale);
536
+ }
537
+ const text = this._localizeService.getLocalizedText(value, locale);
579
538
  const isEmpty = text.trim().length === 0;
580
539
  return isEmpty;
581
540
  }
@@ -584,16 +543,17 @@ class LocalizationIsEmptyPipe {
584
543
  }
585
544
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocalizationIsEmptyPipe, decorators: [{
586
545
  type: Pipe,
587
- args: [{ name: 'localizationIsEmpty', standalone: true, pure: false }]
546
+ args: [{ name: "localizationIsEmpty", pure: false }]
588
547
  }] });
589
548
  class LocalizeUrlPipe {
590
- localizeService = inject(LocalizeServiceBase);
591
- domSanitizer = inject(DomSanitizer);
549
+ _localizeService = inject(LocalizeServiceBase);
550
+ _domSanitizer = inject(DomSanitizer);
592
551
  transform(value, locale) {
593
- if (value === undefined || value === null)
594
- return '';
595
- const urlString = this.localizeService.getLocalizedText(value, locale);
596
- const safeUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(urlString);
552
+ if (value === undefined || value === null) {
553
+ return "";
554
+ }
555
+ const urlString = this._localizeService.getLocalizedText(value, locale);
556
+ const safeUrl = this._domSanitizer.bypassSecurityTrustResourceUrl(urlString);
597
557
  return safeUrl;
598
558
  }
599
559
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocalizeUrlPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
@@ -601,14 +561,15 @@ class LocalizeUrlPipe {
601
561
  }
602
562
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LocalizeUrlPipe, decorators: [{
603
563
  type: Pipe,
604
- args: [{ name: 'localizeUrl', standalone: true, pure: false }]
564
+ args: [{ name: "localizeUrl", pure: false }]
605
565
  }] });
606
566
  class IsLocalUrlPipe {
607
- localizeService = inject(LocalizeServiceBase);
567
+ _localizeService = inject(LocalizeServiceBase);
608
568
  transform(value, locale) {
609
- if (value === undefined || value === null)
569
+ if (value === undefined || value === null) {
610
570
  return false;
611
- const isLocal = this.localizeService.isLocalUrl(value, locale);
571
+ }
572
+ const isLocal = this._localizeService.isLocalUrl(value, locale);
612
573
  return isLocal;
613
574
  }
614
575
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: IsLocalUrlPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
@@ -616,14 +577,15 @@ class IsLocalUrlPipe {
616
577
  }
617
578
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: IsLocalUrlPipe, decorators: [{
618
579
  type: Pipe,
619
- args: [{ name: 'isLocalUrl', standalone: true, pure: false }]
580
+ args: [{ name: "isLocalUrl", pure: false }]
620
581
  }] });
621
582
  class IsNotLocalUrlPipe {
622
- localizeService = inject(LocalizeServiceBase);
583
+ _localizeService = inject(LocalizeServiceBase);
623
584
  transform(value, locale) {
624
- if (value === undefined || value === null)
585
+ if (value === undefined || value === null) {
625
586
  return false;
626
- const isLocal = this.localizeService.isLocalUrl(value, locale);
587
+ }
588
+ const isLocal = this._localizeService.isLocalUrl(value, locale);
627
589
  return !isLocal;
628
590
  }
629
591
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: IsNotLocalUrlPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
@@ -631,254 +593,187 @@ class IsNotLocalUrlPipe {
631
593
  }
632
594
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: IsNotLocalUrlPipe, decorators: [{
633
595
  type: Pipe,
634
- args: [{ name: 'isNotLocalUrl', standalone: true, pure: false }]
596
+ args: [{ name: "isNotLocalUrl", pure: false }]
635
597
  }] });
636
598
 
637
- class ImageSrcDirective extends SrcBaseDirective {
638
- set imgsrc(value) {
639
- console.log('set imgsrc', value);
640
- this.data = value;
599
+ function getDefaultSrc(image) {
600
+ if (image === undefined || image === null) {
601
+ return undefined;
641
602
  }
603
+ const files = image.sources.flatMap((x) => x.srcSet).sort(descendingT((x) => x.meta.width));
604
+ const prefferedFiles = files.filter((x) => x.mimeType === "image/jpeg" || x.mimeType === "image/png" || x.mimeType === "image/gif");
605
+ if (prefferedFiles.length > 0) {
606
+ return prefferedFiles[0];
607
+ }
608
+ if (files.length > 0) {
609
+ return files[0];
610
+ }
611
+ return undefined;
612
+ }
613
+
614
+ class ImageSrcDirective extends SrcBaseDirective {
615
+ data = model(undefined, { ...(ngDevMode ? { debugName: "data" } : {}), alias: "imgsrc" });
642
616
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ImageSrcDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
643
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.6", type: ImageSrcDirective, isStandalone: true, selector: "[imgsrc]", inputs: { imgsrc: "imgsrc" }, usesInheritance: true, ngImport: i0 });
617
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.6", type: ImageSrcDirective, isStandalone: true, selector: "[imgsrc]", inputs: { data: { classPropertyName: "data", publicName: "imgsrc", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { data: "imgsrcChange" }, usesInheritance: true, ngImport: i0 });
644
618
  }
645
619
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ImageSrcDirective, decorators: [{
646
620
  type: Directive,
647
621
  args: [{
648
- standalone: true,
649
- selector: '[imgsrc]',
622
+ selector: "[imgsrc]",
650
623
  }]
651
- }], propDecorators: { imgsrc: [{
652
- type: Input
653
- }] } });
624
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "imgsrc", required: false }] }, { type: i0.Output, args: ["imgsrcChange"] }] } });
654
625
 
655
626
  function toHtmlPictureSources(imageSource) {
656
627
  const sizes = generateSizesString(imageSource.sizes);
657
- const groupedByMime = groupBy(imageSource.srcSet, x => x.mimeType);
628
+ const groupedByMime = groupBy(imageSource.srcSet, (x) => x.mimeType);
658
629
  const simpleSources = [];
659
630
  for (const mime in groupedByMime) {
660
- const fileSrcs = groupedByMime[mime].sort(ascendingT(x => x.meta.width));
661
- const srcSet = fileSrcs
662
- .map(x => `${x.url} ${x.meta.width}w`)
663
- .join(',');
631
+ const fileSrcs = groupedByMime[mime].sort(ascendingT((x) => x.meta.width));
632
+ const srcSet = fileSrcs.map((x) => `${x.url} ${x.meta.width}w`).join(",");
664
633
  const source = { mime, sizes, srcSet, media: imageSource.mediaQuery };
665
634
  simpleSources.push(source);
666
635
  }
667
636
  return simpleSources;
668
637
  }
669
638
 
670
- function getDefaultSrc(image) {
671
- if (image === undefined || image === null)
672
- return undefined;
673
- const files = image.sources
674
- .flatMap(x => x.srcSet)
675
- .sort(descendingT(x => x.meta.width));
676
- const prefferedFiles = files.filter(x => x.mimeType === 'image/jpeg'
677
- || x.mimeType === 'image/png'
678
- || x.mimeType === 'image/gif');
679
- if (prefferedFiles.length > 0)
680
- return prefferedFiles[0];
681
- if (files.length > 0)
682
- return files[0];
683
- return undefined;
684
- }
685
-
686
639
  class MarcyImageComponent {
687
640
  MediaStatus = MediaStatus;
688
641
  MarcyObjectFit = MediaObjectFit;
689
- isLoaded = new EventEmitter();
690
- sources = [];
691
- $status = new BehaviorSubject(MediaStatus.NotSet);
692
- defaultSrc = '';
693
- _objectFit = MediaObjectFit.Original;
694
642
  src;
643
+ isLoaded = output();
644
+ objectFit = input(MediaObjectFit.Original, ...(ngDevMode ? [{ debugName: "objectFit" }] : []));
645
+ sources = signal([], ...(ngDevMode ? [{ debugName: "sources" }] : []));
646
+ status = signal(MediaStatus.NotSet, ...(ngDevMode ? [{ debugName: "status" }] : []));
647
+ defaultSrc = signal("", ...(ngDevMode ? [{ debugName: "defaultSrc" }] : []));
695
648
  device = inject(DeviceServiceBase);
696
- cd = inject(ChangeDetectorRef);
697
- _u = inject(UnsubscriberService);
698
- _srcDir = inject(ImageSrcDirective, { optional: true });
699
649
  constructor() {
700
- console.log('MarcyImageComponent ctor');
701
- if (this._srcDir === undefined || this._srcDir === null)
650
+ const src = inject(ImageSrcDirective, { optional: true });
651
+ if (src === undefined || src === null) {
702
652
  throw new Error(`${MarcyImageComponent.name} should have [imgsrc] directive as source object`);
703
- this.src = this._srcDir;
704
- // bind src changes
705
- this.src.srcChange
706
- .pipe(this._u.takeUntilDestroy)
707
- .subscribe(this.onSrcChange.bind(this));
708
- this.cd.detach();
709
- }
710
- ngOnInit() {
711
- // bind loaded event
712
- this.$status
713
- .pipe(this._u.takeUntilDestroy, filter(status => status === MediaStatus.Loaded))
714
- .subscribe(x => this.isLoaded.next());
715
- this.cd.detectChanges();
653
+ }
654
+ this.src = src;
655
+ effect(() => {
656
+ this.onSrcChange(this.src.data());
657
+ });
658
+ effect(() => {
659
+ if (this.status() === MediaStatus.Loaded) {
660
+ this.isLoaded.emit();
661
+ }
662
+ });
716
663
  }
717
664
  onSrcChange(val) {
718
- console.log('MarcyImageComponent onSrcChange', val);
719
- this.defaultSrc = getDefaultSrc(val)?.url ?? '';
720
- this.sources.splice(0, this.sources.length);
665
+ this.defaultSrc.set(getDefaultSrc(val)?.url ?? "");
721
666
  if (val === undefined || val === null || val.sources.length === 0) {
722
- this.$status.next(MediaStatus.NotSet);
723
- this.cd.detectChanges();
667
+ this.sources.set([]);
668
+ this.status.set(MediaStatus.NotSet);
724
669
  return;
725
670
  }
726
671
  const newSources = val.sources.flatMap(toHtmlPictureSources);
727
- console.log('MarcyImageComponent newSources', newSources);
728
- this.sources.push(...newSources);
729
- this.$status.next(MediaStatus.NotLoaded);
730
- this.cd.detectChanges();
731
- }
732
- set objectFit(val) {
733
- this._objectFit = val ?? MediaObjectFit.Original;
734
- this.cd.detectChanges();
735
- }
736
- get objectFit() {
737
- return this._objectFit;
672
+ this.sources.set(newSources);
673
+ this.status.set(MediaStatus.NotLoaded);
738
674
  }
739
675
  onLoad() {
740
- this.$status.next(MediaStatus.Loaded);
676
+ this.status.set(MediaStatus.Loaded);
741
677
  }
742
678
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: MarcyImageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
743
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: MarcyImageComponent, isStandalone: true, selector: "bon-image", inputs: { objectFit: "objectFit" }, outputs: { isLoaded: "isLoaded" }, providers: [UnsubscriberService], ngImport: i0, template: "<div *ngIf=\"sources.length > 0\"\n [class.knownRatio]=\"src.ratio() > 0 && objectFit === MarcyObjectFit.Original\"\n [class.cover]=\"objectFit === MarcyObjectFit.Cover\"\n [class.contain]=\"objectFit === MarcyObjectFit.Contain\"\n [class.loaded]=\"($status | async) === MediaStatus.Loaded\"\n class=\"picture-container\">\n\n <ng-template #pictureTemplate>\n <picture>\n <source *ngFor=\"let source of sources\"\n [srcset]=\"source.srcSet\"\n [attr.media]=\"source.media.length > 0 ? source.media : undefined\"\n [attr.type]=\"source.mime.length > 0 ? source.mime : undefined\"\n [attr.sizes]=\"source.sizes.length > 0 ? source.sizes : undefined\" />\n\n <img [src]=\"defaultSrc\" (load)=\"onLoad()\" />\n </picture>\n </ng-template>\n\n <noscript *ngIf=\"device.isSSR\">\n <ng-container *ngTemplateOutlet=\"pictureTemplate\"></ng-container>\n </noscript>\n\n <bon-intersection #intersectionZone *ngIf=\"!device.isSSR\" [session]=\"src\" (intersected)=\"cd.detectChanges()\">\n\n <ng-container *ngIf=\"intersectionZone.intersectedOnce()\">\n <ng-container *ngTemplateOutlet=\"pictureTemplate\"></ng-container>\n </ng-container>\n\n </bon-intersection>\n\n <div *ngIf=\"src.ratio() > 0 && objectFit === MarcyObjectFit.Original\" [style.padding-top]=\"100 / src.ratio() +'%'\"></div>\n</div>\n", styles: [":host{display:block}.picture-container{overflow:hidden}.picture-container.cover picture,.picture-container.cover bon-intersection,.picture-container.contain picture,.picture-container.contain bon-intersection,.picture-container.knownRatio picture,.picture-container.knownRatio bon-intersection{width:100%;height:100%}.picture-container.cover picture>img,.picture-container.cover bon-intersection>img,.picture-container.contain picture>img,.picture-container.contain bon-intersection>img,.picture-container.knownRatio picture>img,.picture-container.knownRatio bon-intersection>img{height:100%}.picture-container.cover{height:100%}.picture-container.cover picture>img{object-fit:cover}.picture-container.contain{height:100%}.picture-container.contain picture>img{object-fit:contain}.picture-container.knownRatio{position:relative}.picture-container.knownRatio picture{position:absolute}.picture-container.knownRatio picture>img{object-fit:fill}picture{display:block;backface-visibility:hidden}picture>img{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IntersectionComponent, selector: "bon-intersection", inputs: ["session"], outputs: ["intersected"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] });
679
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: MarcyImageComponent, isStandalone: true, selector: "bon-image", inputs: { objectFit: { classPropertyName: "objectFit", publicName: "objectFit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isLoaded: "isLoaded" }, ngImport: i0, template: "@if (sources().length > 0) {\n <div [class.knownRatio]=\"src.ratio() > 0 && objectFit() === MarcyObjectFit.Original\"\n [class.cover]=\"objectFit() === MarcyObjectFit.Cover\"\n [class.contain]=\"objectFit() === MarcyObjectFit.Contain\"\n [class.loaded]=\"status() === MediaStatus.Loaded\"\n class=\"picture-container\">\n\n <ng-template #pictureTemplate>\n <picture>\n @for (source of sources(); track $index) {\n <source [srcset]=\"source.srcSet\"\n [attr.media]=\"source.media.length > 0 ? source.media : undefined\"\n [attr.type]=\"source.mime.length > 0 ? source.mime : undefined\"\n [attr.sizes]=\"source.sizes.length > 0 ? source.sizes : undefined\" />\n }\n <img [src]=\"defaultSrc()\" (load)=\"onLoad()\" alt=\"\" />\n </picture>\n </ng-template>\n\n @if (device.isSSR) {\n <noscript>\n <ng-container *ngTemplateOutlet=\"pictureTemplate\"></ng-container>\n </noscript>\n } @else {\n <bon-intersection #intersectionZone [session]=\"src\">\n @if (intersectionZone.isIntersected()) {\n <ng-container *ngTemplateOutlet=\"pictureTemplate\"></ng-container>\n }\n </bon-intersection>\n }\n\n @if (src.ratio() > 0 && objectFit() === MarcyObjectFit.Original) {\n <div [style.padding-top]=\"100 / src.ratio() +'%'\"></div>\n }\n </div>\n}\n", styles: [":host{display:block}.picture-container{overflow:hidden}.picture-container.cover picture,.picture-container.cover bon-intersection,.picture-container.contain picture,.picture-container.contain bon-intersection,.picture-container.knownRatio picture,.picture-container.knownRatio bon-intersection{width:100%;height:100%}.picture-container.cover picture>img,.picture-container.cover bon-intersection>img,.picture-container.contain picture>img,.picture-container.contain bon-intersection>img,.picture-container.knownRatio picture>img,.picture-container.knownRatio bon-intersection>img{height:100%}.picture-container.cover{height:100%}.picture-container.cover picture>img{object-fit:cover}.picture-container.contain{height:100%}.picture-container.contain picture>img{object-fit:contain}.picture-container.knownRatio{position:relative}.picture-container.knownRatio picture{position:absolute}.picture-container.knownRatio picture>img{object-fit:fill}picture{display:block;backface-visibility:hidden}picture>img{display:block;width:100%}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IntersectionComponent, selector: "bon-intersection", inputs: ["session"], outputs: ["intersected"] }] });
744
680
  }
745
681
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: MarcyImageComponent, decorators: [{
746
682
  type: Component,
747
- args: [{ selector: 'bon-image', standalone: true, imports: [CommonModule, AsyncPipe, IntersectionComponent], providers: [UnsubscriberService], template: "<div *ngIf=\"sources.length > 0\"\n [class.knownRatio]=\"src.ratio() > 0 && objectFit === MarcyObjectFit.Original\"\n [class.cover]=\"objectFit === MarcyObjectFit.Cover\"\n [class.contain]=\"objectFit === MarcyObjectFit.Contain\"\n [class.loaded]=\"($status | async) === MediaStatus.Loaded\"\n class=\"picture-container\">\n\n <ng-template #pictureTemplate>\n <picture>\n <source *ngFor=\"let source of sources\"\n [srcset]=\"source.srcSet\"\n [attr.media]=\"source.media.length > 0 ? source.media : undefined\"\n [attr.type]=\"source.mime.length > 0 ? source.mime : undefined\"\n [attr.sizes]=\"source.sizes.length > 0 ? source.sizes : undefined\" />\n\n <img [src]=\"defaultSrc\" (load)=\"onLoad()\" />\n </picture>\n </ng-template>\n\n <noscript *ngIf=\"device.isSSR\">\n <ng-container *ngTemplateOutlet=\"pictureTemplate\"></ng-container>\n </noscript>\n\n <bon-intersection #intersectionZone *ngIf=\"!device.isSSR\" [session]=\"src\" (intersected)=\"cd.detectChanges()\">\n\n <ng-container *ngIf=\"intersectionZone.intersectedOnce()\">\n <ng-container *ngTemplateOutlet=\"pictureTemplate\"></ng-container>\n </ng-container>\n\n </bon-intersection>\n\n <div *ngIf=\"src.ratio() > 0 && objectFit === MarcyObjectFit.Original\" [style.padding-top]=\"100 / src.ratio() +'%'\"></div>\n</div>\n", styles: [":host{display:block}.picture-container{overflow:hidden}.picture-container.cover picture,.picture-container.cover bon-intersection,.picture-container.contain picture,.picture-container.contain bon-intersection,.picture-container.knownRatio picture,.picture-container.knownRatio bon-intersection{width:100%;height:100%}.picture-container.cover picture>img,.picture-container.cover bon-intersection>img,.picture-container.contain picture>img,.picture-container.contain bon-intersection>img,.picture-container.knownRatio picture>img,.picture-container.knownRatio bon-intersection>img{height:100%}.picture-container.cover{height:100%}.picture-container.cover picture>img{object-fit:cover}.picture-container.contain{height:100%}.picture-container.contain picture>img{object-fit:contain}.picture-container.knownRatio{position:relative}.picture-container.knownRatio picture{position:absolute}.picture-container.knownRatio picture>img{object-fit:fill}picture{display:block;backface-visibility:hidden}picture>img{display:block;width:100%}\n"] }]
748
- }], ctorParameters: () => [], propDecorators: { isLoaded: [{
749
- type: Output
750
- }], objectFit: [{
751
- type: Input
752
- }] } });
683
+ args: [{ selector: "bon-image", imports: [NgTemplateOutlet, IntersectionComponent], template: "@if (sources().length > 0) {\n <div [class.knownRatio]=\"src.ratio() > 0 && objectFit() === MarcyObjectFit.Original\"\n [class.cover]=\"objectFit() === MarcyObjectFit.Cover\"\n [class.contain]=\"objectFit() === MarcyObjectFit.Contain\"\n [class.loaded]=\"status() === MediaStatus.Loaded\"\n class=\"picture-container\">\n\n <ng-template #pictureTemplate>\n <picture>\n @for (source of sources(); track $index) {\n <source [srcset]=\"source.srcSet\"\n [attr.media]=\"source.media.length > 0 ? source.media : undefined\"\n [attr.type]=\"source.mime.length > 0 ? source.mime : undefined\"\n [attr.sizes]=\"source.sizes.length > 0 ? source.sizes : undefined\" />\n }\n <img [src]=\"defaultSrc()\" (load)=\"onLoad()\" alt=\"\" />\n </picture>\n </ng-template>\n\n @if (device.isSSR) {\n <noscript>\n <ng-container *ngTemplateOutlet=\"pictureTemplate\"></ng-container>\n </noscript>\n } @else {\n <bon-intersection #intersectionZone [session]=\"src\">\n @if (intersectionZone.isIntersected()) {\n <ng-container *ngTemplateOutlet=\"pictureTemplate\"></ng-container>\n }\n </bon-intersection>\n }\n\n @if (src.ratio() > 0 && objectFit() === MarcyObjectFit.Original) {\n <div [style.padding-top]=\"100 / src.ratio() +'%'\"></div>\n }\n </div>\n}\n", styles: [":host{display:block}.picture-container{overflow:hidden}.picture-container.cover picture,.picture-container.cover bon-intersection,.picture-container.contain picture,.picture-container.contain bon-intersection,.picture-container.knownRatio picture,.picture-container.knownRatio bon-intersection{width:100%;height:100%}.picture-container.cover picture>img,.picture-container.cover bon-intersection>img,.picture-container.contain picture>img,.picture-container.contain bon-intersection>img,.picture-container.knownRatio picture>img,.picture-container.knownRatio bon-intersection>img{height:100%}.picture-container.cover{height:100%}.picture-container.cover picture>img{object-fit:cover}.picture-container.contain{height:100%}.picture-container.contain picture>img{object-fit:contain}.picture-container.knownRatio{position:relative}.picture-container.knownRatio picture{position:absolute}.picture-container.knownRatio picture>img{object-fit:fill}picture{display:block;backface-visibility:hidden}picture>img{display:block;width:100%}\n"] }]
684
+ }], ctorParameters: () => [], propDecorators: { isLoaded: [{ type: i0.Output, args: ["isLoaded"] }], objectFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "objectFit", required: false }] }] } });
753
685
 
754
686
  class VideoSrcDirective extends SrcBaseDirective {
755
- set vidsrc(value) {
756
- this.data = value;
757
- console.log('set vidsrc', value);
758
- }
687
+ data = model(undefined, { ...(ngDevMode ? { debugName: "data" } : {}), alias: "vidsrc" });
759
688
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: VideoSrcDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
760
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.6", type: VideoSrcDirective, isStandalone: true, selector: "[vidsrc]", inputs: { vidsrc: "vidsrc" }, usesInheritance: true, ngImport: i0 });
689
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.6", type: VideoSrcDirective, isStandalone: true, selector: "[vidsrc]", inputs: { data: { classPropertyName: "data", publicName: "vidsrc", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { data: "vidsrcChange" }, usesInheritance: true, ngImport: i0 });
761
690
  }
762
691
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: VideoSrcDirective, decorators: [{
763
692
  type: Directive,
764
693
  args: [{
765
- standalone: true,
766
- selector: '[vidsrc]',
694
+ selector: "[vidsrc]",
767
695
  }]
768
- }], propDecorators: { vidsrc: [{
769
- type: Input
770
- }] } });
696
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "vidsrc", required: false }] }, { type: i0.Output, args: ["vidsrcChange"] }] } });
771
697
 
772
698
  function isWebM(src) {
773
- return src.mimeType === 'video/webm';
699
+ return src.mimeType === "video/webm";
774
700
  }
775
701
  class MarcyVideoComponent {
776
702
  MediaStatus = MediaStatus;
777
703
  MarcyObjectFit = MediaObjectFit;
778
- videoRef;
779
- isLoaded = new EventEmitter();
780
- $status = signal(MediaStatus.NotSet, ...(ngDevMode ? [{ debugName: "$status" }] : []));
781
704
  src;
782
- _effectCleanup;
783
- source;
784
- _objectFit = MediaObjectFit.Original;
705
+ isLoaded = output();
706
+ objectFit = input(MediaObjectFit.Original, ...(ngDevMode ? [{ debugName: "objectFit" }] : []));
707
+ videoRef = viewChild("video", ...(ngDevMode ? [{ debugName: "videoRef" }] : []));
708
+ status = signal(MediaStatus.NotSet, ...(ngDevMode ? [{ debugName: "status" }] : []));
709
+ source = signal(undefined, ...(ngDevMode ? [{ debugName: "source" }] : []));
785
710
  device = inject(DeviceServiceBase);
786
- cd = inject(ChangeDetectorRef);
787
- _u = inject(UnsubscriberService);
788
711
  _srcDir = inject(VideoSrcDirective, { optional: true });
789
712
  constructor() {
790
- console.log('MarcyVideoComponent ctor');
791
- if (this._srcDir === undefined || this._srcDir === null)
713
+ if (this._srcDir === undefined || this._srcDir === null) {
792
714
  throw new Error(`${MarcyVideoComponent.name} should have [vidsrc] directive as source object`);
715
+ }
793
716
  this.src = this._srcDir;
794
- this.cd.detach();
795
- // Watch for status changes and emit when loaded
796
- this._effectCleanup = effect(() => {
797
- if (this.$status() === MediaStatus.Loaded) {
798
- this.isLoaded.next();
799
- }
800
- }, ...(ngDevMode ? [{ debugName: "_effectCleanup" }] : []));
801
- }
802
- ngOnInit() {
803
- console.log('MarcyVideoComponent ngOnInit');
804
- this.cd.detectChanges();
805
- }
806
- ngAfterViewInit() {
807
- console.log('MarcyVideoComponent ngAfterViewInit');
808
- // bind src changes
809
- this.src.srcChange
810
- .pipe(this._u.takeUntilDestroy)
811
- .subscribe((val) => {
812
- console.log('MarcyVideoComponent onSrcChange', val);
717
+ effect(() => {
718
+ this.src.data();
719
+ this.videoRef();
813
720
  this.updateSources();
814
- // resubscribe because its updated with src
815
721
  this.subscribeToMediaQueryChange();
816
722
  });
817
- this.updateSources();
818
- // initial, for src added before init
819
- this.subscribeToMediaQueryChange();
723
+ effect(() => {
724
+ if (this.status() === MediaStatus.Loaded) {
725
+ this.isLoaded.emit();
726
+ }
727
+ });
820
728
  }
821
729
  subscribeToMediaQueryChange() {
822
- this.src
823
- .watchMediaQueries()
824
- .subscribe(() => {
825
- console.log('MarcyVideoComponent watchMediaQueries');
730
+ this.src.watchMediaQueries().subscribe(() => {
731
+ console.log("MarcyVideoComponent watchMediaQueries");
826
732
  this.updateSources();
827
733
  });
828
734
  }
829
735
  updateSources() {
830
- console.log('MarcyVideoComponent updateSources');
831
- this.source = this.findMoreSuitableSource();
832
- console.log('MarcyVideoComponent new source', this.source);
833
- if (this.$status() === MediaStatus.NotSet && this.source === undefined) {
736
+ console.log("MarcyVideoComponent updateSources");
737
+ this.source.set(this.findMoreSuitableSource());
738
+ console.log("MarcyVideoComponent new source", this.source());
739
+ const src = this.source();
740
+ if (this.status() === MediaStatus.NotSet && src === undefined) {
834
741
  return;
835
742
  }
836
- if (this.source === undefined) {
837
- this.$status.set(MediaStatus.NotSet);
838
- this.cd.detectChanges();
743
+ if (src === undefined) {
744
+ this.status.set(MediaStatus.NotSet);
839
745
  return;
840
746
  }
841
- this.$status.set(MediaStatus.NotLoaded);
842
- this.cd.detectChanges();
843
- }
844
- set objectFit(val) {
845
- this._objectFit = val ?? MediaObjectFit.Original;
846
- this.cd.detectChanges();
847
- }
848
- get objectFit() {
849
- return this._objectFit;
747
+ this.status.set(MediaStatus.NotLoaded);
850
748
  }
851
749
  onLoad() {
852
- this.$status.set(MediaStatus.Loaded);
750
+ this.status.set(MediaStatus.Loaded);
853
751
  }
854
752
  findMoreSuitableSource() {
855
- if (this.videoRef === undefined) {
856
- console.log('skipping findMoreSuitableSource. videoRef is empty still');
753
+ const ref = this.videoRef();
754
+ if (ref === undefined) {
755
+ console.log("skipping findMoreSuitableSource. videoRef is empty still");
857
756
  return;
858
757
  }
859
- const videoSources = this.src.data?.sources ?? [];
860
- const currentVideoWidth = this.videoRef.nativeElement.clientWidth;
758
+ const videoSources = this.src.data()?.sources ?? [];
759
+ const currentVideoWidth = ref.nativeElement.clientWidth;
861
760
  const realPixelsVideoWidth = this.device.devicePixelRatio * currentVideoWidth;
862
761
  console.log(`MarcyVideoComponent currentVideoWidth ${currentVideoWidth}`);
863
762
  console.log(`MarcyVideoComponent realPixelsVideoWidth ${realPixelsVideoWidth}`);
864
763
  for (let i = 0; i < videoSources.length; i++) {
865
764
  const videoSource = videoSources[i];
866
- if (!matchesMediaQuery(videoSource.mediaQuery))
765
+ if (!matchesMediaQuery(videoSource.mediaQuery)) {
867
766
  continue;
767
+ }
868
768
  // SSR
869
- if (typeof this.videoRef.nativeElement?.canPlayType !== 'function') {
870
- // return first mp4, because all players can play them
871
- const mp4Srcs = videoSource
872
- .srcSet
873
- .filter(x => x.mimeType === 'video/mp4')
874
- .sort(descendingT(x => x.meta.width)); // bigest video
875
- // console.log(`ssr found video ${mp4Srcs[0].url}`)
876
- // element or undefined
769
+ if (typeof ref.nativeElement.canPlayType !== "function") {
770
+ const mp4Srcs = videoSource.srcSet
771
+ .filter((x) => x.mimeType === "video/mp4")
772
+ .sort(descendingT((x) => x.meta.width));
877
773
  return mp4Srcs[0];
878
774
  }
879
- const fileSrcs = videoSource
880
- .srcSet
881
- .filter(x => this.videoRef.nativeElement.canPlayType(x.mimeType))
775
+ const fileSrcs = videoSource.srcSet
776
+ .filter((x) => ref.nativeElement.canPlayType(x.mimeType))
882
777
  .sort((a, b) => {
883
778
  if (a.meta.width === b.meta.width) {
884
779
  return isWebM(a) ? -1 : 1; // if same width prefer webM
@@ -886,8 +781,9 @@ class MarcyVideoComponent {
886
781
  // else prefer smallest
887
782
  return a.meta.width <= b.meta.width ? -1 : 1;
888
783
  }); // smallest video
889
- if (fileSrcs.length === 0)
784
+ if (fileSrcs.length === 0) {
890
785
  continue;
786
+ }
891
787
  // console.log('sources ', fileSrcs);
892
788
  let bestSrc = fileSrcs[0];
893
789
  for (let i = 1; i < fileSrcs.length; i++) {
@@ -895,8 +791,9 @@ class MarcyVideoComponent {
895
791
  const currentDiff = fileSrc.meta.width - realPixelsVideoWidth;
896
792
  // console.log(`browser video currentDiff ${currentDiff}`)
897
793
  // too big video source width
898
- if (currentDiff > 0)
794
+ if (currentDiff > 0) {
899
795
  break;
796
+ }
900
797
  bestSrc = fileSrc;
901
798
  }
902
799
  console.log(`browser found suitable video ${bestSrc.url}`);
@@ -904,111 +801,56 @@ class MarcyVideoComponent {
904
801
  }
905
802
  return undefined;
906
803
  }
907
- ngOnDestroy() {
908
- this._effectCleanup?.destroy();
909
- }
910
804
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: MarcyVideoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
911
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: MarcyVideoComponent, isStandalone: true, selector: "bon-video", inputs: { objectFit: "objectFit" }, outputs: { isLoaded: "isLoaded" }, providers: [UnsubscriberService], viewQueries: [{ propertyName: "videoRef", first: true, predicate: ["video"], descendants: true }], ngImport: i0, template: "<div [class.knownRatio]=\"src.ratio() > 0 && objectFit === MarcyObjectFit.Original\"\n [class.cover]=\"objectFit === MarcyObjectFit.Cover\"\n [class.contain]=\"objectFit === MarcyObjectFit.Contain\"\n [class.loaded]=\"$status() === MediaStatus.Loaded\"\n class=\"video-container\">\n\n <ng-container *ngIf=\"device.isSSR ; then ssrTemplate else browserTemplate\"></ng-container>\n\n <ng-template #videoTemplate>\n <video #video\n [src]=\"source !== undefined ? source.url :'' \"\n (load)=\"onLoad()\"\n (canplay)=\"video.muted=true;video.play();\"\n playsInline\n autoplay\n loop\n muted> </video>\n </ng-template>\n\n <ng-template #ssrTemplate>\n <noscript *ngIf=\"device.isSSR\">\n <ng-container *ngTemplateOutlet=\"videoTemplate\"></ng-container>\n </noscript>\n </ng-template>\n\n <ng-template #browserTemplate>\n <bon-intersection #intersectionZone [session]=\"src\" (intersected)=\"cd.detectChanges()\">\n <ng-container *ngTemplateOutlet=\"videoTemplate\"></ng-container>\n </bon-intersection>\n </ng-template>\n\n <div *ngIf=\"src.ratio() > 0 && objectFit === MarcyObjectFit.Original\" [style.padding-top]=\"100 / src.ratio() +'%'\"></div>\n</div>\n", styles: [":host{display:block}.video-container{background-color:#000;overflow:hidden}.video-container.cover video,.video-container.cover bon-intersection,.video-container.contain video,.video-container.contain bon-intersection,.video-container.knownRatio video,.video-container.knownRatio bon-intersection{width:100%;height:100%}.video-container.cover{height:100%}.video-container.cover video{object-fit:cover}.video-container.contain{height:100%}.video-container.contain video{object-fit:contain}.video-container.knownRatio{position:relative}.video-container.knownRatio video{position:absolute;object-fit:fill}video{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IntersectionComponent, selector: "bon-intersection", inputs: ["session"], outputs: ["intersected"] }] });
805
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: MarcyVideoComponent, isStandalone: true, selector: "bon-video", inputs: { objectFit: { classPropertyName: "objectFit", publicName: "objectFit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isLoaded: "isLoaded" }, viewQueries: [{ propertyName: "videoRef", first: true, predicate: ["video"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n [class.knownRatio]=\"\n src.ratio() > 0 && objectFit() === MarcyObjectFit.Original\n \"\n [class.cover]=\"objectFit() === MarcyObjectFit.Cover\"\n [class.contain]=\"objectFit() === MarcyObjectFit.Contain\"\n [class.loaded]=\"status() === MediaStatus.Loaded\"\n class=\"video-container\"\n>\n @if (device.isSSR) {\n <ng-container *ngTemplateOutlet=\"ssrTemplate\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"browserTemplate\"></ng-container>\n }\n\n <ng-template #videoTemplate>\n <video\n #video\n [src]=\"source()?.url ?? ''\"\n (load)=\"onLoad()\"\n (canplay)=\"video.muted = true; video.play()\"\n playsInline\n autoplay\n loop\n muted\n ></video>\n </ng-template>\n\n <ng-template #ssrTemplate>\n @if (device.isSSR) {\n <noscript>\n <ng-container *ngTemplateOutlet=\"videoTemplate\"></ng-container>\n </noscript>\n }\n </ng-template>\n\n <ng-template #browserTemplate>\n <bon-intersection #intersectionZone [session]=\"src\">\n <ng-container *ngTemplateOutlet=\"videoTemplate\"></ng-container>\n </bon-intersection>\n </ng-template>\n\n @if (src.ratio() > 0 && objectFit() === MarcyObjectFit.Original) {\n <div [style.padding-top]=\"100 / src.ratio() + '%'\"></div>\n }\n</div>\n", styles: [":host{display:block}.video-container{background-color:#000;overflow:hidden}.video-container.cover video,.video-container.cover bon-intersection,.video-container.contain video,.video-container.contain bon-intersection,.video-container.knownRatio video,.video-container.knownRatio bon-intersection{width:100%;height:100%}.video-container.cover{height:100%}.video-container.cover video{object-fit:cover}.video-container.contain{height:100%}.video-container.contain video{object-fit:contain}.video-container.knownRatio{position:relative}.video-container.knownRatio video{position:absolute;object-fit:fill}video{display:block;width:100%}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IntersectionComponent, selector: "bon-intersection", inputs: ["session"], outputs: ["intersected"] }] });
912
806
  }
913
807
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: MarcyVideoComponent, decorators: [{
914
808
  type: Component,
915
- args: [{ selector: 'bon-video', standalone: true, imports: [CommonModule, IntersectionComponent], providers: [UnsubscriberService], template: "<div [class.knownRatio]=\"src.ratio() > 0 && objectFit === MarcyObjectFit.Original\"\n [class.cover]=\"objectFit === MarcyObjectFit.Cover\"\n [class.contain]=\"objectFit === MarcyObjectFit.Contain\"\n [class.loaded]=\"$status() === MediaStatus.Loaded\"\n class=\"video-container\">\n\n <ng-container *ngIf=\"device.isSSR ; then ssrTemplate else browserTemplate\"></ng-container>\n\n <ng-template #videoTemplate>\n <video #video\n [src]=\"source !== undefined ? source.url :'' \"\n (load)=\"onLoad()\"\n (canplay)=\"video.muted=true;video.play();\"\n playsInline\n autoplay\n loop\n muted> </video>\n </ng-template>\n\n <ng-template #ssrTemplate>\n <noscript *ngIf=\"device.isSSR\">\n <ng-container *ngTemplateOutlet=\"videoTemplate\"></ng-container>\n </noscript>\n </ng-template>\n\n <ng-template #browserTemplate>\n <bon-intersection #intersectionZone [session]=\"src\" (intersected)=\"cd.detectChanges()\">\n <ng-container *ngTemplateOutlet=\"videoTemplate\"></ng-container>\n </bon-intersection>\n </ng-template>\n\n <div *ngIf=\"src.ratio() > 0 && objectFit === MarcyObjectFit.Original\" [style.padding-top]=\"100 / src.ratio() +'%'\"></div>\n</div>\n", styles: [":host{display:block}.video-container{background-color:#000;overflow:hidden}.video-container.cover video,.video-container.cover bon-intersection,.video-container.contain video,.video-container.contain bon-intersection,.video-container.knownRatio video,.video-container.knownRatio bon-intersection{width:100%;height:100%}.video-container.cover{height:100%}.video-container.cover video{object-fit:cover}.video-container.contain{height:100%}.video-container.contain video{object-fit:contain}.video-container.knownRatio{position:relative}.video-container.knownRatio video{position:absolute;object-fit:fill}video{display:block;width:100%}\n"] }]
916
- }], ctorParameters: () => [], propDecorators: { videoRef: [{
917
- type: ViewChild,
918
- args: ['video']
919
- }], isLoaded: [{
920
- type: Output
921
- }], objectFit: [{
922
- type: Input
923
- }] } });
809
+ args: [{ selector: "bon-video", imports: [NgTemplateOutlet, IntersectionComponent], template: "<div\n [class.knownRatio]=\"\n src.ratio() > 0 && objectFit() === MarcyObjectFit.Original\n \"\n [class.cover]=\"objectFit() === MarcyObjectFit.Cover\"\n [class.contain]=\"objectFit() === MarcyObjectFit.Contain\"\n [class.loaded]=\"status() === MediaStatus.Loaded\"\n class=\"video-container\"\n>\n @if (device.isSSR) {\n <ng-container *ngTemplateOutlet=\"ssrTemplate\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"browserTemplate\"></ng-container>\n }\n\n <ng-template #videoTemplate>\n <video\n #video\n [src]=\"source()?.url ?? ''\"\n (load)=\"onLoad()\"\n (canplay)=\"video.muted = true; video.play()\"\n playsInline\n autoplay\n loop\n muted\n ></video>\n </ng-template>\n\n <ng-template #ssrTemplate>\n @if (device.isSSR) {\n <noscript>\n <ng-container *ngTemplateOutlet=\"videoTemplate\"></ng-container>\n </noscript>\n }\n </ng-template>\n\n <ng-template #browserTemplate>\n <bon-intersection #intersectionZone [session]=\"src\">\n <ng-container *ngTemplateOutlet=\"videoTemplate\"></ng-container>\n </bon-intersection>\n </ng-template>\n\n @if (src.ratio() > 0 && objectFit() === MarcyObjectFit.Original) {\n <div [style.padding-top]=\"100 / src.ratio() + '%'\"></div>\n }\n</div>\n", styles: [":host{display:block}.video-container{background-color:#000;overflow:hidden}.video-container.cover video,.video-container.cover bon-intersection,.video-container.contain video,.video-container.contain bon-intersection,.video-container.knownRatio video,.video-container.knownRatio bon-intersection{width:100%;height:100%}.video-container.cover{height:100%}.video-container.cover video{object-fit:cover}.video-container.contain{height:100%}.video-container.contain video{object-fit:contain}.video-container.knownRatio{position:relative}.video-container.knownRatio video{position:absolute;object-fit:fill}video{display:block;width:100%}\n"] }]
810
+ }], ctorParameters: () => [], propDecorators: { isLoaded: [{ type: i0.Output, args: ["isLoaded"] }], objectFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "objectFit", required: false }] }], videoRef: [{ type: i0.ViewChild, args: ["video", { isSignal: true }] }] } });
924
811
 
925
812
  class MarcyMediaComponent {
926
- cd = inject(ChangeDetectorRef);
927
813
  MarcyObjectFit = MediaObjectFit;
928
- isLoaded = new EventEmitter();
929
- _objectFit = MediaObjectFit.Original;
930
- _src;
931
- constructor() {
932
- const cd = this.cd;
933
- console.log('MarcyMediaComponent ctor');
934
- cd.detach();
935
- }
936
- ngOnInit() {
937
- console.log('MarcyMediaComponent ngOnInit');
938
- this.cd.detectChanges();
939
- }
940
- get src() {
941
- return this._src;
942
- }
943
- set src(val) {
944
- console.log('set data', val);
945
- this._src = val;
946
- this.cd.detectChanges();
947
- }
948
- set objectFit(val) {
949
- this._objectFit = val ?? MediaObjectFit.Original;
950
- this.cd.detectChanges();
951
- }
952
- get objectFit() {
953
- return this._objectFit;
954
- }
814
+ isLoaded = output();
815
+ src = input(...(ngDevMode ? [undefined, { debugName: "src" }] : []));
816
+ objectFit = input(MediaObjectFit.Original, ...(ngDevMode ? [{ debugName: "objectFit" }] : []));
955
817
  onLoad() {
956
- this.isLoaded.next();
818
+ this.isLoaded.emit();
957
819
  }
958
820
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: MarcyMediaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
959
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: MarcyMediaComponent, isStandalone: true, selector: "bon-media", inputs: { src: "src", objectFit: "objectFit" }, outputs: { isLoaded: "isLoaded" }, providers: [UnsubscriberService], ngImport: i0, template: "<bon-image *ngIf=\"src && src.type==='image'\"\n [imgsrc]=\"src\"\n [objectFit]=\"objectFit\"\n (isLoaded)=\"onLoad()\"></bon-image>\n\n<bon-video *ngIf=\"src && src.type==='video'\"\n [vidsrc]=\"src\"\n [objectFit]=\"objectFit\"\n (isLoaded)=\"onLoad()\"></bon-video>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: MarcyImageComponent, selector: "bon-image", inputs: ["objectFit"], outputs: ["isLoaded"] }, { kind: "component", type: MarcyVideoComponent, selector: "bon-video", inputs: ["objectFit"], outputs: ["isLoaded"] }, { kind: "directive", type: VideoSrcDirective, selector: "[vidsrc]", inputs: ["vidsrc"] }, { kind: "directive", type: ImageSrcDirective, selector: "[imgsrc]", inputs: ["imgsrc"] }] });
821
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: MarcyMediaComponent, isStandalone: true, selector: "bon-media", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, objectFit: { classPropertyName: "objectFit", publicName: "objectFit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isLoaded: "isLoaded" }, ngImport: i0, template: "@if (src(); as mediaSrc) {\n @if (mediaSrc.type === 'image') {\n <bon-image\n [imgsrc]=\"mediaSrc\"\n [objectFit]=\"objectFit()\"\n (isLoaded)=\"onLoad()\"\n ></bon-image>\n } @else if (mediaSrc.type === 'video') {\n <bon-video\n [vidsrc]=\"mediaSrc\"\n [objectFit]=\"objectFit()\"\n (isLoaded)=\"onLoad()\"\n ></bon-video>\n }\n}\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: MarcyImageComponent, selector: "bon-image", inputs: ["objectFit"], outputs: ["isLoaded"] }, { kind: "component", type: MarcyVideoComponent, selector: "bon-video", inputs: ["objectFit"], outputs: ["isLoaded"] }, { kind: "directive", type: VideoSrcDirective, selector: "[vidsrc]", inputs: ["vidsrc"], outputs: ["vidsrcChange"] }, { kind: "directive", type: ImageSrcDirective, selector: "[imgsrc]", inputs: ["imgsrc"], outputs: ["imgsrcChange"] }] });
960
822
  }
961
823
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: MarcyMediaComponent, decorators: [{
962
824
  type: Component,
963
- args: [{ selector: 'bon-media', standalone: true, imports: [CommonModule, MarcyImageComponent, MarcyVideoComponent, VideoSrcDirective, ImageSrcDirective], providers: [UnsubscriberService], template: "<bon-image *ngIf=\"src && src.type==='image'\"\n [imgsrc]=\"src\"\n [objectFit]=\"objectFit\"\n (isLoaded)=\"onLoad()\"></bon-image>\n\n<bon-video *ngIf=\"src && src.type==='video'\"\n [vidsrc]=\"src\"\n [objectFit]=\"objectFit\"\n (isLoaded)=\"onLoad()\"></bon-video>\n", styles: [":host{display:block}\n"] }]
964
- }], ctorParameters: () => [], propDecorators: { isLoaded: [{
965
- type: Output
966
- }], src: [{
967
- type: Input
968
- }], objectFit: [{
969
- type: Input
970
- }] } });
825
+ args: [{ selector: "bon-media", imports: [MarcyImageComponent, MarcyVideoComponent, VideoSrcDirective, ImageSrcDirective], template: "@if (src(); as mediaSrc) {\n @if (mediaSrc.type === 'image') {\n <bon-image\n [imgsrc]=\"mediaSrc\"\n [objectFit]=\"objectFit()\"\n (isLoaded)=\"onLoad()\"\n ></bon-image>\n } @else if (mediaSrc.type === 'video') {\n <bon-video\n [vidsrc]=\"mediaSrc\"\n [objectFit]=\"objectFit()\"\n (isLoaded)=\"onLoad()\"\n ></bon-video>\n }\n}\n", styles: [":host{display:block}\n"] }]
826
+ }], propDecorators: { isLoaded: [{ type: i0.Output, args: ["isLoaded"] }], src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], objectFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "objectFit", required: false }] }] } });
971
827
 
972
- class BoneDirective {
973
- _bone;
974
- cd = inject(ChangeDetectorRef);
975
- localizationService = inject(LocalizeServiceBase);
976
- _effectCleanup;
977
- constructor() {
978
- this.cd.detach();
979
- // todo: check if this is needed
980
- // Watch locale changes using signal
981
- this._effectCleanup = effect(() => {
982
- // Access the signal to track changes
983
- this.localizationService.locale();
984
- // need to detect changes in our detached components
985
- this.cd.detectChanges();
986
- }, ...(ngDevMode ? [{ debugName: "_effectCleanup" }] : []));
987
- }
988
- ngOnInit() {
989
- }
990
- set bone(value) {
991
- this._bone = value;
992
- this.cd.detectChanges();
993
- }
994
- get bone() {
995
- if (this._bone === undefined || this._bone === null)
996
- throw new Error('The property "bone" should be set at least once. For example in skeleton');
997
- return this._bone;
998
- }
999
- ngOnDestroy() {
1000
- this._effectCleanup?.destroy();
828
+ class BoneMap extends Map {
829
+ getRequired(key) {
830
+ const value = this.get(key);
831
+ if (value === undefined || value === null) {
832
+ throw new Error(`BoneMap doesn't contain type for key = ${key}`);
833
+ }
834
+ return value;
1001
835
  }
836
+ }
837
+
838
+ class BoneDirective {
839
+ bone = model.required(...(ngDevMode ? [{ debugName: "bone" }] : []));
1002
840
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BoneDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1003
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.6", type: BoneDirective, isStandalone: true, selector: "[bonBoneDir]", ngImport: i0 });
841
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.6", type: BoneDirective, isStandalone: true, selector: "[bonBoneDir]", inputs: { bone: { classPropertyName: "bone", publicName: "bone", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { bone: "boneChange" }, ngImport: i0 });
1004
842
  }
1005
843
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BoneDirective, decorators: [{
1006
844
  type: Directive,
1007
845
  args: [{
1008
- selector: '[bonBoneDir]',
1009
- standalone: true
846
+ selector: "[bonBoneDir]",
1010
847
  }]
1011
- }], ctorParameters: () => [] });
848
+ }], propDecorators: { bone: [{ type: i0.Input, args: [{ isSignal: true, alias: "bone", required: true }] }, { type: i0.Output, args: ["boneChange"] }] } });
849
+ const BONE_DIRECTIVE_WITH_INPUTS_AND_OUTPUTS = {
850
+ directive: BoneDirective,
851
+ inputs: ["bone"],
852
+ outputs: ["boneChange"],
853
+ };
1012
854
 
1013
855
  class SkeletonAnchorDirective {
1014
856
  viewContainerRef = inject(ViewContainerRef);
@@ -1018,92 +860,65 @@ class SkeletonAnchorDirective {
1018
860
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SkeletonAnchorDirective, decorators: [{
1019
861
  type: Directive,
1020
862
  args: [{
1021
- selector: '[bonSkeletonAnchor]',
1022
- standalone: true
863
+ selector: "[bonSkeletonAnchor]",
1023
864
  }]
1024
865
  }] });
1025
866
 
1026
867
  class UnknownBoneComponent {
1027
- cd = inject(ChangeDetectorRef);
1028
868
  bd = inject((BoneDirective), { host: true });
1029
- constructor() {
1030
- console.log('BoneDirective', this.bd);
1031
- this.cd.detach();
1032
- }
1033
- ngOnInit() {
1034
- this.cd.detectChanges();
1035
- }
1036
869
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: UnknownBoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1037
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: UnknownBoneComponent, isStandalone: true, selector: "bon-unknown-bone", hostDirectives: [{ directive: BoneDirective }], ngImport: i0, template: `<h2>unknown bone {{bd.bone.type}}</h2>
1038
- <div>{{bd.bone | json}}</div>`, isInline: true, styles: [":host{display:block;border:2px solid red;box-sizing:border-box}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.JsonPipe, name: "json" }] });
870
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: UnknownBoneComponent, isStandalone: true, selector: "bon-unknown-bone", hostDirectives: [{ directive: BoneDirective, inputs: ["bone", "bone"], outputs: ["boneChange", "boneChange"] }], ngImport: i0, template: `@if (bd.bone(); as bone) {
871
+ <h2>unknown bone {{bone.type}}</h2>
872
+ <div>{{bone | json}}</div>
873
+ } @else{
874
+ bone is undefined
875
+ }`, isInline: true, styles: [":host{display:block;border:2px solid red;box-sizing:border-box}\n"], dependencies: [{ kind: "pipe", type: JsonPipe, name: "json" }] });
1039
876
  }
1040
877
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: UnknownBoneComponent, decorators: [{
1041
878
  type: Component,
1042
- args: [{ selector: 'bon-unknown-bone', standalone: true, imports: [CommonModule, JsonPipe], hostDirectives: [BoneDirective], template: `<h2>unknown bone {{bd.bone.type}}</h2>
1043
- <div>{{bd.bone | json}}</div>`, styles: [":host{display:block;border:2px solid red;box-sizing:border-box}\n"] }]
1044
- }], ctorParameters: () => [] });
879
+ args: [{ selector: "bon-unknown-bone", imports: [JsonPipe], hostDirectives: [{ directive: BoneDirective, inputs: ["bone"], outputs: ["boneChange"] }], template: `@if (bd.bone(); as bone) {
880
+ <h2>unknown bone {{bone.type}}</h2>
881
+ <div>{{bone | json}}</div>
882
+ } @else{
883
+ bone is undefined
884
+ }`, styles: [":host{display:block;border:2px solid red;box-sizing:border-box}\n"] }]
885
+ }] });
1045
886
 
1046
887
  class SkeletonComponent {
1047
- skeletonAnchor;
1048
- map;
1049
- _bones = [];
1050
- iniailized = false;
1051
- cd = inject(ChangeDetectorRef);
1052
- ngOnInit() {
1053
- this.iniailized = true;
1054
- this.fillComponentFromBones();
1055
- }
1056
- set bones(newValue) {
1057
- this._bones.splice(0, this._bones.length);
1058
- this._bones.push(...newValue ?? []);
1059
- this.fillComponentFromBones();
1060
- }
1061
- fillComponentFromBones() {
1062
- if (this.iniailized === false)
1063
- return;
1064
- const viewContainerRef = this.skeletonAnchor.viewContainerRef;
1065
- viewContainerRef.clear();
1066
- if (this.map === undefined || this.map === null)
1067
- throw new Error('add type map with input: [map]="..."');
1068
- for (const bone of this._bones) {
1069
- let componentType = this.map.get(bone.type);
1070
- if (componentType === undefined || componentType === null) {
1071
- console.warn(`Mapping type for ${bone.type} not found`);
1072
- componentType = UnknownBoneComponent;
888
+ skeletonAnchor = viewChild.required(SkeletonAnchorDirective);
889
+ map = input.required(...(ngDevMode ? [{ debugName: "map" }] : []));
890
+ bones = input.required(...(ngDevMode ? [{ debugName: "bones" }] : []));
891
+ constructor() {
892
+ effect(() => {
893
+ const anchor = this.skeletonAnchor();
894
+ const bones = this.bones();
895
+ const mapVal = this.map();
896
+ const viewContainerRef = anchor.viewContainerRef;
897
+ viewContainerRef.clear();
898
+ if (mapVal === undefined || mapVal === null) {
899
+ throw new Error('add type map with input: [map]="..."');
1073
900
  }
1074
- const boneComponentRef = viewContainerRef.createComponent(componentType);
1075
- boneComponentRef.instance.bd.bone = bone;
1076
- }
901
+ for (const bone of bones) {
902
+ let componentType = mapVal.get(bone.type);
903
+ if (componentType === undefined || componentType === null) {
904
+ console.warn(`Mapping type for ${bone.type} not found`);
905
+ componentType = UnknownBoneComponent;
906
+ }
907
+ viewContainerRef.createComponent(componentType).setInput("bone", bone);
908
+ }
909
+ });
1077
910
  }
1078
911
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SkeletonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1079
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: SkeletonComponent, isStandalone: true, selector: "bon-skeleton", inputs: { map: "map", bones: "bones" }, viewQueries: [{ propertyName: "skeletonAnchor", first: true, predicate: SkeletonAnchorDirective, descendants: true, static: true }], ngImport: i0, template: "<ng-template bonSkeletonAnchor></ng-template>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: SkeletonAnchorDirective, selector: "[bonSkeletonAnchor]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
912
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.6", type: SkeletonComponent, isStandalone: true, selector: "bon-skeleton", inputs: { map: { classPropertyName: "map", publicName: "map", isSignal: true, isRequired: true, transformFunction: null }, bones: { classPropertyName: "bones", publicName: "bones", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "skeletonAnchor", first: true, predicate: SkeletonAnchorDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template bonSkeletonAnchor></ng-template>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: SkeletonAnchorDirective, selector: "[bonSkeletonAnchor]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1080
913
  }
1081
914
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SkeletonComponent, decorators: [{
1082
915
  type: Component,
1083
- args: [{ selector: 'bon-skeleton', standalone: true, imports: [SkeletonAnchorDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template bonSkeletonAnchor></ng-template>\n", styles: [":host{display:block}\n"] }]
1084
- }], propDecorators: { skeletonAnchor: [{
1085
- type: ViewChild,
1086
- args: [SkeletonAnchorDirective, { static: true }]
1087
- }], map: [{
1088
- type: Input,
1089
- args: [{ required: true }]
1090
- }], bones: [{
1091
- type: Input
1092
- }] } });
1093
-
1094
- class BoneMap extends Map {
1095
- getRequired(key) {
1096
- const value = this.get(key);
1097
- if (value === undefined || value === null) {
1098
- throw Error(`BoneMap doesn't contain type for key = ${key}`);
1099
- }
1100
- return value;
1101
- }
1102
- }
916
+ args: [{ selector: "bon-skeleton", imports: [SkeletonAnchorDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template bonSkeletonAnchor></ng-template>\n", styles: [":host{display:block}\n"] }]
917
+ }], ctorParameters: () => [], propDecorators: { skeletonAnchor: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SkeletonAnchorDirective), { isSignal: true }] }], map: [{ type: i0.Input, args: [{ isSignal: true, alias: "map", required: true }] }], bones: [{ type: i0.Input, args: [{ isSignal: true, alias: "bones", required: true }] }] } });
1103
918
 
1104
919
  /**
1105
920
  * Generated bundle index. Do not edit.
1106
921
  */
1107
922
 
1108
- export { BoneDirective, BoneMap, DeviceService, DeviceServiceBase, EncodeURIComponentPipe, ImageSrcDirective, IntersectionComponent, IsLocalUrlPipe, IsNotLocalUrlPipe, LocalizationIsEmptyPipe, LocalizationIsNotEmptyPipe, LocalizeObjectPipe, LocalizePipe, LocalizeServiceBase, LocalizeUrlPipe, MarcyImageComponent, MarcyMediaComponent, MarcyVideoComponent, MediaObjectFit, MediaStatus, PublishStatus, SizesWidthUnit, SkeletonAnchorDirective, SkeletonComponent, SrcBaseDirective, UnknownBoneComponent, UnsubscriberService, VideoSrcDirective, emptyBone, emptyImage, emptyLocalizedString, emptyVideo, getDefaultSrc, toHtmlPictureSources };
923
+ export { BONE_DIRECTIVE_WITH_INPUTS_AND_OUTPUTS, BoneDirective, BoneMap, DeviceService, DeviceServiceBase, EncodeURIComponentPipe, ImageSrcDirective, IntersectionComponent, IsLocalUrlPipe, IsNotLocalUrlPipe, LocalizationIsEmptyPipe, LocalizationIsNotEmptyPipe, LocalizeObjectPipe, LocalizePipe, LocalizeServiceBase, LocalizeUrlPipe, MarcyImageComponent, MarcyMediaComponent, MarcyVideoComponent, MediaObjectFit, MediaStatus, PublishStatus, SizesWidthUnit, SkeletonAnchorDirective, SkeletonComponent, SrcBaseDirective, UnknownBoneComponent, VideoSrcDirective, emptyBone, emptyImage, emptyLocalizedString, emptyVideo, getDefaultSrc, toHtmlPictureSources };
1109
924
  //# sourceMappingURL=candy-kingdom-bonnie.mjs.map