@acorex/cdk 22.1.0-next.0 → 22.1.0-next.10

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, EventEmitter, DOCUMENT, PLATFORM_ID, Renderer2, Input, Directive, NgModule, InjectionToken, Output, input, effect } from '@angular/core';
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
- class NXValueComponent {
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
- this.readonly = model(/* @ts-ignore */
142
- ...(ngDevMode ? [undefined, { debugName: "readonly" }] : /* istanbul ignore next */ []));
143
- this.name = model(/* @ts-ignore */
144
- ...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
145
- this.value = model(/* @ts-ignore */
146
- ...(ngDevMode ? [undefined, { debugName: "value" }] : /* istanbul ignore next */ []));
147
- this.onValueChanged = output();
148
- }
149
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: NXValueComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
150
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.8", type: NXValueComponent, isStandalone: true, selector: "ng-component", inputs: { readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { readonly: "readonlyChange", name: "nameChange", value: "valueChange", onValueChanged: "onValueChanged" }, ngImport: i0, template: '', isInline: true }); }
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: Component,
154
- args: [{
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();
@@ -1263,7 +1400,7 @@ class AXAutoFocusDirective {
1263
1400
  this._host = inject(AXFocusableComponent, { host: true, self: true, optional: true });
1264
1401
  this.autoFocus = true;
1265
1402
  this.time = 50;
1266
- this.document = inject(DOCUMENT);
1403
+ this.document = inject(DOCUMENT$1);
1267
1404
  this.platformID = inject(PLATFORM_ID);
1268
1405
  }
1269
1406
  ngAfterViewInit() {
@@ -1309,7 +1446,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
1309
1446
  class AXHotkeysService {
1310
1447
  constructor() {
1311
1448
  this.eventManager = inject(EventManager);
1312
- this.document = inject(DOCUMENT);
1449
+ this.document = inject(DOCUMENT$1);
1313
1450
  this.defaults = {
1314
1451
  element: this.document,
1315
1452
  };
@@ -2491,7 +2628,7 @@ class AXRippleDirective {
2491
2628
  this.cdr = inject(ChangeDetectorRef);
2492
2629
  this.enabled = true;
2493
2630
  this.axRippleColor = 'var(--ax-comp-ripple-color, rgba(255, 255, 255, 0.3))';
2494
- this.document = inject(DOCUMENT);
2631
+ this.document = inject(DOCUMENT$1);
2495
2632
  this.platformID = inject(PLATFORM_ID);
2496
2633
  }
2497
2634
  ngOnInit() {