@acorex/components 22.0.0 → 22.0.1-next.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.
Files changed (149) hide show
  1. package/emoji/README.md +3 -0
  2. package/emojipicker/README.md +3 -0
  3. package/fesm2022/acorex-components-accordion.mjs +4 -4
  4. package/fesm2022/acorex-components-accordion.mjs.map +1 -1
  5. package/fesm2022/acorex-components-audio-wave.mjs +291 -267
  6. package/fesm2022/acorex-components-audio-wave.mjs.map +1 -1
  7. package/fesm2022/acorex-components-bubble.mjs +71 -0
  8. package/fesm2022/acorex-components-bubble.mjs.map +1 -0
  9. package/fesm2022/acorex-components-button-group.mjs +12 -5
  10. package/fesm2022/acorex-components-button-group.mjs.map +1 -1
  11. package/fesm2022/acorex-components-button.mjs +2 -2
  12. package/fesm2022/acorex-components-button.mjs.map +1 -1
  13. package/fesm2022/acorex-components-calendar.mjs +321 -118
  14. package/fesm2022/acorex-components-calendar.mjs.map +1 -1
  15. package/fesm2022/acorex-components-combo-box.mjs +238 -48
  16. package/fesm2022/acorex-components-combo-box.mjs.map +1 -1
  17. package/fesm2022/acorex-components-conversation-acorex-components-conversation-DDkiZfPb.mjs +19058 -0
  18. package/fesm2022/acorex-components-conversation-acorex-components-conversation-DDkiZfPb.mjs.map +1 -0
  19. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-COUB9zrM.mjs +50 -0
  20. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-COUB9zrM.mjs.map +1 -0
  21. package/fesm2022/acorex-components-conversation-image-picker-editor-dialog.component-COT96F_v.mjs +87 -0
  22. package/fesm2022/acorex-components-conversation-image-picker-editor-dialog.component-COT96F_v.mjs.map +1 -0
  23. package/fesm2022/acorex-components-conversation-picker-rename-file-dialog.component-CH3Q6Hry.mjs +65 -0
  24. package/fesm2022/acorex-components-conversation-picker-rename-file-dialog.component-CH3Q6Hry.mjs.map +1 -0
  25. package/fesm2022/acorex-components-conversation.mjs +1 -15470
  26. package/fesm2022/acorex-components-conversation.mjs.map +1 -1
  27. package/fesm2022/acorex-components-cron-job.mjs +1 -1
  28. package/fesm2022/acorex-components-cron-job.mjs.map +1 -1
  29. package/fesm2022/acorex-components-data-pager.mjs +4 -4
  30. package/fesm2022/acorex-components-data-pager.mjs.map +1 -1
  31. package/fesm2022/acorex-components-data-table.mjs +126 -30
  32. package/fesm2022/acorex-components-data-table.mjs.map +1 -1
  33. package/fesm2022/acorex-components-datetime-picker.mjs +1 -1
  34. package/fesm2022/acorex-components-datetime-picker.mjs.map +1 -1
  35. package/fesm2022/acorex-components-decorators.mjs +36 -6
  36. package/fesm2022/acorex-components-decorators.mjs.map +1 -1
  37. package/fesm2022/acorex-components-dialog.mjs +1 -1
  38. package/fesm2022/acorex-components-dialog.mjs.map +1 -1
  39. package/fesm2022/acorex-components-dropdown-button.mjs +1 -1
  40. package/fesm2022/acorex-components-dropdown-button.mjs.map +1 -1
  41. package/fesm2022/acorex-components-emoji.mjs +74 -0
  42. package/fesm2022/acorex-components-emoji.mjs.map +1 -0
  43. package/fesm2022/acorex-components-emojipicker.mjs +425 -0
  44. package/fesm2022/acorex-components-emojipicker.mjs.map +1 -0
  45. package/fesm2022/acorex-components-fab.mjs +2 -2
  46. package/fesm2022/acorex-components-fab.mjs.map +1 -1
  47. package/fesm2022/acorex-components-file-viewer.mjs +339 -89
  48. package/fesm2022/acorex-components-file-viewer.mjs.map +1 -1
  49. package/fesm2022/acorex-components-form.mjs +1 -1
  50. package/fesm2022/acorex-components-form.mjs.map +1 -1
  51. package/fesm2022/acorex-components-highlight.mjs +80 -0
  52. package/fesm2022/acorex-components-highlight.mjs.map +1 -0
  53. package/fesm2022/acorex-components-image-editor.mjs +686 -416
  54. package/fesm2022/acorex-components-image-editor.mjs.map +1 -1
  55. package/fesm2022/acorex-components-inline-reaction.mjs +111 -0
  56. package/fesm2022/acorex-components-inline-reaction.mjs.map +1 -0
  57. package/fesm2022/acorex-components-kanban.mjs +1 -1
  58. package/fesm2022/acorex-components-kanban.mjs.map +1 -1
  59. package/fesm2022/acorex-components-loading-dialog.mjs +1 -1
  60. package/fesm2022/acorex-components-loading-dialog.mjs.map +1 -1
  61. package/fesm2022/acorex-components-lookup.mjs +742 -134
  62. package/fesm2022/acorex-components-lookup.mjs.map +1 -1
  63. package/fesm2022/acorex-components-map.mjs +7 -0
  64. package/fesm2022/acorex-components-map.mjs.map +1 -1
  65. package/fesm2022/acorex-components-menu.mjs +96 -16
  66. package/fesm2022/acorex-components-menu.mjs.map +1 -1
  67. package/fesm2022/acorex-components-message-status.mjs +71 -0
  68. package/fesm2022/acorex-components-message-status.mjs.map +1 -0
  69. package/fesm2022/acorex-components-message-time.mjs +36 -0
  70. package/fesm2022/acorex-components-message-time.mjs.map +1 -0
  71. package/fesm2022/acorex-components-message.mjs +120 -0
  72. package/fesm2022/acorex-components-message.mjs.map +1 -0
  73. package/fesm2022/acorex-components-notification.mjs +1 -1
  74. package/fesm2022/acorex-components-notification.mjs.map +1 -1
  75. package/fesm2022/acorex-components-paint.mjs +1 -1
  76. package/fesm2022/acorex-components-paint.mjs.map +1 -1
  77. package/fesm2022/acorex-components-popover.mjs +19 -8
  78. package/fesm2022/acorex-components-popover.mjs.map +1 -1
  79. package/fesm2022/acorex-components-popup.mjs +1 -1
  80. package/fesm2022/acorex-components-popup.mjs.map +1 -1
  81. package/fesm2022/acorex-components-rail-navigation.mjs +2 -2
  82. package/fesm2022/acorex-components-rail-navigation.mjs.map +1 -1
  83. package/fesm2022/acorex-components-range-slider.mjs +2 -2
  84. package/fesm2022/acorex-components-range-slider.mjs.map +1 -1
  85. package/fesm2022/acorex-components-reaction.mjs +144 -0
  86. package/fesm2022/acorex-components-reaction.mjs.map +1 -0
  87. package/fesm2022/acorex-components-rest-api-generator.mjs +5 -5
  88. package/fesm2022/acorex-components-rest-api-generator.mjs.map +1 -1
  89. package/fesm2022/acorex-components-rrule.mjs +1 -1
  90. package/fesm2022/acorex-components-rrule.mjs.map +1 -1
  91. package/fesm2022/acorex-components-scheduler-picker.mjs +5 -5
  92. package/fesm2022/acorex-components-scheduler-picker.mjs.map +1 -1
  93. package/fesm2022/acorex-components-scheduler.mjs +1 -1
  94. package/fesm2022/acorex-components-scheduler.mjs.map +1 -1
  95. package/fesm2022/acorex-components-selection-list.mjs +1 -2
  96. package/fesm2022/acorex-components-selection-list.mjs.map +1 -1
  97. package/fesm2022/acorex-components-tabs.mjs +510 -74
  98. package/fesm2022/acorex-components-tabs.mjs.map +1 -1
  99. package/fesm2022/acorex-components-tree-view.mjs +49 -6
  100. package/fesm2022/acorex-components-tree-view.mjs.map +1 -1
  101. package/fesm2022/acorex-components-wysiwyg.mjs +76 -6
  102. package/fesm2022/acorex-components-wysiwyg.mjs.map +1 -1
  103. package/highlight/README.md +13 -0
  104. package/inline-reaction/README.md +3 -0
  105. package/lookup/README.md +1 -1
  106. package/message/README.md +3 -0
  107. package/message-status/README.md +3 -0
  108. package/message-time/README.md +3 -0
  109. package/package.json +42 -12
  110. package/reaction/README.md +3 -0
  111. package/types/acorex-components-audio-wave.d.ts +132 -73
  112. package/types/acorex-components-bubble.d.ts +31 -0
  113. package/types/acorex-components-button-group.d.ts +4 -0
  114. package/types/acorex-components-button.d.ts +1 -1
  115. package/types/acorex-components-calendar.d.ts +41 -9
  116. package/types/acorex-components-combo-box.d.ts +34 -4
  117. package/types/acorex-components-conversation.d.ts +1745 -1322
  118. package/types/acorex-components-data-table.d.ts +27 -7
  119. package/types/acorex-components-decorators.d.ts +13 -1
  120. package/types/acorex-components-emoji.d.ts +42 -0
  121. package/types/acorex-components-emojipicker.d.ts +146 -0
  122. package/types/acorex-components-file-viewer.d.ts +48 -4
  123. package/types/acorex-components-highlight.d.ts +31 -0
  124. package/types/acorex-components-image-editor.d.ts +68 -48
  125. package/types/acorex-components-inline-reaction.d.ts +52 -0
  126. package/types/acorex-components-lookup.d.ts +213 -82
  127. package/types/acorex-components-map.d.ts +5 -0
  128. package/types/acorex-components-menu.d.ts +15 -3
  129. package/types/acorex-components-message-status.d.ts +23 -0
  130. package/types/acorex-components-message-time.d.ts +19 -0
  131. package/types/acorex-components-message.d.ts +59 -0
  132. package/types/acorex-components-popover.d.ts +5 -3
  133. package/types/acorex-components-reaction.d.ts +85 -0
  134. package/types/acorex-components-selection-list.d.ts +1 -1
  135. package/types/acorex-components-tabs.d.ts +148 -19
  136. package/types/acorex-components-tree-view.d.ts +31 -2
  137. package/types/acorex-components-wysiwyg.d.ts +13 -0
  138. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-DCcRJYfF.mjs +0 -50
  139. package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-DCcRJYfF.mjs.map +0 -1
  140. package/fesm2022/acorex-components-conversation-open-composer-picker-for-files-DnSW908R.mjs +0 -210
  141. package/fesm2022/acorex-components-conversation-open-composer-picker-for-files-DnSW908R.mjs.map +0 -1
  142. package/fesm2022/acorex-components-flow-chart.mjs +0 -735
  143. package/fesm2022/acorex-components-flow-chart.mjs.map +0 -1
  144. package/fesm2022/acorex-components-query-builder.mjs +0 -267
  145. package/fesm2022/acorex-components-query-builder.mjs.map +0 -1
  146. package/flow-chart/README.md +0 -3
  147. package/query-builder/README.md +0 -3
  148. package/types/acorex-components-flow-chart.d.ts +0 -187
  149. package/types/acorex-components-query-builder.d.ts +0 -52
