@acorex/cdk 22.1.0-next.2 → 22.1.0-next.20
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,11 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { model, output, Component, inject, ElementRef, signal, afterNextRender, Injectable, ChangeDetectorRef, ViewContainerRef,
|
|
2
|
+
import { model, output, Component, inject, ElementRef, signal, afterNextRender, Injectable, EventEmitter, PLATFORM_ID, ChangeDetectorRef, ViewContainerRef, DOCUMENT as DOCUMENT$1, Renderer2, Input, Directive, NgModule, InjectionToken, Output, input, effect } from '@angular/core';
|
|
3
3
|
import { AXHtmlUtil } from '@acorex/core/utils';
|
|
4
|
-
import { flatten, cloneDeep, isEqual, omit, get } from 'lodash-es';
|
|
5
4
|
import { isBrowser } from '@acorex/core/platform';
|
|
6
5
|
import { AXValidationService } from '@acorex/core/validation';
|
|
6
|
+
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
7
|
+
import { omit, isEqual, flatten, cloneDeep, get } from 'lodash-es';
|
|
7
8
|
import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
|
|
8
|
-
import { isPlatformBrowser } from '@angular/common';
|
|
9
9
|
import { noop, Subscription, BehaviorSubject, debounceTime, distinctUntilChanged, Subject, fromEvent, skip } from 'rxjs';
|
|
10
10
|
import { DataSource } from '@angular/cdk/collections';
|
|
11
11
|
import { EventManager } from '@angular/platform-browser';
|
|
@@ -66,6 +66,13 @@ class NXComponent {
|
|
|
66
66
|
get nativeElement() {
|
|
67
67
|
return this.#elementRef.nativeElement;
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Gets the host HTML element of the component.
|
|
71
|
+
* Same contract as classic editors so `ax-label` / `ax-form-field` can associate the field.
|
|
72
|
+
*/
|
|
73
|
+
getHostElement() {
|
|
74
|
+
return this.nativeElement;
|
|
75
|
+
}
|
|
69
76
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: NXComponent, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
70
77
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: NXComponent }); }
|
|
71
78
|
}
|
|
@@ -136,25 +143,155 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
136
143
|
}]
|
|
137
144
|
}], propDecorators: { look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }, { type: i0.Output, args: ["lookChange"] }] } });
|
|
138
145
|
|
|
139
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Signal-based value editor with the same `ax-validation-rule` / `ax-form` contract as the classic value mixins.
|
|
148
|
+
*/
|
|
149
|
+
class NXValueComponent extends NXComponent {
|
|
140
150
|
constructor() {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this
|
|
144
|
-
|
|
145
|
-
this
|
|
146
|
-
|
|
147
|
-
this
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
super(...arguments);
|
|
152
|
+
this.validationRulesChange = new EventEmitter();
|
|
153
|
+
this.#validationRules = [];
|
|
154
|
+
this.#state = 'clear';
|
|
155
|
+
this.#validationService = inject(AXValidationService);
|
|
156
|
+
this.#document = inject(DOCUMENT);
|
|
157
|
+
this.#platformId = inject(PLATFORM_ID);
|
|
158
|
+
this.#registerValidation = afterNextRender(() => {
|
|
159
|
+
this.registerValidation();
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
#validationRules;
|
|
163
|
+
#state;
|
|
164
|
+
#validationService;
|
|
165
|
+
#document;
|
|
166
|
+
#platformId;
|
|
167
|
+
#registerValidation;
|
|
168
|
+
get isRequired() {
|
|
169
|
+
return this.#validationRules.some((rule) => rule.rule == 'required');
|
|
170
|
+
}
|
|
171
|
+
get state() {
|
|
172
|
+
return this.#state;
|
|
173
|
+
}
|
|
174
|
+
registerValidation() {
|
|
175
|
+
this.nativeElement.querySelectorAll('[ax-form-item="true"]').forEach((node) => {
|
|
176
|
+
node.removeAttribute('ax-form-item');
|
|
177
|
+
});
|
|
178
|
+
this.nativeElement.setAttribute('ax-form-item', 'true');
|
|
179
|
+
}
|
|
180
|
+
addValidationRule(rule) {
|
|
181
|
+
this.#validationRules.push(rule);
|
|
182
|
+
this.validationRulesChange.emit(this.#validationRules);
|
|
183
|
+
}
|
|
184
|
+
removeValidationRule(ruleToRemove) {
|
|
185
|
+
this.#validationRules = this.#validationRules.filter((rule) => {
|
|
186
|
+
if (rule.rule !== ruleToRemove.rule) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
const ruleOptions = omit(rule.options, ['title']);
|
|
190
|
+
const removeOptions = omit(ruleToRemove.options, ['title']);
|
|
191
|
+
return !isEqual(ruleOptions['pattern'], removeOptions['pattern']);
|
|
192
|
+
});
|
|
193
|
+
this.validationRulesChange.emit(this.#validationRules);
|
|
194
|
+
this.setState('clear');
|
|
195
|
+
}
|
|
196
|
+
removeValidationRuleByType(type) {
|
|
197
|
+
this.#validationRules = this.#validationRules.filter((rule) => rule.rule !== type);
|
|
198
|
+
this.validationRulesChange.emit(this.#validationRules);
|
|
199
|
+
this.setState('clear');
|
|
200
|
+
}
|
|
201
|
+
async validate() {
|
|
202
|
+
const containerClasses = ['ax-editor-container', 'ax-checkbox', 'ax-radio'];
|
|
203
|
+
const container = containerClasses.some((className) => this.nativeElement.classList.contains(className))
|
|
204
|
+
? this.nativeElement
|
|
205
|
+
: this.nativeElement.querySelector('.ax-editor-container');
|
|
206
|
+
const formField = (container || this.nativeElement).closest('ax-form-field') || container?.closest('ax-checkbox');
|
|
207
|
+
const label = formField?.querySelector('ax-label') || formField?.querySelector('label');
|
|
208
|
+
const rules = this.#validationService.ruleFor(this.#currentValue());
|
|
209
|
+
this.#validationRules.forEach((rule) => {
|
|
210
|
+
rule.options ??= {};
|
|
211
|
+
rule.options['title'] = (label?.firstChild?.textContent ?? this.#currentName())?.replace('*', '').trim();
|
|
212
|
+
rules.addRule(rule.rule, rule.options);
|
|
213
|
+
});
|
|
214
|
+
const result = await rules.validate();
|
|
215
|
+
if (result.result) {
|
|
216
|
+
this.setState('clear');
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
const message = result.rules.find((rule) => !rule.result)?.message;
|
|
220
|
+
this.setState('error', message);
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
setState(state, ...args) {
|
|
225
|
+
if (!isBrowser()) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const container = this.nativeElement.classList.contains('ax-editor-container')
|
|
229
|
+
? this.nativeElement
|
|
230
|
+
: this.nativeElement.querySelector('.ax-editor-container');
|
|
231
|
+
const formField = (container || this.nativeElement).closest('ax-form-field');
|
|
232
|
+
const label = formField?.querySelector('ax-label') || formField?.querySelector('label');
|
|
233
|
+
let target = container || this.nativeElement.firstElementChild;
|
|
234
|
+
if (target?.querySelector('.ax-error-container')) {
|
|
235
|
+
target = target.querySelector('.ax-error-container');
|
|
236
|
+
}
|
|
237
|
+
const parent = target?.parentElement;
|
|
238
|
+
if (!target || !parent) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
switch (state) {
|
|
242
|
+
case 'clear':
|
|
243
|
+
this.#state = 'clear';
|
|
244
|
+
parent.querySelector('span.ax-error-message')?.remove();
|
|
245
|
+
label?.classList.remove('ax-state-error');
|
|
246
|
+
target.classList.remove('ax-state-error', 'ax-state-success');
|
|
247
|
+
break;
|
|
248
|
+
case 'success':
|
|
249
|
+
this.setState('clear');
|
|
250
|
+
target.classList.add('ax-state-success');
|
|
251
|
+
this.#state = 'success';
|
|
252
|
+
break;
|
|
253
|
+
case 'error':
|
|
254
|
+
this.setState('clear');
|
|
255
|
+
if (isPlatformBrowser(this.#platformId)) {
|
|
256
|
+
const message = args[0] ?? '';
|
|
257
|
+
if (message) {
|
|
258
|
+
const span = this.#document.createElement('span');
|
|
259
|
+
span.innerHTML = message;
|
|
260
|
+
span.classList.add('ax-error-message');
|
|
261
|
+
parent.appendChild(span);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
label?.classList.add('ax-state-error');
|
|
265
|
+
target.classList.add('ax-state-error');
|
|
266
|
+
this.#state = 'error';
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
resetErrors() {
|
|
271
|
+
this.setState('clear');
|
|
272
|
+
}
|
|
273
|
+
commitValue(value, _isUserInteraction = false) {
|
|
274
|
+
const model = this.#valueModel();
|
|
275
|
+
model?.set?.(value);
|
|
276
|
+
}
|
|
277
|
+
#currentValue() {
|
|
278
|
+
return this.#resolve(this.value);
|
|
279
|
+
}
|
|
280
|
+
#currentName() {
|
|
281
|
+
return String(this.#resolve(this.name) ?? '');
|
|
282
|
+
}
|
|
283
|
+
#valueModel() {
|
|
284
|
+
return this.value;
|
|
285
|
+
}
|
|
286
|
+
#resolve(prop) {
|
|
287
|
+
return typeof prop === 'function' ? prop() : prop;
|
|
288
|
+
}
|
|
289
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: NXValueComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
290
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: NXValueComponent }); }
|
|
151
291
|
}
|
|
152
292
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: NXValueComponent, decorators: [{
|
|
153
|
-
type:
|
|
154
|
-
|
|
155
|
-
template: '',
|
|
156
|
-
}]
|
|
157
|
-
}], propDecorators: { readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }, { type: i0.Output, args: ["readonlyChange"] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }, { type: i0.Output, args: ["nameChange"] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onValueChanged: [{ type: i0.Output, args: ["onValueChanged"] }] } });
|
|
293
|
+
type: Injectable
|
|
294
|
+
}] });
|
|
158
295
|
|
|
159
296
|
const defaultOffset = 3;
|
|
160
297
|
function convertToPlacement(value) {
|
|
@@ -575,7 +712,7 @@ class MXValueComponent extends MXInteractiveComponent {
|
|
|
575
712
|
this._isUserInteraction = false;
|
|
576
713
|
this.stateChange = new EventEmitter();
|
|
577
714
|
this._state = 'clear';
|
|
578
|
-
this.document = inject(DOCUMENT);
|
|
715
|
+
this.document = inject(DOCUMENT$1);
|
|
579
716
|
this.platformID = inject(PLATFORM_ID);
|
|
580
717
|
this.validationService = inject(AXValidationService);
|
|
581
718
|
this.validationRulesChange = new EventEmitter();
|
|
@@ -1047,6 +1184,10 @@ class AXListDataSource extends DataSource {
|
|
|
1047
1184
|
.pipe(distinctUntilChanged())
|
|
1048
1185
|
.subscribe((range) => {
|
|
1049
1186
|
this._range = range;
|
|
1187
|
+
if (range.end <= range.start) {
|
|
1188
|
+
this.source.setPage(0);
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1050
1191
|
const startPage = this.getPageForIndex(range.start);
|
|
1051
1192
|
const endPage = this.getPageForIndex(range.end - 1);
|
|
1052
1193
|
for (let i = startPage; i <= endPage; i++) {
|
|
@@ -1094,6 +1235,7 @@ class AXDataSource {
|
|
|
1094
1235
|
this._totalCount = 0;
|
|
1095
1236
|
this._items = [];
|
|
1096
1237
|
this.fetchedPages = new Set();
|
|
1238
|
+
this.inflightPages = new Set();
|
|
1097
1239
|
this._page = 0;
|
|
1098
1240
|
this._query = { skip: 0, take: 0, sort: [] };
|
|
1099
1241
|
this.onChanged = new Subject();
|
|
@@ -1106,18 +1248,26 @@ class AXDataSource {
|
|
|
1106
1248
|
this._items = new Array(0);
|
|
1107
1249
|
this._query.take = this.config.pageSize;
|
|
1108
1250
|
}
|
|
1251
|
+
pageHasCachedItems(page) {
|
|
1252
|
+
const start = page * this.config.pageSize;
|
|
1253
|
+
return this._cachedItems.slice(start, start + this.config.pageSize).some((item) => item != null);
|
|
1254
|
+
}
|
|
1109
1255
|
load() {
|
|
1110
1256
|
const page = this._page;
|
|
1111
|
-
if (this.
|
|
1257
|
+
if (this.inflightPages.has(page)) {
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
if (this.fetchedPages.has(page) && this.useCache && this.pageHasCachedItems(page)) {
|
|
1112
1261
|
return;
|
|
1113
1262
|
}
|
|
1114
1263
|
this.setLoadingState(true);
|
|
1115
|
-
this.
|
|
1264
|
+
this.inflightPages.add(page);
|
|
1116
1265
|
this._query.take = this.config.pageSize;
|
|
1117
1266
|
this._query.skip = page * this.config.pageSize;
|
|
1118
1267
|
this.config
|
|
1119
1268
|
.load({ ...this._query })
|
|
1120
1269
|
.then((result) => {
|
|
1270
|
+
this.fetchedPages.add(page);
|
|
1121
1271
|
if (this._totalCount != result.total) {
|
|
1122
1272
|
this._cachedItems = new Array(result.total);
|
|
1123
1273
|
this._totalCount = result.total;
|
|
@@ -1132,8 +1282,12 @@ class AXDataSource {
|
|
|
1132
1282
|
totalPages: this.totalPages,
|
|
1133
1283
|
};
|
|
1134
1284
|
this.onChanged.next(event);
|
|
1285
|
+
})
|
|
1286
|
+
.catch(() => {
|
|
1287
|
+
this.fetchedPages.delete(page);
|
|
1135
1288
|
})
|
|
1136
1289
|
.finally(() => {
|
|
1290
|
+
this.inflightPages.delete(page);
|
|
1137
1291
|
this.setLoadingState(false);
|
|
1138
1292
|
});
|
|
1139
1293
|
}
|
|
@@ -1170,6 +1324,7 @@ class AXDataSource {
|
|
|
1170
1324
|
this._items = new Array(0);
|
|
1171
1325
|
this._cachedItems = new Array(this.config.pageSize);
|
|
1172
1326
|
this.fetchedPages.clear();
|
|
1327
|
+
this.inflightPages.clear();
|
|
1173
1328
|
this._page = 0;
|
|
1174
1329
|
this._totalCount = 0;
|
|
1175
1330
|
}
|
|
@@ -1263,7 +1418,7 @@ class AXAutoFocusDirective {
|
|
|
1263
1418
|
this._host = inject(AXFocusableComponent, { host: true, self: true, optional: true });
|
|
1264
1419
|
this.autoFocus = true;
|
|
1265
1420
|
this.time = 50;
|
|
1266
|
-
this.document = inject(DOCUMENT);
|
|
1421
|
+
this.document = inject(DOCUMENT$1);
|
|
1267
1422
|
this.platformID = inject(PLATFORM_ID);
|
|
1268
1423
|
}
|
|
1269
1424
|
ngAfterViewInit() {
|
|
@@ -1309,7 +1464,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
1309
1464
|
class AXHotkeysService {
|
|
1310
1465
|
constructor() {
|
|
1311
1466
|
this.eventManager = inject(EventManager);
|
|
1312
|
-
this.document = inject(DOCUMENT);
|
|
1467
|
+
this.document = inject(DOCUMENT$1);
|
|
1313
1468
|
this.defaults = {
|
|
1314
1469
|
element: this.document,
|
|
1315
1470
|
};
|
|
@@ -2491,7 +2646,7 @@ class AXRippleDirective {
|
|
|
2491
2646
|
this.cdr = inject(ChangeDetectorRef);
|
|
2492
2647
|
this.enabled = true;
|
|
2493
2648
|
this.axRippleColor = 'var(--ax-comp-ripple-color, rgba(255, 255, 255, 0.3))';
|
|
2494
|
-
this.document = inject(DOCUMENT);
|
|
2649
|
+
this.document = inject(DOCUMENT$1);
|
|
2495
2650
|
this.platformID = inject(PLATFORM_ID);
|
|
2496
2651
|
}
|
|
2497
2652
|
ngOnInit() {
|