@@ -1,13 +1,16 @@
1
1
  import { AXComponent } from '@acorex/cdk/common';
2
- import { AXSkeletonComponent, AXSkeletonModule } from '@acorex/components/skeleton';
3
- import { AXTranslatorPipe, AXTranslationModule } from '@acorex/core/translation';
4
- import { isPlatformBrowser, NgStyle, AsyncPipe, CommonModule } from '@angular/common';
2
+ import { AXSkeletonComponent } from '@acorex/components/skeleton';
3
+ import { AXTranslatorPipe } from '@acorex/core/translation';
4
+ import { isPlatformBrowser, AsyncPipe } from '@angular/common';
5
5
  import * as i0 from '@angular/core';
6
- import { input, output, signal, inject, NgZone, PLATFORM_ID, afterNextRender, ViewChild, ViewEncapsulation, Component, NgModule } from '@angular/core';
6
+ import { viewChild, input, output, signal, computed, inject, NgZone, PLATFORM_ID, DestroyRef, afterRenderEffect, ChangeDetectionStrategy, ViewEncapsulation, Component, NgModule } from '@angular/core';
7
7
  import WaveSurfer from 'wavesurfer.js';
8
- import { AXButtonModule } from '@acorex/components/button';
9
- import { AXDecoratorModule } from '@acorex/components/decorators';
10
8
 
9
+ const DEFAULT_BAR_WIDTH = 2;
10
+ const DEFAULT_BAR_GAP = 2;
11
+ const DEFAULT_BAR_RADIUS = 2;
12
+ const DEFAULT_HEIGHT = 36;
13
+ const FALLBACK_RGB = '128, 128, 128';
11
14
  /**
12
15
  * Displays and interacts with audio waveform visualization.
13
16
  *
@@ -15,9 +18,14 @@ import { AXDecoratorModule } from '@acorex/components/decorators';
15
18
  */
16
19
  class AXAudioWaveComponent {
17
20
  /**
18
- * @ignore
21
+ * @ignore
19
22
  */
20
23
  constructor() {
24
+ /**
25
+ * @ignore
26
+ */
27
+ this.wave = viewChild('wave', /* @ts-ignore */
28
+ ...(ngDevMode ? [{ debugName: "wave" }] : /* istanbul ignore next */ []));
21
29
  /**
22
30
  * Configuration settings for the audio wave.
23
31
  */
@@ -29,58 +37,89 @@ class AXAudioWaveComponent {
29
37
  * @event
30
38
  */
31
39
  this.onStatusChanged = output();
32
- this.audioState = signal('paused', /* @ts-ignore */
40
+ /**
41
+ * @ignore
42
+ */
43
+ this.audioState = signal('loading', /* @ts-ignore */
33
44
  ...(ngDevMode ? [{ debugName: "audioState" }] : /* istanbul ignore next */ []));
45
+ /**
46
+ * @ignore
47
+ */
34
48
  this.errorMessage = signal('', /* @ts-ignore */
35
49
  ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
36
50
  /**
37
- * @ignore
51
+ * @ignore
52
+ */
53
+ this.isWaveVisible = computed(() => {
54
+ const state = this.audioState();
55
+ return state === 'ready' || state === 'playing' || state === 'paused';
56
+ }, /* @ts-ignore */
57
+ ...(ngDevMode ? [{ debugName: "isWaveVisible" }] : /* istanbul ignore next */ []));
58
+ /**
59
+ * @ignore
60
+ */
61
+ this.loadedUrl = '';
62
+ /**
63
+ * @ignore
64
+ */
65
+ this.lastVisualKey = '';
66
+ /**
67
+ * @ignore
68
+ */
69
+ this.isDestroyed = false;
70
+ /**
71
+ * @ignore
38
72
  */
39
73
  this.ngZone = inject(NgZone);
40
- this.platformID = inject(PLATFORM_ID);
41
- afterNextRender(() => {
42
- if (isPlatformBrowser(this.platformID)) {
43
- const primary200 = getComputedStyle(document.body).getPropertyValue('--ax-sys-color-primary-200');
44
- const primary700 = getComputedStyle(document.body).getPropertyValue('--ax-sys-color-primary-700');
45
- this.audio = WaveSurfer.create({
46
- container: this.div.nativeElement,
47
- waveColor: this.config()?.waveColor || `rgba(${primary200})`,
48
- progressColor: this.config()?.progressColor || `rgba(${primary700})`,
49
- url: this.config()?.url || '',
50
- barWidth: this.config()?.barWidth || 2,
51
- barRadius: this.config()?.barRadius || 2,
52
- barGap: this.config()?.barGap || 2,
53
- height: this.config()?.height || 36,
54
- });
74
+ /**
75
+ * @ignore
76
+ */
77
+ this.platformId = inject(PLATFORM_ID);
78
+ /**
79
+ * @ignore
80
+ */
81
+ this.destroyRef = inject(DestroyRef);
82
+ afterRenderEffect(() => {
83
+ const container = this.wave()?.nativeElement;
84
+ const config = this.config();
85
+ if (this.isDestroyed || !isPlatformBrowser(this.platformId) || !container) {
86
+ return;
55
87
  }
56
- this.load();
57
- this.audio?.on('loading', () => {
58
- this.audioState.set('loading');
59
- });
60
- this.audio?.on('ready', () => {
61
- this.audioState.set('ready');
62
- });
63
- this.audio?.on('error', (e) => {
64
- this.errorMessage.set(e?.message);
65
- this.audioState.set('error');
66
- });
67
- this.bindEvents();
88
+ if (!this.audio) {
89
+ this.createWaveSurfer(container, config);
90
+ return;
91
+ }
92
+ this.syncFromConfig(config);
93
+ });
94
+ this.destroyRef.onDestroy(() => {
95
+ this.isDestroyed = true;
96
+ this.audio?.destroy();
97
+ this.audio = undefined;
68
98
  });
69
99
  }
70
100
  /**
71
101
  * Loads the audio from the specified URL.
72
102
  *
73
103
  * @param url - The URL of the audio to load. Defaults to the URL from the config.
104
+ * @returns A promise that resolves when loading starts, or immediately when unavailable.
74
105
  */
75
- load(url = this.config().url) {
76
- this.audio.load(url);
106
+ load(url = this.config()?.url) {
107
+ const nextUrl = url?.trim();
108
+ if (!this.audio || !nextUrl) {
109
+ return Promise.resolve();
110
+ }
111
+ this.loadedUrl = nextUrl;
112
+ this.audioState.set('loading');
113
+ this.errorMessage.set('');
114
+ return this.swallowAbort(this.audio.load(nextUrl));
77
115
  }
78
116
  /**
79
117
  * Plays the audio.
80
118
  *
119
+ * @returns A promise that resolves when playback starts.
81
120
  */
82
121
  play() {
83
- return this.audio?.play();
122
+ return this.swallowAbort(this.audio?.play());
84
123
  }
85
124
  /**
86
125
  * Pauses the audio.
@@ -89,296 +128,281 @@ class AXAudioWaveComponent {
89
128
  this.audio?.pause();
90
129
  }
91
130
  /**
92
- * Retrieves the duration of the audio.
131
+ * Retrieves the duration of the audio in seconds.
93
132
  *
133
+ * @returns The audio duration, or `0` when unavailable.
94
134
  */
95
135
  getDuration() {
96
136
  return this.audio?.getDuration() ?? 0;
97
137
  }
98
138
  /**
99
- * Retrieves the media element of the audio.
139
+ * Retrieves the underlying HTML media element.
100
140
  *
141
+ * @returns The media element used by WaveSurfer, or `undefined` when unavailable.
101
142
  */
102
143
  getMediaElement() {
103
144
  return this.audio?.getMediaElement();
104
145
  }
146
+ /**
147
+ * Retrieves the current playback position in seconds.
148
+ *
149
+ * @returns The current time, or `0` when unavailable.
150
+ */
151
+ getCurrentTime() {
152
+ return this.audio?.getCurrentTime() ?? this.getMediaElement()?.currentTime ?? 0;
153
+ }
105
154
  /**
106
155
  * Sets the playback rate of the audio.
107
156
  *
108
157
  * @param rate - The playback rate to set.
109
158
  */
110
159
  setRate(rate) {
111
- this.audio.setPlaybackRate(rate);
160
+ this.audio?.setPlaybackRate(rate);
112
161
  }
113
162
  /**
114
- * @ignore
163
+ * Mutes or unmutes the audio.
164
+ *
165
+ * @param muted - Whether the audio should be muted.
115
166
  */
116
- bindEvents() {
117
- this.handleLoad();
118
- this.handleLoading();
119
- this.handleDecode();
120
- this.handleReady();
121
- this.handleRedRawComplete();
122
- this.handlePlay();
123
- this.handlePause();
124
- this.handleFinish();
125
- this.handleTimeUpdate();
126
- this.handleSeeking();
127
- this.handleInteraction();
128
- this.handleClick();
129
- this.handleDrag();
130
- this.handleScroll();
131
- this.handleZoom();
132
- this.handleDestroy();
133
- this.handleError();
167
+ setMuted(muted) {
168
+ this.audio?.setMuted(muted);
134
169
  }
135
- /** When audio starts loading */
136
- handleLoad() {
137
- this.audio?.on('load', (url) => {
138
- this.ngZone.run(() => {
139
- this.onStatusChanged.emit({
140
- component: this,
141
- data: { url: url },
142
- status: 'load',
143
- isUserInteraction: false,
144
- });
145
- });
146
- });
170
+ /**
171
+ * Indicates whether the audio is currently muted.
172
+ *
173
+ * @returns True when muted; otherwise false.
174
+ */
175
+ isMuted() {
176
+ return this.audio?.getMuted() ?? false;
147
177
  }
148
- /** During audio loading */
149
- handleLoading() {
150
- this.audio?.on('loading', (percent) => {
151
- this.ngZone.run(() => {
152
- this.onStatusChanged.emit({
153
- component: this,
154
- data: { percent: percent },
155
- status: 'loading',
156
- isUserInteraction: false,
157
- });
158
- });
178
+ /**
179
+ * @ignore
180
+ */
181
+ createWaveSurfer(container, config) {
182
+ const visualOptions = this.resolveVisualOptions(config);
183
+ this.lastVisualKey = JSON.stringify(visualOptions);
184
+ this.audio = WaveSurfer.create({
185
+ container,
186
+ ...visualOptions,
159
187
  });
188
+ this.bindEvents();
189
+ this.applyUrlAndRate(config);
160
190
  }
161
- /** When the audio has been decoded */
162
- handleDecode() {
163
- this.audio?.on('decode', (duration) => {
164
- this.ngZone.run(() => {
165
- this.onStatusChanged.emit({
166
- component: this,
167
- data: { duration: duration },
168
- status: 'decode',
169
- isUserInteraction: false,
170
- });
171
- });
172
- });
191
+ /**
192
+ * @ignore
193
+ */
194
+ syncFromConfig(config) {
195
+ if (!this.audio) {
196
+ return;
197
+ }
198
+ const visualOptions = this.resolveVisualOptions(config);
199
+ const visualKey = JSON.stringify(visualOptions);
200
+ if (visualKey !== this.lastVisualKey) {
201
+ this.lastVisualKey = visualKey;
202
+ this.audio.setOptions(visualOptions);
203
+ }
204
+ this.applyUrlAndRate(config);
173
205
  }
174
- /** When the audio is both decoded and can play */
175
- handleReady() {
176
- this.audio?.on('ready', (duration) => {
177
- this.ngZone.run(() => {
178
- this.onStatusChanged.emit({
179
- component: this,
180
- data: { duration: duration },
181
- status: 'ready',
182
- isUserInteraction: false,
183
- });
206
+ /**
207
+ * @ignore
208
+ */
209
+ applyUrlAndRate(config) {
210
+ const url = config?.url?.trim() ?? '';
211
+ if (url && url !== this.loadedUrl) {
212
+ this.loadedUrl = url;
213
+ void this.swallowAbort(this.audio?.load(url));
214
+ }
215
+ else if (!url) {
216
+ queueMicrotask(() => {
217
+ if (!this.isDestroyed && !this.loadedUrl && this.audioState() === 'loading') {
218
+ this.audioState.set('paused');
219
+ }
184
220
  });
185
- });
221
+ }
222
+ if (config?.audioRate != null) {
223
+ this.audio?.setPlaybackRate(config.audioRate);
224
+ }
186
225
  }
187
- /** When all audio channel chunks of the waveform have drawn */
188
- handleRedRawComplete() {
189
- this.audio?.on('redrawcomplete', () => {
190
- this.ngZone.run(() => {
191
- this.onStatusChanged.emit({
192
- component: this,
193
- data: null,
194
- status: 'redrawcomplete',
195
- isUserInteraction: false,
196
- });
197
- });
198
- });
226
+ /**
227
+ * @ignore
228
+ */
229
+ resolveVisualOptions(config) {
230
+ const primary200 = this.readCssRgbVar('--ax-sys-color-primary-200');
231
+ const primary700 = this.readCssRgbVar('--ax-sys-color-primary-700');
232
+ return {
233
+ waveColor: config?.waveColor ?? `rgba(${primary200})`,
234
+ progressColor: config?.progressColor ?? `rgba(${primary700})`,
235
+ barWidth: config?.barWidth ?? DEFAULT_BAR_WIDTH,
236
+ barGap: config?.barGap ?? DEFAULT_BAR_GAP,
237
+ barRadius: config?.barRadius ?? DEFAULT_BAR_RADIUS,
238
+ height: config?.height ?? DEFAULT_HEIGHT,
239
+ };
199
240
  }
200
- /** When the audio starts playing */
201
- handlePlay() {
202
- this.audio?.on('play', () => {
203
- this.ngZone.run(() => {
204
- this.onStatusChanged.emit({ component: this, data: null, status: 'play', isUserInteraction: false });
205
- });
206
- });
241
+ /**
242
+ * @ignore
243
+ */
244
+ readCssRgbVar(name) {
245
+ if (!isPlatformBrowser(this.platformId)) {
246
+ return FALLBACK_RGB;
247
+ }
248
+ return getComputedStyle(document.documentElement).getPropertyValue(name).trim() || FALLBACK_RGB;
207
249
  }
208
- /** When the audio pauses */
209
- handlePause() {
210
- this.audio?.on('pause', () => {
211
- this.ngZone.run(() => {
212
- this.onStatusChanged.emit({ component: this, data: null, status: 'pause', isUserInteraction: false });
213
- });
250
+ /**
251
+ * @ignore
252
+ */
253
+ bindEvents() {
254
+ if (!this.audio) {
255
+ return;
256
+ }
257
+ this.audio.on('load', (url) => {
258
+ this.emitStatus('load', { url }, false);
214
259
  });
215
- }
216
- /** When the audio finishes playing */
217
- handleFinish() {
218
- this.audio?.on('finish', () => {
219
- this.ngZone.run(() => {
220
- this.onStatusChanged.emit({
221
- component: this,
222
- data: null,
223
- status: 'finish',
224
- isUserInteraction: false,
225
- });
260
+ this.audio.on('loading', (percent) => {
261
+ this.runInZone(() => {
262
+ this.errorMessage.set('');
263
+ this.audioState.set('loading');
264
+ this.emitStatus('loading', { percent }, false, false);
226
265
  });
227
266
  });
228
- }
229
- /** On audio position change, fires continuously during playback */
230
- handleTimeUpdate() {
231
- this.audio?.on('timeupdate', (currentTime) => {
232
- this.ngZone.run(() => {
233
- this.onStatusChanged.emit({
234
- component: this,
235
- data: { currentTime: currentTime },
236
- status: 'timeupdate',
237
- isUserInteraction: false,
238
- });
239
- });
267
+ this.audio.on('decode', (duration) => {
268
+ this.emitStatus('decode', { duration }, false);
240
269
  });
241
- }
242
- /** When the user seeks to a new position */
243
- handleSeeking() {
244
- this.audio?.on('seeking', (currentTime) => {
245
- this.ngZone.run(() => {
246
- this.onStatusChanged.emit({
247
- component: this,
248
- data: { currentTime: currentTime },
249
- status: 'seeking',
250
- isUserInteraction: false,
251
- });
270
+ this.audio.on('ready', (duration) => {
271
+ this.runInZone(() => {
272
+ if (this.audioState() !== 'playing') {
273
+ this.audioState.set('ready');
274
+ }
275
+ this.emitStatus('ready', { duration }, false, false);
252
276
  });
253
277
  });
254
- }
255
- /** When the user interacts with the waveform (i.g. clicks or drags on it) */
256
- handleInteraction() {
257
- this.audio?.on('interaction', (newTime) => {
258
- this.ngZone.run(() => {
259
- this.onStatusChanged.emit({
260
- component: this,
261
- data: { newTime: newTime },
262
- status: 'interaction',
263
- isUserInteraction: false,
264
- });
265
- });
278
+ this.audio.on('redrawcomplete', () => {
279
+ this.emitStatus('redrawcomplete', null, false);
266
280
  });
267
- }
268
- /** When the user clicks on the waveform */
269
- handleClick() {
270
- this.audio?.on('click', (relativeX) => {
271
- this.ngZone.run(() => {
272
- this.onStatusChanged.emit({
273
- component: this,
274
- data: { relativeX: relativeX },
275
- status: 'click',
276
- isUserInteraction: false,
277
- });
281
+ this.audio.on('play', () => {
282
+ this.runInZone(() => {
283
+ this.audioState.set('playing');
284
+ this.emitStatus('play', null, false, false);
278
285
  });
279
286
  });
280
- }
281
- /** When the user drags the cursor */
282
- handleDrag() {
283
- this.audio?.on('drag', (relativeX) => {
284
- this.ngZone.run(() => {
285
- this.onStatusChanged.emit({
286
- component: this,
287
- data: { relativeX: relativeX },
288
- status: 'drag',
289
- isUserInteraction: false,
290
- });
287
+ this.audio.on('pause', () => {
288
+ this.runInZone(() => {
289
+ if (this.audioState() !== 'error') {
290
+ this.audioState.set('paused');
291
+ }
292
+ this.emitStatus('pause', null, false, false);
291
293
  });
292
294
  });
293
- }
294
- /** When the waveform is scrolled (panned) */
295
- handleScroll() {
296
- this.audio?.on('scroll', (visibleStartTime, visibleEndTime) => {
297
- this.ngZone.run(() => {
298
- this.onStatusChanged.emit({
299
- component: this,
300
- data: { visibleStartTime, visibleEndTime },
301
- status: 'scroll',
302
- isUserInteraction: false,
303
- });
295
+ this.audio.on('finish', () => {
296
+ this.runInZone(() => {
297
+ this.audioState.set('paused');
298
+ this.emitStatus('finish', null, false, false);
304
299
  });
305
300
  });
306
- }
307
- /** When the zoom level changes */
308
- handleZoom() {
309
- this.audio?.on('zoom', (minPxPerSec) => {
310
- this.ngZone.run(() => {
311
- this.onStatusChanged.emit({
312
- component: this,
313
- data: { minPxPerSec: minPxPerSec },
314
- status: 'zoom',
315
- isUserInteraction: false,
316
- });
301
+ this.audio.on('timeupdate', (currentTime) => {
302
+ this.emitStatus('timeupdate', { currentTime }, false);
303
+ });
304
+ this.audio.on('seeking', (currentTime) => {
305
+ this.emitStatus('seeking', { currentTime }, true);
306
+ });
307
+ this.audio.on('interaction', (newTime) => {
308
+ this.emitStatus('interaction', { newTime }, true);
309
+ });
310
+ this.audio.on('click', (relativeX, relativeY) => {
311
+ this.emitStatus('click', { relativeX, relativeY }, true);
312
+ });
313
+ this.audio.on('drag', (relativeX) => {
314
+ this.emitStatus('drag', { relativeX }, true);
315
+ });
316
+ this.audio.on('scroll', (visibleStartTime, visibleEndTime) => {
317
+ this.emitStatus('scroll', { visibleStartTime, visibleEndTime }, true);
318
+ });
319
+ this.audio.on('zoom', (minPxPerSec) => {
320
+ this.emitStatus('zoom', { minPxPerSec }, false);
321
+ });
322
+ this.audio.on('destroy', () => {
323
+ this.emitStatus('destroy', null, false);
324
+ });
325
+ this.audio.on('error', (error) => {
326
+ if (this.isAbortError(error)) {
327
+ return;
328
+ }
329
+ this.runInZone(() => {
330
+ const message = error?.message ?? '';
331
+ this.errorMessage.set(message);
332
+ this.audioState.set('error');
333
+ this.emitStatus('error', { message }, false, false);
317
334
  });
318
335
  });
319
336
  }
320
- /** Just before the waveform is destroyed so you can clean up your events */
321
- handleDestroy() {
322
- this.audio?.on('destroy', () => {
323
- this.ngZone.run(() => {
324
- this.onStatusChanged.emit({
325
- component: this,
326
- data: null,
327
- status: 'destroy',
328
- isUserInteraction: false,
329
- });
330
- });
337
+ /**
338
+ * @ignore
339
+ */
340
+ swallowAbort(promise) {
341
+ return Promise.resolve(promise).then(() => undefined, (error) => {
342
+ if (this.isAbortError(error)) {
343
+ return;
344
+ }
345
+ throw error;
331
346
  });
332
347
  }
333
- /** Just before the waveform is destroyed so you can clean up your events */
334
- handleError() {
335
- this.audio?.on('error', (e) => {
336
- this.ngZone.run(() => {
337
- this.onStatusChanged.emit({ component: this, data: e, status: 'error', isUserInteraction: false });
348
+ /**
349
+ * @ignore
350
+ */
351
+ isAbortError(error) {
352
+ return ((typeof DOMException !== 'undefined' && error instanceof DOMException && error.name === 'AbortError') ||
353
+ (error instanceof Error && (error.name === 'AbortError' || /aborted/i.test(error.message))));
354
+ }
355
+ /**
356
+ * @ignore
357
+ */
358
+ emitStatus(status, data, isUserInteraction, wrapInZone = true) {
359
+ if (this.isDestroyed) {
360
+ return;
361
+ }
362
+ const emit = () => {
363
+ this.onStatusChanged.emit({
364
+ component: this,
365
+ data,
366
+ status,
367
+ isUserInteraction,
338
368
  });
339
- });
369
+ };
370
+ if (wrapInZone) {
371
+ this.runInZone(emit);
372
+ return;
373
+ }
374
+ emit();
340
375
  }
341
- ngOnDestroy() {
342
- this.audio.destroy();
376
+ /**
377
+ * @ignore
378
+ */
379
+ runInZone(fn) {
380
+ if (this.isDestroyed) {
381
+ return;
382
+ }
383
+ this.ngZone.run(fn);
343
384
  }
344
385
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXAudioWaveComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
345
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXAudioWaveComponent, isStandalone: true, selector: "ax-audio-wave", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onStatusChanged: "onStatusChanged" }, providers: [{ provide: AXComponent, useExisting: AXAudioWaveComponent }], viewQueries: [{ propertyName: "div", first: true, predicate: ["d"], descendants: true }], ngImport: i0, template: "<div class=\"ax-audio-wave\" #d [ngStyle]=\"{ display: audioState() === 'ready' ? 'block' : 'none' }\"></div>\n\n@switch (audioState()) {\n @case ('loading') {\n <ax-skeleton class=\"h-5 w-full rounded-full\"></ax-skeleton>\n }\n @case ('error') {\n <div class=\"ax-wave-message\">\n {{ '@acorex:error.message' | translate: { params: { message: errorMessage() } } | async }}\n </div>\n }\n}\n", styles: ["@layer components{ax-audio-wave{display:block;width:100%;flex:1}ax-audio-wave .ax-wave-message{padding-inline-start:calc(var(--spacing, .25rem) * 2);padding-inline-start:.5rem}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None }); }
386
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXAudioWaveComponent, isStandalone: true, selector: "ax-audio-wave", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onStatusChanged: "onStatusChanged" }, host: { properties: { "attr.aria-busy": "audioState() === \"loading\" || null", "attr.aria-invalid": "audioState() === \"error\" || null" } }, providers: [{ provide: AXComponent, useExisting: AXAudioWaveComponent }], viewQueries: [{ propertyName: "wave", first: true, predicate: ["wave"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ax-audio-wave-host\" [class.ax-audio-wave-host--loading]=\"audioState() === 'loading'\">\n <div class=\"ax-audio-wave\" #wave [class.ax-audio-wave--hidden]=\"!isWaveVisible()\"></div>\n\n @switch (audioState()) {\n @case ('loading') {\n <ax-skeleton class=\"ax-audio-wave-skeleton\"></ax-skeleton>\n }\n @case ('error') {\n <div class=\"ax-wave-message\">\n {{ '@acorex:error.message' | translate: { params: { message: errorMessage() } } | async }}\n </div>\n }\n }\n</div>\n", styles: ["@layer properties;@layer components{ax-audio-wave{display:block;width:100%;flex:1}ax-audio-wave .ax-audio-wave-host{position:relative;display:block;width:100%}ax-audio-wave .ax-audio-wave-host--loading{min-height:1.25rem}ax-audio-wave .ax-audio-wave{width:100%}ax-audio-wave .ax-audio-wave--hidden{visibility:hidden}ax-audio-wave .ax-audio-wave-skeleton.ax-skeleton{position:absolute;inset-inline:calc(var(--spacing, .25rem) * 0);top:50%;height:calc(var(--spacing, .25rem) * 5);width:100%;--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);border-radius:calc(infinity * 1px)}ax-audio-wave .ax-wave-message{position:absolute;inset-inline:calc(var(--spacing, .25rem) * 0);top:50%;--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);padding-inline-start:calc(var(--spacing, .25rem) * 2)}}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0}}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
346
387
  }
347
388
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXAudioWaveComponent, decorators: [{
348
389
  type: Component,
349
- args: [{ selector: 'ax-audio-wave', encapsulation: ViewEncapsulation.None, imports: [NgStyle, AsyncPipe, AXTranslatorPipe, AXSkeletonComponent], providers: [{ provide: AXComponent, useExisting: AXAudioWaveComponent }], template: "<div class=\"ax-audio-wave\" #d [ngStyle]=\"{ display: audioState() === 'ready' ? 'block' : 'none' }\"></div>\n\n@switch (audioState()) {\n @case ('loading') {\n <ax-skeleton class=\"h-5 w-full rounded-full\"></ax-skeleton>\n }\n @case ('error') {\n <div class=\"ax-wave-message\">\n {{ '@acorex:error.message' | translate: { params: { message: errorMessage() } } | async }}\n </div>\n }\n}\n", styles: ["@layer components{ax-audio-wave{display:block;width:100%;flex:1}ax-audio-wave .ax-wave-message{padding-inline-start:calc(var(--spacing, .25rem) * 2);padding-inline-start:.5rem}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"] }]
350
- }], ctorParameters: () => [], propDecorators: { div: [{
351
- type: ViewChild,
352
- args: ['d', { static: false }]
353
- }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], onStatusChanged: [{ type: i0.Output, args: ["onStatusChanged"] }] } });
390
+ args: [{ selector: 'ax-audio-wave', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [AsyncPipe, AXTranslatorPipe, AXSkeletonComponent], providers: [{ provide: AXComponent, useExisting: AXAudioWaveComponent }], host: {
391
+ '[attr.aria-busy]': 'audioState() === "loading" || null',
392
+ '[attr.aria-invalid]': 'audioState() === "error" || null',
393
+ }, template: "<div class=\"ax-audio-wave-host\" [class.ax-audio-wave-host--loading]=\"audioState() === 'loading'\">\n <div class=\"ax-audio-wave\" #wave [class.ax-audio-wave--hidden]=\"!isWaveVisible()\"></div>\n\n @switch (audioState()) {\n @case ('loading') {\n <ax-skeleton class=\"ax-audio-wave-skeleton\"></ax-skeleton>\n }\n @case ('error') {\n <div class=\"ax-wave-message\">\n {{ '@acorex:error.message' | translate: { params: { message: errorMessage() } } | async }}\n </div>\n }\n }\n</div>\n", styles: ["@layer properties;@layer components{ax-audio-wave{display:block;width:100%;flex:1}ax-audio-wave .ax-audio-wave-host{position:relative;display:block;width:100%}ax-audio-wave .ax-audio-wave-host--loading{min-height:1.25rem}ax-audio-wave .ax-audio-wave{width:100%}ax-audio-wave .ax-audio-wave--hidden{visibility:hidden}ax-audio-wave .ax-audio-wave-skeleton.ax-skeleton{position:absolute;inset-inline:calc(var(--spacing, .25rem) * 0);top:50%;height:calc(var(--spacing, .25rem) * 5);width:100%;--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);border-radius:calc(infinity * 1px)}ax-audio-wave .ax-wave-message{position:absolute;inset-inline:calc(var(--spacing, .25rem) * 0);top:50%;--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y);padding-inline-start:calc(var(--spacing, .25rem) * 2)}}@property --tw-translate-x{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: \"*\"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: \"*\"; inherits: false; initial-value: 0;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0}}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"] }]
394
+ }], ctorParameters: () => [], propDecorators: { wave: [{ type: i0.ViewChild, args: ['wave', { isSignal: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], onStatusChanged: [{ type: i0.Output, args: ["onStatusChanged"] }] } });
354
395
 
355
396
  class AXAudioWaveModule {
356
397
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXAudioWaveModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
357
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXAudioWaveModule, imports: [CommonModule,
358
- AXButtonModule,
359
- AXDecoratorModule,
360
- AXSkeletonModule,
361
- AXTranslationModule,
362
- AXAudioWaveComponent], exports: [AXAudioWaveComponent] }); }
363
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXAudioWaveModule, imports: [CommonModule,
364
- AXButtonModule,
365
- AXDecoratorModule,
366
- AXSkeletonModule,
367
- AXTranslationModule,
368
- AXAudioWaveComponent] }); }
398
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXAudioWaveModule, imports: [AXAudioWaveComponent], exports: [AXAudioWaveComponent] }); }
399
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXAudioWaveModule, imports: [AXAudioWaveComponent] }); }
369
400
  }
370
401
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXAudioWaveModule, decorators: [{
371
402
  type: NgModule,
372
403
  args: [{
373
404
  exports: [AXAudioWaveComponent],
374
- imports: [
375
- CommonModule,
376
- AXButtonModule,
377
- AXDecoratorModule,
378
- AXSkeletonModule,
379
- AXTranslationModule,
380
- AXAudioWaveComponent,
381
- ],
405
+ imports: [AXAudioWaveComponent],
382
406
  }]
383
407
  }] });
384
408