@nexterajs/ui 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/nexterajs-ui-core.mjs +189 -5
- package/fesm2022/nexterajs-ui-core.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-dropdowns.mjs +314 -50
- package/fesm2022/nexterajs-ui-dropdowns.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-file-uploader.mjs +6 -3
- package/fesm2022/nexterajs-ui-file-uploader.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-forms.mjs +729 -370
- package/fesm2022/nexterajs-ui-forms.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-grid.mjs +1188 -208
- package/fesm2022/nexterajs-ui-grid.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-intl.mjs +15 -5
- package/fesm2022/nexterajs-ui-intl.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-notify.mjs +351 -0
- package/fesm2022/nexterajs-ui-notify.mjs.map +1 -0
- package/fesm2022/nexterajs-ui-pivot.mjs +146 -116
- package/fesm2022/nexterajs-ui-pivot.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-styling.mjs +568 -3
- package/fesm2022/nexterajs-ui-styling.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-tree-view.mjs +147 -18
- package/fesm2022/nexterajs-ui-tree-view.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-validation.mjs +247 -92
- package/fesm2022/nexterajs-ui-validation.mjs.map +1 -1
- package/fesm2022/nexterajs-ui.mjs +1 -0
- package/fesm2022/nexterajs-ui.mjs.map +1 -1
- package/package.json +5 -1
- package/styles/_dropdown.scss +149 -0
- package/styles/_editor.scss +23 -4
- package/styles/_icons.scss +92 -0
- package/styles/_mixins.scss +104 -1
- package/styles/_scrollbar.scss +134 -0
- package/styles/_toast.scss +243 -0
- package/styles/_tokens.scss +48 -0
- package/styles/index.scss +4 -0
- package/types/nexterajs-ui-core.d.ts +142 -22
- package/types/nexterajs-ui-dropdowns.d.ts +145 -27
- package/types/nexterajs-ui-file-uploader.d.ts +4 -1
- package/types/nexterajs-ui-forms.d.ts +103 -19
- package/types/nexterajs-ui-grid.d.ts +445 -57
- package/types/nexterajs-ui-notify.d.ts +147 -0
- package/types/nexterajs-ui-pivot.d.ts +35 -22
- package/types/nexterajs-ui-styling.d.ts +163 -3
- package/types/nexterajs-ui-tree-view.d.ts +50 -1
- package/types/nexterajs-ui-validation.d.ts +94 -15
- package/types/nexterajs-ui.d.ts +1 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, inject, contentChildren, signal, Injector, DestroyRef } from '@angular/core';
|
|
2
|
+
import { input, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, inject, contentChildren, output, signal, Injector, DestroyRef } from '@angular/core';
|
|
3
3
|
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
-
import { distinctUntilChanged, startWith, pairwise } from 'rxjs';
|
|
5
|
-
import { NXE_VALIDATION_TARGET, NxeValidationGroupRegistry } from '@nexterajs/ui/core';
|
|
4
|
+
import { distinctUntilChanged, startWith, pairwise, skip } from 'rxjs';
|
|
5
|
+
import { NXE_VALIDATION_TARGET, NxeValidationGroupRegistry, NXE_VALIDATION_GROUP } from '@nexterajs/ui/core';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* The message shown when a rule fails and the caller gave none.
|
|
@@ -19,6 +19,73 @@ const NXE_DEFAULT_VALIDATION_MESSAGES = {
|
|
|
19
19
|
compare: 'Values do not match',
|
|
20
20
|
custom: 'Value is invalid',
|
|
21
21
|
};
|
|
22
|
+
/** DevExtreme RequiredRule semantics: null/undefined/''/false are "not specified". */
|
|
23
|
+
function nxeIsEmptyValue(value) {
|
|
24
|
+
return (value === null ||
|
|
25
|
+
value === undefined ||
|
|
26
|
+
value === '' ||
|
|
27
|
+
value === false ||
|
|
28
|
+
(Array.isArray(value) && value.length === 0));
|
|
29
|
+
}
|
|
30
|
+
/** The message for a rule with none of its own. */
|
|
31
|
+
function nxeDefaultMessage(type) {
|
|
32
|
+
return NXE_DEFAULT_VALIDATION_MESSAGES[type] ?? '';
|
|
33
|
+
}
|
|
34
|
+
/** Whether `value` satisfies `spec`. The single evaluator behind both rule forms. */
|
|
35
|
+
function nxeEvaluateRule(spec, value, rule) {
|
|
36
|
+
switch (spec.type) {
|
|
37
|
+
case 'required':
|
|
38
|
+
return !nxeIsEmptyValue(value);
|
|
39
|
+
case 'compare': {
|
|
40
|
+
const target = spec.comparisonTarget?.();
|
|
41
|
+
switch (spec.comparisonType) {
|
|
42
|
+
case '===':
|
|
43
|
+
return value === target;
|
|
44
|
+
case '!=':
|
|
45
|
+
// eslint-disable-next-line eqeqeq
|
|
46
|
+
return value != target;
|
|
47
|
+
case '!==':
|
|
48
|
+
return value !== target;
|
|
49
|
+
case '>':
|
|
50
|
+
return value > target;
|
|
51
|
+
case '<':
|
|
52
|
+
return value < target;
|
|
53
|
+
case '>=':
|
|
54
|
+
return value >= target;
|
|
55
|
+
case '<=':
|
|
56
|
+
return value <= target;
|
|
57
|
+
case '==':
|
|
58
|
+
default:
|
|
59
|
+
// eslint-disable-next-line eqeqeq
|
|
60
|
+
return value == target;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
case 'range': {
|
|
64
|
+
if (nxeIsEmptyValue(value)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
const num = Number(value);
|
|
68
|
+
if (Number.isNaN(num)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return ((spec.min === undefined || num >= spec.min) &&
|
|
72
|
+
(spec.max === undefined || num <= spec.max));
|
|
73
|
+
}
|
|
74
|
+
case 'pattern': {
|
|
75
|
+
if (nxeIsEmptyValue(value) || !spec.pattern) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
const regex = typeof spec.pattern === 'string' ? new RegExp(spec.pattern) : spec.pattern;
|
|
79
|
+
return regex.test(String(value));
|
|
80
|
+
}
|
|
81
|
+
case 'email':
|
|
82
|
+
return nxeIsEmptyValue(value) || /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(String(value));
|
|
83
|
+
case 'custom':
|
|
84
|
+
return spec.validationCallback?.({ value, rule }) ?? true;
|
|
85
|
+
default:
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
22
89
|
/**
|
|
23
90
|
* `nxe-validation-rule` — drop-in for DevExtreme `dxi-validation-rule`.
|
|
24
91
|
*
|
|
@@ -54,73 +121,22 @@ class NxeValidationRuleComponent {
|
|
|
54
121
|
*/
|
|
55
122
|
resolvedMessage = computed(() => this.message().trim() || NXE_DEFAULT_VALIDATION_MESSAGES[this.type()] || '', /* @ts-ignore */
|
|
56
123
|
...(ngDevMode ? [{ debugName: "resolvedMessage" }] : /* istanbul ignore next */ []));
|
|
124
|
+
/** This rule as plain data, so both rule forms evaluate through one function. */
|
|
125
|
+
toSpec() {
|
|
126
|
+
return {
|
|
127
|
+
type: this.type(),
|
|
128
|
+
message: this.message(),
|
|
129
|
+
comparisonTarget: this.comparisonTarget(),
|
|
130
|
+
comparisonType: this.comparisonType(),
|
|
131
|
+
validationCallback: this.validationCallback(),
|
|
132
|
+
pattern: this.pattern(),
|
|
133
|
+
min: this.min(),
|
|
134
|
+
max: this.max(),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
57
137
|
/** Whether `value` satisfies this rule. */
|
|
58
138
|
evaluate(value) {
|
|
59
|
-
|
|
60
|
-
case 'required':
|
|
61
|
-
return !this.isEmpty(value);
|
|
62
|
-
case 'compare':
|
|
63
|
-
return this.compare(value);
|
|
64
|
-
case 'range':
|
|
65
|
-
return this.isEmpty(value) || this.inRange(value);
|
|
66
|
-
case 'pattern':
|
|
67
|
-
return this.isEmpty(value) || this.matchesPattern(value);
|
|
68
|
-
case 'email':
|
|
69
|
-
return this.isEmpty(value) || /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(String(value));
|
|
70
|
-
case 'custom':
|
|
71
|
-
return this.validationCallback()?.({ value, rule: this }) ?? true;
|
|
72
|
-
default:
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/** DevExtreme RequiredRule semantics: null/undefined/''/false are "not specified". */
|
|
77
|
-
isEmpty(value) {
|
|
78
|
-
return (value === null ||
|
|
79
|
-
value === undefined ||
|
|
80
|
-
value === '' ||
|
|
81
|
-
value === false ||
|
|
82
|
-
(Array.isArray(value) && value.length === 0));
|
|
83
|
-
}
|
|
84
|
-
compare(value) {
|
|
85
|
-
const target = this.comparisonTarget()?.();
|
|
86
|
-
switch (this.comparisonType()) {
|
|
87
|
-
case '===':
|
|
88
|
-
return value === target;
|
|
89
|
-
case '!=':
|
|
90
|
-
// eslint-disable-next-line eqeqeq
|
|
91
|
-
return value != target;
|
|
92
|
-
case '!==':
|
|
93
|
-
return value !== target;
|
|
94
|
-
case '>':
|
|
95
|
-
return value > target;
|
|
96
|
-
case '<':
|
|
97
|
-
return value < target;
|
|
98
|
-
case '>=':
|
|
99
|
-
return value >= target;
|
|
100
|
-
case '<=':
|
|
101
|
-
return value <= target;
|
|
102
|
-
case '==':
|
|
103
|
-
default:
|
|
104
|
-
// eslint-disable-next-line eqeqeq
|
|
105
|
-
return value == target;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
inRange(value) {
|
|
109
|
-
const num = Number(value);
|
|
110
|
-
if (Number.isNaN(num)) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
const min = this.min();
|
|
114
|
-
const max = this.max();
|
|
115
|
-
return (min === undefined || num >= min) && (max === undefined || num <= max);
|
|
116
|
-
}
|
|
117
|
-
matchesPattern(value) {
|
|
118
|
-
const pattern = this.pattern();
|
|
119
|
-
if (!pattern) {
|
|
120
|
-
return true;
|
|
121
|
-
}
|
|
122
|
-
const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
|
|
123
|
-
return regex.test(String(value));
|
|
139
|
+
return nxeEvaluateRule(this.toSpec(), value, this);
|
|
124
140
|
}
|
|
125
141
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeValidationRuleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
126
142
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.5", type: NxeValidationRuleComponent, isStandalone: true, selector: "nxe-validation-rule", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, comparisonTarget: { classPropertyName: "comparisonTarget", publicName: "comparisonTarget", isSignal: true, isRequired: false, transformFunction: null }, comparisonType: { classPropertyName: "comparisonType", publicName: "comparisonType", isSignal: true, isRequired: false, transformFunction: null }, validationCallback: { classPropertyName: "validationCallback", publicName: "validationCallback", isSignal: true, isRequired: false, transformFunction: null }, pattern: { classPropertyName: "pattern", publicName: "pattern", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
@@ -140,36 +156,73 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
140
156
|
* `nxe-validator` — drop-in for DevExtreme `dx-validator`.
|
|
141
157
|
*
|
|
142
158
|
* Placed inside an editor (`<nxe-text-box><nxe-validator><nxe-validation-rule .../></nxe-validator></nxe-text-box>`),
|
|
143
|
-
* it adapts the editor via {@link NXE_VALIDATION_TARGET}, collects its
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* `validate()` is invoked by
|
|
159
|
+
* it adapts the editor via {@link NXE_VALIDATION_TARGET}, collects its rules, and registers into
|
|
160
|
+
* the {@link NxeValidationGroupRegistry} under the editor's `validationGroup`.
|
|
161
|
+
*
|
|
162
|
+
* Validation is on demand, as in DevExtreme — `validate()` is invoked by
|
|
163
|
+
* `nxe-button[validationGroup]` or directly. With one exception, which is also dx's: once a
|
|
164
|
+
* validator HAS been validated, it re-validates as the value changes, so a field that has gone
|
|
165
|
+
* red clears itself as the user fixes it rather than staying red until the next submit.
|
|
147
166
|
*/
|
|
148
167
|
class NxeValidatorComponent {
|
|
149
168
|
target = inject(NXE_VALIDATION_TARGET, { optional: true });
|
|
150
169
|
registry = inject(NxeValidationGroupRegistry);
|
|
170
|
+
groupScope = inject(NXE_VALIDATION_GROUP, { optional: true });
|
|
151
171
|
rules = contentChildren(NxeValidationRuleComponent, /* @ts-ignore */
|
|
152
172
|
...(ngDevMode ? [{ debugName: "rules" }] : /* istanbul ignore next */ []));
|
|
173
|
+
/**
|
|
174
|
+
* dx `validationRules` — rules as data instead of projected children. Both forms combine;
|
|
175
|
+
* projected children come first, matching declaration order.
|
|
176
|
+
*/
|
|
177
|
+
validationRules = input(undefined, /* @ts-ignore */
|
|
178
|
+
...(ngDevMode ? [{ debugName: "validationRules" }] : /* istanbul ignore next */ []));
|
|
153
179
|
/** Explicit group; otherwise inherited from the wrapped editor's `validationGroup`. */
|
|
154
180
|
validationGroupInput = input(undefined, { ...(ngDevMode ? { debugName: "validationGroupInput" } : /* istanbul ignore next */ {}), alias: 'validationGroup' });
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
181
|
+
/** dx `onValidated`, fired on every validation, valid or not. */
|
|
182
|
+
onValidated = output();
|
|
183
|
+
// An explicit name wins over a surrounding `nxe-validation-group`, as in dx. Bare validators
|
|
184
|
+
// with neither join the implicit default group `''` — dx's global group — so a groupless
|
|
185
|
+
// `nxe-button` validates them.
|
|
186
|
+
group = computed(() => this.validationGroupInput() ??
|
|
187
|
+
this.target?.validationGroup() ??
|
|
188
|
+
this.groupScope?.groupKey ??
|
|
189
|
+
'', /* @ts-ignore */
|
|
158
190
|
...(ngDevMode ? [{ debugName: "group" }] : /* istanbul ignore next */ []));
|
|
159
191
|
/** Last validation outcome (false once a rule has failed, until re-validated). */
|
|
160
192
|
isValid = signal(true, /* @ts-ignore */
|
|
161
193
|
...(ngDevMode ? [{ debugName: "isValid" }] : /* istanbul ignore next */ []));
|
|
194
|
+
/** Every rule broken by the last validation, in declaration order. */
|
|
195
|
+
brokenRules = signal([], /* @ts-ignore */
|
|
196
|
+
...(ngDevMode ? [{ debugName: "brokenRules" }] : /* istanbul ignore next */ []));
|
|
197
|
+
/** Whether `validate()` has ever run — the gate on live re-validation. */
|
|
198
|
+
validated = signal(false, /* @ts-ignore */
|
|
199
|
+
...(ngDevMode ? [{ debugName: "validated" }] : /* istanbul ignore next */ []));
|
|
162
200
|
/** DevExtreme parity: existing code calls `validator.instance.validate()` via `@ViewChild`. */
|
|
163
201
|
get instance() {
|
|
164
202
|
return this;
|
|
165
203
|
}
|
|
166
|
-
member = { validate: () => this.validate() };
|
|
204
|
+
member = { validate: () => this.validate(), reset: () => this.reset() };
|
|
205
|
+
/** Projected children plus `[validationRules]`, as one evaluable list. */
|
|
206
|
+
allRules = computed(() => [
|
|
207
|
+
...this.rules().map((rule) => ({
|
|
208
|
+
type: rule.type(),
|
|
209
|
+
evaluate: (value) => rule.evaluate(value),
|
|
210
|
+
message: () => rule.resolvedMessage(),
|
|
211
|
+
})),
|
|
212
|
+
...(this.validationRules() ?? []).map((spec) => ({
|
|
213
|
+
type: spec.type,
|
|
214
|
+
evaluate: (value) => nxeEvaluateRule(spec, value),
|
|
215
|
+
message: () => spec.message?.trim() || nxeDefaultMessage(spec.type),
|
|
216
|
+
})),
|
|
217
|
+
], /* @ts-ignore */
|
|
218
|
+
...(ngDevMode ? [{ debugName: "allRules" }] : /* istanbul ignore next */ []));
|
|
167
219
|
constructor() {
|
|
220
|
+
const injector = inject(Injector);
|
|
168
221
|
// Register/unregister into the named group reactively (handles dynamic group changes).
|
|
169
222
|
/* ⚠ NOT an effect - UI-48. The registration follows ONE signal, and the unregister that
|
|
170
223
|
`onCleanup` used to run is the pairwise step below: a group change unregisters the old
|
|
171
224
|
one before registering the new, and destruction unregisters the last. */
|
|
172
|
-
toObservable(this.group, { injector
|
|
225
|
+
toObservable(this.group, { injector })
|
|
173
226
|
.pipe(distinctUntilChanged(), startWith(undefined), pairwise(), takeUntilDestroyed())
|
|
174
227
|
.subscribe(([previous, group]) => {
|
|
175
228
|
if (previous !== undefined) {
|
|
@@ -177,32 +230,76 @@ class NxeValidatorComponent {
|
|
|
177
230
|
}
|
|
178
231
|
this.registry.register(group, this.member);
|
|
179
232
|
});
|
|
180
|
-
|
|
233
|
+
// dx re-validates a field that has already been validated as its value changes, so an
|
|
234
|
+
// error clears while the user types rather than surviving until the next submit.
|
|
235
|
+
/* ⚠ NOT an effect - UI-48. This takes exactly one dependency, the target's value, named
|
|
236
|
+
here rather than inferred from whatever `validate()` happens to read. */
|
|
237
|
+
toObservable(computed(() => this.target?.getValue()), { injector })
|
|
238
|
+
.pipe(skip(1), takeUntilDestroyed())
|
|
239
|
+
.subscribe(() => {
|
|
240
|
+
if (this.validated()) {
|
|
241
|
+
this.validate();
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
// Tell the editor whether it is required, so it can render aria-required. The rule is
|
|
245
|
+
// where the requirement is stated; the editor should not have to be told twice.
|
|
246
|
+
/* ⚠ NOT an effect - UI-48: one named dependency, the resolved rule list. */
|
|
247
|
+
toObservable(computed(() => this.allRules().some((rule) => rule.type === 'required')), { injector })
|
|
248
|
+
.pipe(takeUntilDestroyed())
|
|
249
|
+
.subscribe((required) => this.target?.setRequired?.(required));
|
|
250
|
+
inject(DestroyRef).onDestroy(() => {
|
|
251
|
+
this.registry.unregister(this.group(), this.member);
|
|
252
|
+
// The editor outlives its validator when the validator sits inside an @if, and a
|
|
253
|
+
// field left advertising aria-required by a rule that no longer exists is worse than
|
|
254
|
+
// one that never advertised it.
|
|
255
|
+
this.target?.setRequired?.(false);
|
|
256
|
+
this.target?.setValidationError(null);
|
|
257
|
+
});
|
|
181
258
|
}
|
|
182
|
-
/**
|
|
259
|
+
/**
|
|
260
|
+
* Run every rule against the editor's current value.
|
|
261
|
+
*
|
|
262
|
+
* dx reports ALL broken rules, not just the first — a `brokenRules` array with at most one
|
|
263
|
+
* entry cannot tell a caller whether a field failed once or three times. The editor's bubble
|
|
264
|
+
* still shows the first message, which is what dx renders.
|
|
265
|
+
*/
|
|
183
266
|
validate() {
|
|
184
267
|
const value = this.target?.getValue();
|
|
185
|
-
|
|
268
|
+
const broken = [];
|
|
269
|
+
for (const rule of this.allRules()) {
|
|
186
270
|
if (!rule.evaluate(value)) {
|
|
187
271
|
// resolvedMessage(), not message(): a rule declared without one would otherwise
|
|
188
272
|
// push the empty string, and every editor guards its bubble with
|
|
189
273
|
// `@if (validationError())` — so the field would block the group in silence.
|
|
190
|
-
|
|
191
|
-
this.isValid.set(false);
|
|
192
|
-
this.target?.setValidationError(message);
|
|
193
|
-
return {
|
|
194
|
-
isValid: false,
|
|
195
|
-
brokenRules: [{ type: rule.type(), message }],
|
|
196
|
-
status: 'invalid',
|
|
197
|
-
};
|
|
274
|
+
broken.push({ type: rule.type, message: rule.message() });
|
|
198
275
|
}
|
|
199
276
|
}
|
|
277
|
+
this.validated.set(true);
|
|
278
|
+
this.brokenRules.set(broken);
|
|
279
|
+
this.isValid.set(broken.length === 0);
|
|
280
|
+
this.target?.setValidationError(broken.length ? broken[0].message : null);
|
|
281
|
+
const result = {
|
|
282
|
+
isValid: broken.length === 0,
|
|
283
|
+
brokenRules: broken,
|
|
284
|
+
status: broken.length === 0 ? 'valid' : 'invalid',
|
|
285
|
+
};
|
|
286
|
+
this.onValidated.emit({ ...result, value, validationGroup: this.group() });
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Clear the error state without validating (dx `reset()`).
|
|
291
|
+
*
|
|
292
|
+
* Also clears `validated`, so the field goes back to staying quiet until it is validated
|
|
293
|
+
* again — otherwise a reset field would light up on the next keystroke.
|
|
294
|
+
*/
|
|
295
|
+
reset() {
|
|
296
|
+
this.validated.set(false);
|
|
297
|
+
this.brokenRules.set([]);
|
|
200
298
|
this.isValid.set(true);
|
|
201
299
|
this.target?.setValidationError(null);
|
|
202
|
-
return { isValid: true, brokenRules: [], status: 'valid' };
|
|
203
300
|
}
|
|
204
301
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeValidatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
205
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.5", type: NxeValidatorComponent, isStandalone: true, selector: "nxe-validator", inputs: { validationGroupInput: { classPropertyName: "validationGroupInput", publicName: "validationGroup", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "rules", predicate: NxeValidationRuleComponent, isSignal: true }], ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
302
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.5", type: NxeValidatorComponent, isStandalone: true, selector: "nxe-validator", inputs: { validationRules: { classPropertyName: "validationRules", publicName: "validationRules", isSignal: true, isRequired: false, transformFunction: null }, validationGroupInput: { classPropertyName: "validationGroupInput", publicName: "validationGroup", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onValidated: "onValidated" }, queries: [{ propertyName: "rules", predicate: NxeValidationRuleComponent, isSignal: true }], ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
206
303
|
}
|
|
207
304
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeValidatorComponent, decorators: [{
|
|
208
305
|
type: Component,
|
|
@@ -213,7 +310,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
213
310
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
214
311
|
encapsulation: ViewEncapsulation.None,
|
|
215
312
|
}]
|
|
216
|
-
}], ctorParameters: () => [], propDecorators: { rules: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NxeValidationRuleComponent), { isSignal: true }] }], validationGroupInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationGroup", required: false }] }] } });
|
|
313
|
+
}], ctorParameters: () => [], propDecorators: { rules: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NxeValidationRuleComponent), { isSignal: true }] }], validationRules: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationRules", required: false }] }], validationGroupInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationGroup", required: false }] }], onValidated: [{ type: i0.Output, args: ["onValidated"] }] } });
|
|
217
314
|
|
|
218
315
|
class NxeValidators {
|
|
219
316
|
/**
|
|
@@ -259,11 +356,69 @@ class NxeValidators {
|
|
|
259
356
|
}
|
|
260
357
|
}
|
|
261
358
|
|
|
359
|
+
let nextGroupId = 0;
|
|
360
|
+
/**
|
|
361
|
+
* `nxe-validation-group` — drop-in for DevExtreme `dx-validation-group`.
|
|
362
|
+
*
|
|
363
|
+
* DevExtreme lets a group be addressed two ways. Either a string name is repeated on the
|
|
364
|
+
* validator and on the button, or both are wrapped in a group element and the relationship is
|
|
365
|
+
* structural. Only the string form existed here, which meant a form could not be validated as a
|
|
366
|
+
* unit without inventing a name for it and keeping that name in two places.
|
|
367
|
+
*
|
|
368
|
+
* The key is generated, not derived from anything the application controls, so two groups on one
|
|
369
|
+
* page cannot collide and a group can never accidentally share a name with a string group. An
|
|
370
|
+
* explicit `validationGroup` on a descendant still wins, as in dx — the structural form is a
|
|
371
|
+
* default, not an override.
|
|
372
|
+
*/
|
|
373
|
+
class NxeValidationGroupComponent {
|
|
374
|
+
registry = inject(NxeValidationGroupRegistry);
|
|
375
|
+
scope = inject(NXE_VALIDATION_GROUP);
|
|
376
|
+
/** The generated key descendants register under. Exposed for a caller that needs to name it. */
|
|
377
|
+
get groupKey() {
|
|
378
|
+
return this.scope.groupKey;
|
|
379
|
+
}
|
|
380
|
+
/** DevExtreme parity: `group.instance.validate()` / `.reset()`. */
|
|
381
|
+
get instance() {
|
|
382
|
+
return this;
|
|
383
|
+
}
|
|
384
|
+
/** Validate every validator inside this group. */
|
|
385
|
+
validate() {
|
|
386
|
+
return this.registry.validate(this.scope.groupKey);
|
|
387
|
+
}
|
|
388
|
+
/** Clear every validator inside this group without validating (dx `reset()`). */
|
|
389
|
+
reset() {
|
|
390
|
+
this.registry.reset(this.scope.groupKey);
|
|
391
|
+
}
|
|
392
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeValidationGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
393
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.5", type: NxeValidationGroupComponent, isStandalone: true, selector: "nxe-validation-group", providers: [
|
|
394
|
+
{
|
|
395
|
+
provide: NXE_VALIDATION_GROUP,
|
|
396
|
+
useFactory: () => ({ groupKey: `nxe-group-${nextGroupId++}` }),
|
|
397
|
+
},
|
|
398
|
+
], ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
399
|
+
}
|
|
400
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeValidationGroupComponent, decorators: [{
|
|
401
|
+
type: Component,
|
|
402
|
+
args: [{
|
|
403
|
+
selector: 'nxe-validation-group',
|
|
404
|
+
standalone: true,
|
|
405
|
+
template: '<ng-content />',
|
|
406
|
+
providers: [
|
|
407
|
+
{
|
|
408
|
+
provide: NXE_VALIDATION_GROUP,
|
|
409
|
+
useFactory: () => ({ groupKey: `nxe-group-${nextGroupId++}` }),
|
|
410
|
+
},
|
|
411
|
+
],
|
|
412
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
413
|
+
encapsulation: ViewEncapsulation.None,
|
|
414
|
+
}]
|
|
415
|
+
}] });
|
|
416
|
+
|
|
262
417
|
// @nexterajs/ui/validation — public API.
|
|
263
418
|
|
|
264
419
|
/**
|
|
265
420
|
* Generated bundle index. Do not edit.
|
|
266
421
|
*/
|
|
267
422
|
|
|
268
|
-
export { NXE_DEFAULT_VALIDATION_MESSAGES, NxeValidationRuleComponent, NxeValidatorComponent, NxeValidators };
|
|
423
|
+
export { NXE_DEFAULT_VALIDATION_MESSAGES, NxeValidationGroupComponent, NxeValidationRuleComponent, NxeValidatorComponent, NxeValidators, nxeDefaultMessage, nxeEvaluateRule, nxeIsEmptyValue };
|
|
269
424
|
//# sourceMappingURL=nexterajs-ui-validation.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nexterajs-ui-validation.mjs","sources":["../../../projects/nextera-ui/validation/src/lib/validation/nxe-validation-rule.component.ts","../../../projects/nextera-ui/validation/src/lib/validation/nxe-validator.component.ts","../../../projects/nextera-ui/validation/src/lib/validation/nxe-validators.ts","../../../projects/nextera-ui/validation/src/public-api.ts","../../../projects/nextera-ui/validation/src/nexterajs-ui-validation.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from '@angular/core';\r\n\r\n/** DevExtreme validation rule type (the codebase uses `required`, `compare`, and `range`). */\r\nexport type NxeValidationRuleType = 'required' | 'compare' | 'custom' | 'pattern' | 'email' | 'range';\r\n\r\n/**\r\n * The message shown when a rule fails and the caller gave none.\r\n *\r\n * These are DevExtreme's own defaults, verbatim from its `validation-*` message keys. Without\r\n * them a rule with no `message` blocks its group and displays nothing at all, because every\r\n * editor renders its error bubble under `@if (validationError())` — falsy for the empty string.\r\n */\r\nexport const NXE_DEFAULT_VALIDATION_MESSAGES: Readonly<Record<NxeValidationRuleType, string>> = {\r\n required: 'Required',\r\n email: 'Email is invalid',\r\n pattern: 'Value does not match pattern',\r\n range: 'Value is out of range',\r\n compare: 'Values do not match',\r\n custom: 'Value is invalid',\r\n};\r\n\r\n/** Payload passed to a `custom` rule's `validationCallback` (mirrors DevExtreme). */\r\nexport interface NxeCustomRuleData {\r\n value: unknown;\r\n rule: NxeValidationRuleComponent;\r\n}\r\n\r\n/**\r\n * `nxe-validation-rule` — drop-in for DevExtreme `dxi-validation-rule`.\r\n *\r\n * A no-template configuration child of `nxe-validator`. The codebase uses the universal element\r\n * with a `type` attribute (overwhelmingly `type=\"required\"`), so a single component with a\r\n * `type` input covers 100% of usage.\r\n */\r\n@Component({\r\n selector: 'nxe-validation-rule',\r\n standalone: true,\r\n template: '',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class NxeValidationRuleComponent {\r\n readonly type = input<NxeValidationRuleType>('required');\r\n readonly message = input<string>('');\r\n\r\n /** `compare` rule: returns the value to compare against. Mirrors `comparisonTarget`. */\r\n readonly comparisonTarget = input<(() => unknown) | undefined>(undefined);\r\n /** `compare` rule comparison operator (default `==`). */\r\n readonly comparisonType = input<'==' | '===' | '!=' | '!==' | '>' | '<' | '>=' | '<='>('==');\r\n\r\n /** `custom` rule: returns true when valid. Mirrors `validationCallback`. */\r\n readonly validationCallback = input<((data: NxeCustomRuleData) => boolean) | undefined>(undefined);\r\n\r\n /** `pattern` rule. */\r\n readonly pattern = input<string | RegExp | undefined>(undefined);\r\n\r\n /** `range` rule bounds (DevExtreme RangeRule: empty values pass, bounds are inclusive). */\r\n readonly min = input<number | undefined>(undefined);\r\n readonly max = input<number | undefined>(undefined);\r\n\r\n /**\r\n * The message to show when this rule fails: the caller's, or DevExtreme's default for the\r\n * rule type. Whitespace counts as absent — a message of spaces is still an empty bubble.\r\n */\r\n readonly resolvedMessage = computed(\r\n () => this.message().trim() || NXE_DEFAULT_VALIDATION_MESSAGES[this.type()] || '',\r\n );\r\n\r\n /** Whether `value` satisfies this rule. */\r\n evaluate(value: unknown): boolean {\r\n switch (this.type()) {\r\n case 'required':\r\n return !this.isEmpty(value);\r\n case 'compare':\r\n return this.compare(value);\r\n case 'range':\r\n return this.isEmpty(value) || this.inRange(value);\r\n case 'pattern':\r\n return this.isEmpty(value) || this.matchesPattern(value);\r\n case 'email':\r\n return this.isEmpty(value) || /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(String(value));\r\n case 'custom':\r\n return this.validationCallback()?.({ value, rule: this }) ?? true;\r\n default:\r\n return true;\r\n }\r\n }\r\n\r\n /** DevExtreme RequiredRule semantics: null/undefined/''/false are \"not specified\". */\r\n private isEmpty(value: unknown): boolean {\r\n return (\r\n value === null ||\r\n value === undefined ||\r\n value === '' ||\r\n value === false ||\r\n (Array.isArray(value) && value.length === 0)\r\n );\r\n }\r\n\r\n private compare(value: unknown): boolean {\r\n const target = this.comparisonTarget()?.();\r\n switch (this.comparisonType()) {\r\n case '===':\r\n return value === target;\r\n case '!=':\r\n // eslint-disable-next-line eqeqeq\r\n return value != target;\r\n case '!==':\r\n return value !== target;\r\n case '>':\r\n return (value as number) > (target as number);\r\n case '<':\r\n return (value as number) < (target as number);\r\n case '>=':\r\n return (value as number) >= (target as number);\r\n case '<=':\r\n return (value as number) <= (target as number);\r\n case '==':\r\n default:\r\n // eslint-disable-next-line eqeqeq\r\n return value == target;\r\n }\r\n }\r\n\r\n private inRange(value: unknown): boolean {\r\n const num = Number(value);\r\n if (Number.isNaN(num)) {\r\n return false;\r\n }\r\n const min = this.min();\r\n const max = this.max();\r\n return (min === undefined || num >= min) && (max === undefined || num <= max);\r\n }\r\n\r\n private matchesPattern(value: unknown): boolean {\r\n const pattern = this.pattern();\r\n if (!pattern) {\r\n return true;\r\n }\r\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\r\n return regex.test(String(value));\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n contentChildren,\r\n DestroyRef,\r\n inject,\r\n Injector,\r\n input,\r\n signal,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';\r\nimport { distinctUntilChanged, pairwise, startWith } from 'rxjs';\r\nimport { NxeValidationGroupRegistry } from '@nexterajs/ui/core';\r\nimport {\r\n NXE_VALIDATION_TARGET,\r\n NxeValidationResult,\r\n} from '@nexterajs/ui/core';\r\nimport { NxeValidationRuleComponent } from './nxe-validation-rule.component';\r\n\r\n/**\r\n * `nxe-validator` — drop-in for DevExtreme `dx-validator`.\r\n *\r\n * Placed inside an editor (`<nxe-text-box><nxe-validator><nxe-validation-rule .../></nxe-validator></nxe-text-box>`),\r\n * it adapts the editor via {@link NXE_VALIDATION_TARGET}, collects its `nxe-validation-rule`\r\n * children, and registers into the {@link NxeValidationGroupRegistry} under the editor's\r\n * `validationGroup`. Validation is on-demand (matching DevExtreme: not auto-run on change) —\r\n * `validate()` is invoked by `nxe-button[validationGroup]` (group-level) or directly.\r\n */\r\n@Component({\r\n selector: 'nxe-validator',\r\n standalone: true,\r\n template: '<ng-content />',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class NxeValidatorComponent {\r\n private readonly target = inject(NXE_VALIDATION_TARGET, { optional: true });\r\n private readonly registry = inject(NxeValidationGroupRegistry);\r\n\r\n readonly rules = contentChildren(NxeValidationRuleComponent);\r\n\r\n /** Explicit group; otherwise inherited from the wrapped editor's `validationGroup`. */\r\n readonly validationGroupInput = input<string | undefined>(undefined, { alias: 'validationGroup' });\r\n // Bare validators (no group) join the implicit default group `''` — mirroring DevExtreme's\r\n // global default group — so a groupless `nxe-button` validates them.\r\n private readonly group = computed(\r\n () => this.validationGroupInput() ?? this.target?.validationGroup() ?? '',\r\n );\r\n\r\n /** Last validation outcome (false once a rule has failed, until re-validated). */\r\n readonly isValid = signal(true);\r\n\r\n /** DevExtreme parity: existing code calls `validator.instance.validate()` via `@ViewChild`. */\r\n get instance(): NxeValidatorComponent {\r\n return this;\r\n }\r\n\r\n private readonly member = { validate: () => this.validate() };\r\n\r\n constructor() {\r\n // Register/unregister into the named group reactively (handles dynamic group changes).\r\n /* ⚠ NOT an effect - UI-48. The registration follows ONE signal, and the unregister that\r\n `onCleanup` used to run is the pairwise step below: a group change unregisters the old\r\n one before registering the new, and destruction unregisters the last. */\r\n toObservable(this.group, { injector: inject(Injector) })\r\n .pipe(\r\n distinctUntilChanged(),\r\n startWith(undefined as string | undefined),\r\n pairwise(),\r\n takeUntilDestroyed(),\r\n )\r\n .subscribe(([ previous, group ]) => {\r\n if (previous !== undefined) {\r\n this.registry.unregister(previous, this.member);\r\n }\r\n\r\n this.registry.register(group, this.member);\r\n });\r\n\r\n inject(DestroyRef).onDestroy(() => this.registry.unregister(this.group(), this.member));\r\n }\r\n\r\n /** Run all rules against the editor's current value; pushes the first failing message. */\r\n validate(): NxeValidationResult {\r\n const value = this.target?.getValue();\r\n for (const rule of this.rules()) {\r\n if (!rule.evaluate(value)) {\r\n // resolvedMessage(), not message(): a rule declared without one would otherwise\r\n // push the empty string, and every editor guards its bubble with\r\n // `@if (validationError())` — so the field would block the group in silence.\r\n const message = rule.resolvedMessage();\r\n this.isValid.set(false);\r\n this.target?.setValidationError(message);\r\n return {\r\n isValid: false,\r\n brokenRules: [{ type: rule.type(), message }],\r\n status: 'invalid',\r\n };\r\n }\r\n }\r\n this.isValid.set(true);\r\n this.target?.setValidationError(null);\r\n return { isValid: true, brokenRules: [], status: 'valid' };\r\n }\r\n}\r\n","import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';\r\n\r\nexport class NxeValidators {\r\n /**\r\n * Check for empty (optional fields) values\r\n *\r\n * @param value\r\n */\r\n static isEmptyInputValue(value: any): boolean {\r\n return value == null || value.length === 0;\r\n }\r\n\r\n /**\r\n * Must match validator\r\n *\r\n * @param controlPath A dot-delimited string values that define the path to the control.\r\n * @param matchingControlPath A dot-delimited string values that define the path to the matching control.\r\n */\r\n static mustMatch(controlPath: string, matchingControlPath: string): ValidatorFn {\r\n return (formGroup: AbstractControl): ValidationErrors | null => {\r\n // Get the control and matching control\r\n const control = formGroup.get(controlPath);\r\n const matchingControl = formGroup.get(matchingControlPath);\r\n\r\n // Return if control or matching control doesn't exist\r\n if (!control || !matchingControl) {\r\n return null;\r\n }\r\n\r\n // Delete the mustMatch error to reset the error on the matching control\r\n if (matchingControl.hasError('mustMatch')) {\r\n delete matchingControl.errors.mustMatch;\r\n matchingControl.updateValueAndValidity();\r\n }\r\n\r\n // Don't validate empty values on the matching control\r\n // Don't validate if values are matching\r\n if (this.isEmptyInputValue(matchingControl.value) || control.value === matchingControl.value) {\r\n return null;\r\n }\r\n\r\n // Prepare the validation errors\r\n const errors = { mustMatch: true };\r\n\r\n // Set the validation error on the matching control\r\n matchingControl.setErrors(errors);\r\n\r\n // Return the errors\r\n return errors;\r\n };\r\n }\r\n}\r\n","// @nexterajs/ui/validation — public API.\r\nexport * from './lib/validation/nxe-validation-rule.component';\r\nexport * from './lib/validation/nxe-validator.component';\r\nexport * from './lib/validation/nxe-validators';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nexterajs-ui-validation.mjs","sources":["../../../projects/nextera-ui/validation/src/lib/validation/nxe-validation-rule.component.ts","../../../projects/nextera-ui/validation/src/lib/validation/nxe-validator.component.ts","../../../projects/nextera-ui/validation/src/lib/validation/nxe-validators.ts","../../../projects/nextera-ui/validation/src/lib/validation/nxe-validation-group.component.ts","../../../projects/nextera-ui/validation/src/public-api.ts","../../../projects/nextera-ui/validation/src/nexterajs-ui-validation.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from '@angular/core';\r\n\r\n/** DevExtreme validation rule type (the codebase uses `required`, `compare`, and `range`). */\r\nexport type NxeValidationRuleType = 'required' | 'compare' | 'custom' | 'pattern' | 'email' | 'range';\r\n\r\n/**\r\n * The message shown when a rule fails and the caller gave none.\r\n *\r\n * These are DevExtreme's own defaults, verbatim from its `validation-*` message keys. Without\r\n * them a rule with no `message` blocks its group and displays nothing at all, because every\r\n * editor renders its error bubble under `@if (validationError())` — falsy for the empty string.\r\n */\r\nexport const NXE_DEFAULT_VALIDATION_MESSAGES: Readonly<Record<NxeValidationRuleType, string>> = {\r\n required: 'Required',\r\n email: 'Email is invalid',\r\n pattern: 'Value does not match pattern',\r\n range: 'Value is out of range',\r\n compare: 'Values do not match',\r\n custom: 'Value is invalid',\r\n};\r\n\r\n/** Payload passed to a `custom` rule's `validationCallback` (mirrors DevExtreme). */\r\nexport interface NxeCustomRuleData {\r\n value: unknown;\r\n /** Absent when the rule came from `[validationRules]` rather than a projected element. */\r\n rule?: NxeValidationRuleComponent;\r\n}\r\n\r\n/**\r\n * A rule as plain data.\r\n *\r\n * The projected `<nxe-validation-rule>` and the `[validationRules]` array are two ways of saying\r\n * the same thing, so they evaluate through one function rather than two implementations that\r\n * could drift.\r\n */\r\nexport interface NxeRuleSpec {\r\n type: NxeValidationRuleType;\r\n message?: string;\r\n comparisonTarget?: () => unknown;\r\n comparisonType?: '==' | '===' | '!=' | '!==' | '>' | '<' | '>=' | '<=';\r\n validationCallback?: (data: NxeCustomRuleData) => boolean;\r\n pattern?: string | RegExp;\r\n min?: number;\r\n max?: number;\r\n}\r\n\r\n/** DevExtreme RequiredRule semantics: null/undefined/''/false are \"not specified\". */\r\nexport function nxeIsEmptyValue(value: unknown): boolean {\r\n return (\r\n value === null ||\r\n value === undefined ||\r\n value === '' ||\r\n value === false ||\r\n (Array.isArray(value) && value.length === 0)\r\n );\r\n}\r\n\r\n/** The message for a rule with none of its own. */\r\nexport function nxeDefaultMessage(type: NxeValidationRuleType): string {\r\n return NXE_DEFAULT_VALIDATION_MESSAGES[type] ?? '';\r\n}\r\n\r\n/** Whether `value` satisfies `spec`. The single evaluator behind both rule forms. */\r\nexport function nxeEvaluateRule(spec: NxeRuleSpec, value: unknown, rule?: NxeValidationRuleComponent): boolean {\r\n switch (spec.type) {\r\n case 'required':\r\n return !nxeIsEmptyValue(value);\r\n case 'compare': {\r\n const target = spec.comparisonTarget?.();\r\n switch (spec.comparisonType) {\r\n case '===':\r\n return value === target;\r\n case '!=':\r\n // eslint-disable-next-line eqeqeq\r\n return value != target;\r\n case '!==':\r\n return value !== target;\r\n case '>':\r\n return (value as number) > (target as number);\r\n case '<':\r\n return (value as number) < (target as number);\r\n case '>=':\r\n return (value as number) >= (target as number);\r\n case '<=':\r\n return (value as number) <= (target as number);\r\n case '==':\r\n default:\r\n // eslint-disable-next-line eqeqeq\r\n return value == target;\r\n }\r\n }\r\n case 'range': {\r\n if (nxeIsEmptyValue(value)) {\r\n return true;\r\n }\r\n const num = Number(value);\r\n if (Number.isNaN(num)) {\r\n return false;\r\n }\r\n return (\r\n (spec.min === undefined || num >= spec.min) &&\r\n (spec.max === undefined || num <= spec.max)\r\n );\r\n }\r\n case 'pattern': {\r\n if (nxeIsEmptyValue(value) || !spec.pattern) {\r\n return true;\r\n }\r\n const regex = typeof spec.pattern === 'string' ? new RegExp(spec.pattern) : spec.pattern;\r\n return regex.test(String(value));\r\n }\r\n case 'email':\r\n return nxeIsEmptyValue(value) || /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(String(value));\r\n case 'custom':\r\n return spec.validationCallback?.({ value, rule }) ?? true;\r\n default:\r\n return true;\r\n }\r\n}\r\n\r\n/**\r\n * `nxe-validation-rule` — drop-in for DevExtreme `dxi-validation-rule`.\r\n *\r\n * A no-template configuration child of `nxe-validator`. The codebase uses the universal element\r\n * with a `type` attribute (overwhelmingly `type=\"required\"`), so a single component with a\r\n * `type` input covers 100% of usage.\r\n */\r\n@Component({\r\n selector: 'nxe-validation-rule',\r\n standalone: true,\r\n template: '',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class NxeValidationRuleComponent {\r\n readonly type = input<NxeValidationRuleType>('required');\r\n readonly message = input<string>('');\r\n\r\n /** `compare` rule: returns the value to compare against. Mirrors `comparisonTarget`. */\r\n readonly comparisonTarget = input<(() => unknown) | undefined>(undefined);\r\n /** `compare` rule comparison operator (default `==`). */\r\n readonly comparisonType = input<'==' | '===' | '!=' | '!==' | '>' | '<' | '>=' | '<='>('==');\r\n\r\n /** `custom` rule: returns true when valid. Mirrors `validationCallback`. */\r\n readonly validationCallback = input<((data: NxeCustomRuleData) => boolean) | undefined>(undefined);\r\n\r\n /** `pattern` rule. */\r\n readonly pattern = input<string | RegExp | undefined>(undefined);\r\n\r\n /** `range` rule bounds (DevExtreme RangeRule: empty values pass, bounds are inclusive). */\r\n readonly min = input<number | undefined>(undefined);\r\n readonly max = input<number | undefined>(undefined);\r\n\r\n /**\r\n * The message to show when this rule fails: the caller's, or DevExtreme's default for the\r\n * rule type. Whitespace counts as absent — a message of spaces is still an empty bubble.\r\n */\r\n readonly resolvedMessage = computed(\r\n () => this.message().trim() || NXE_DEFAULT_VALIDATION_MESSAGES[this.type()] || '',\r\n );\r\n\r\n /** This rule as plain data, so both rule forms evaluate through one function. */\r\n toSpec(): NxeRuleSpec {\r\n return {\r\n type: this.type(),\r\n message: this.message(),\r\n comparisonTarget: this.comparisonTarget(),\r\n comparisonType: this.comparisonType(),\r\n validationCallback: this.validationCallback(),\r\n pattern: this.pattern(),\r\n min: this.min(),\r\n max: this.max(),\r\n };\r\n }\r\n\r\n /** Whether `value` satisfies this rule. */\r\n evaluate(value: unknown): boolean {\r\n return nxeEvaluateRule(this.toSpec(), value, this);\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n contentChildren,\r\n DestroyRef,\r\n inject,\r\n Injector,\r\n input,\r\n output,\r\n signal,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';\r\nimport { distinctUntilChanged, pairwise, skip, startWith } from 'rxjs';\r\nimport { NxeValidationGroupRegistry } from '@nexterajs/ui/core';\r\nimport {\r\n NXE_VALIDATION_GROUP,\r\n NXE_VALIDATION_TARGET,\r\n NxeBrokenRule,\r\n NxeValidatedEvent,\r\n NxeValidationResult,\r\n} from '@nexterajs/ui/core';\r\nimport {\r\n nxeDefaultMessage,\r\n nxeEvaluateRule,\r\n NxeRuleSpec,\r\n NxeValidationRuleComponent,\r\n} from './nxe-validation-rule.component';\r\n\r\n/**\r\n * `nxe-validator` — drop-in for DevExtreme `dx-validator`.\r\n *\r\n * Placed inside an editor (`<nxe-text-box><nxe-validator><nxe-validation-rule .../></nxe-validator></nxe-text-box>`),\r\n * it adapts the editor via {@link NXE_VALIDATION_TARGET}, collects its rules, and registers into\r\n * the {@link NxeValidationGroupRegistry} under the editor's `validationGroup`.\r\n *\r\n * Validation is on demand, as in DevExtreme — `validate()` is invoked by\r\n * `nxe-button[validationGroup]` or directly. With one exception, which is also dx's: once a\r\n * validator HAS been validated, it re-validates as the value changes, so a field that has gone\r\n * red clears itself as the user fixes it rather than staying red until the next submit.\r\n */\r\n@Component({\r\n selector: 'nxe-validator',\r\n standalone: true,\r\n template: '<ng-content />',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class NxeValidatorComponent {\r\n private readonly target = inject(NXE_VALIDATION_TARGET, { optional: true });\r\n private readonly registry = inject(NxeValidationGroupRegistry);\r\n private readonly groupScope = inject(NXE_VALIDATION_GROUP, { optional: true });\r\n\r\n readonly rules = contentChildren(NxeValidationRuleComponent);\r\n\r\n /**\r\n * dx `validationRules` — rules as data instead of projected children. Both forms combine;\r\n * projected children come first, matching declaration order.\r\n */\r\n readonly validationRules = input<readonly NxeRuleSpec[] | undefined>(undefined);\r\n\r\n /** Explicit group; otherwise inherited from the wrapped editor's `validationGroup`. */\r\n readonly validationGroupInput = input<string | undefined>(undefined, { alias: 'validationGroup' });\r\n\r\n /** dx `onValidated`, fired on every validation, valid or not. */\r\n readonly onValidated = output<NxeValidatedEvent>();\r\n\r\n // An explicit name wins over a surrounding `nxe-validation-group`, as in dx. Bare validators\r\n // with neither join the implicit default group `''` — dx's global group — so a groupless\r\n // `nxe-button` validates them.\r\n private readonly group = computed(\r\n () =>\r\n this.validationGroupInput() ??\r\n this.target?.validationGroup() ??\r\n this.groupScope?.groupKey ??\r\n '',\r\n );\r\n\r\n /** Last validation outcome (false once a rule has failed, until re-validated). */\r\n readonly isValid = signal(true);\r\n\r\n /** Every rule broken by the last validation, in declaration order. */\r\n readonly brokenRules = signal<readonly NxeBrokenRule[]>([]);\r\n\r\n /** Whether `validate()` has ever run — the gate on live re-validation. */\r\n private readonly validated = signal(false);\r\n\r\n /** DevExtreme parity: existing code calls `validator.instance.validate()` via `@ViewChild`. */\r\n get instance(): NxeValidatorComponent {\r\n return this;\r\n }\r\n\r\n private readonly member = { validate: () => this.validate(), reset: () => this.reset() };\r\n\r\n /** Projected children plus `[validationRules]`, as one evaluable list. */\r\n private readonly allRules = computed(() => [\r\n ...this.rules().map((rule) => ({\r\n type: rule.type(),\r\n evaluate: (value: unknown) => rule.evaluate(value),\r\n message: () => rule.resolvedMessage(),\r\n })),\r\n ...(this.validationRules() ?? []).map((spec) => ({\r\n type: spec.type,\r\n evaluate: (value: unknown) => nxeEvaluateRule(spec, value),\r\n message: () => spec.message?.trim() || nxeDefaultMessage(spec.type),\r\n })),\r\n ]);\r\n\r\n constructor() {\r\n const injector = inject(Injector);\r\n\r\n // Register/unregister into the named group reactively (handles dynamic group changes).\r\n /* ⚠ NOT an effect - UI-48. The registration follows ONE signal, and the unregister that\r\n `onCleanup` used to run is the pairwise step below: a group change unregisters the old\r\n one before registering the new, and destruction unregisters the last. */\r\n toObservable(this.group, { injector })\r\n .pipe(\r\n distinctUntilChanged(),\r\n startWith(undefined as string | undefined),\r\n pairwise(),\r\n takeUntilDestroyed(),\r\n )\r\n .subscribe(([previous, group]) => {\r\n if (previous !== undefined) {\r\n this.registry.unregister(previous, this.member);\r\n }\r\n\r\n this.registry.register(group, this.member);\r\n });\r\n\r\n // dx re-validates a field that has already been validated as its value changes, so an\r\n // error clears while the user types rather than surviving until the next submit.\r\n /* ⚠ NOT an effect - UI-48. This takes exactly one dependency, the target's value, named\r\n here rather than inferred from whatever `validate()` happens to read. */\r\n toObservable(\r\n computed(() => this.target?.getValue()),\r\n { injector },\r\n )\r\n .pipe(skip(1), takeUntilDestroyed())\r\n .subscribe(() => {\r\n if (this.validated()) {\r\n this.validate();\r\n }\r\n });\r\n\r\n // Tell the editor whether it is required, so it can render aria-required. The rule is\r\n // where the requirement is stated; the editor should not have to be told twice.\r\n /* ⚠ NOT an effect - UI-48: one named dependency, the resolved rule list. */\r\n toObservable(\r\n computed(() => this.allRules().some((rule) => rule.type === 'required')),\r\n { injector },\r\n )\r\n .pipe(takeUntilDestroyed())\r\n .subscribe((required) => this.target?.setRequired?.(required));\r\n\r\n inject(DestroyRef).onDestroy(() => {\r\n this.registry.unregister(this.group(), this.member);\r\n // The editor outlives its validator when the validator sits inside an @if, and a\r\n // field left advertising aria-required by a rule that no longer exists is worse than\r\n // one that never advertised it.\r\n this.target?.setRequired?.(false);\r\n this.target?.setValidationError(null);\r\n });\r\n }\r\n\r\n\r\n /**\r\n * Run every rule against the editor's current value.\r\n *\r\n * dx reports ALL broken rules, not just the first — a `brokenRules` array with at most one\r\n * entry cannot tell a caller whether a field failed once or three times. The editor's bubble\r\n * still shows the first message, which is what dx renders.\r\n */\r\n validate(): NxeValidationResult {\r\n const value = this.target?.getValue();\r\n const broken: NxeBrokenRule[] = [];\r\n for (const rule of this.allRules()) {\r\n if (!rule.evaluate(value)) {\r\n // resolvedMessage(), not message(): a rule declared without one would otherwise\r\n // push the empty string, and every editor guards its bubble with\r\n // `@if (validationError())` — so the field would block the group in silence.\r\n broken.push({ type: rule.type, message: rule.message() });\r\n }\r\n }\r\n this.validated.set(true);\r\n this.brokenRules.set(broken);\r\n this.isValid.set(broken.length === 0);\r\n this.target?.setValidationError(broken.length ? broken[0].message : null);\r\n\r\n const result: NxeValidationResult = {\r\n isValid: broken.length === 0,\r\n brokenRules: broken,\r\n status: broken.length === 0 ? 'valid' : 'invalid',\r\n };\r\n this.onValidated.emit({ ...result, value, validationGroup: this.group() });\r\n return result;\r\n }\r\n\r\n /**\r\n * Clear the error state without validating (dx `reset()`).\r\n *\r\n * Also clears `validated`, so the field goes back to staying quiet until it is validated\r\n * again — otherwise a reset field would light up on the next keystroke.\r\n */\r\n reset(): void {\r\n this.validated.set(false);\r\n this.brokenRules.set([]);\r\n this.isValid.set(true);\r\n this.target?.setValidationError(null);\r\n }\r\n}\r\n","import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';\r\n\r\nexport class NxeValidators {\r\n /**\r\n * Check for empty (optional fields) values\r\n *\r\n * @param value\r\n */\r\n static isEmptyInputValue(value: any): boolean {\r\n return value == null || value.length === 0;\r\n }\r\n\r\n /**\r\n * Must match validator\r\n *\r\n * @param controlPath A dot-delimited string values that define the path to the control.\r\n * @param matchingControlPath A dot-delimited string values that define the path to the matching control.\r\n */\r\n static mustMatch(controlPath: string, matchingControlPath: string): ValidatorFn {\r\n return (formGroup: AbstractControl): ValidationErrors | null => {\r\n // Get the control and matching control\r\n const control = formGroup.get(controlPath);\r\n const matchingControl = formGroup.get(matchingControlPath);\r\n\r\n // Return if control or matching control doesn't exist\r\n if (!control || !matchingControl) {\r\n return null;\r\n }\r\n\r\n // Delete the mustMatch error to reset the error on the matching control\r\n if (matchingControl.hasError('mustMatch')) {\r\n delete matchingControl.errors.mustMatch;\r\n matchingControl.updateValueAndValidity();\r\n }\r\n\r\n // Don't validate empty values on the matching control\r\n // Don't validate if values are matching\r\n if (this.isEmptyInputValue(matchingControl.value) || control.value === matchingControl.value) {\r\n return null;\r\n }\r\n\r\n // Prepare the validation errors\r\n const errors = { mustMatch: true };\r\n\r\n // Set the validation error on the matching control\r\n matchingControl.setErrors(errors);\r\n\r\n // Return the errors\r\n return errors;\r\n };\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n inject,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport {\r\n NXE_VALIDATION_GROUP,\r\n NxeValidationGroupRegistry,\r\n NxeValidationResult,\r\n} from '@nexterajs/ui/core';\r\n\r\nlet nextGroupId = 0;\r\n\r\n/**\r\n * `nxe-validation-group` — drop-in for DevExtreme `dx-validation-group`.\r\n *\r\n * DevExtreme lets a group be addressed two ways. Either a string name is repeated on the\r\n * validator and on the button, or both are wrapped in a group element and the relationship is\r\n * structural. Only the string form existed here, which meant a form could not be validated as a\r\n * unit without inventing a name for it and keeping that name in two places.\r\n *\r\n * The key is generated, not derived from anything the application controls, so two groups on one\r\n * page cannot collide and a group can never accidentally share a name with a string group. An\r\n * explicit `validationGroup` on a descendant still wins, as in dx — the structural form is a\r\n * default, not an override.\r\n */\r\n@Component({\r\n selector: 'nxe-validation-group',\r\n standalone: true,\r\n template: '<ng-content />',\r\n providers: [\r\n {\r\n provide: NXE_VALIDATION_GROUP,\r\n useFactory: () => ({ groupKey: `nxe-group-${nextGroupId++}` }),\r\n },\r\n ],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class NxeValidationGroupComponent {\r\n private readonly registry = inject(NxeValidationGroupRegistry);\r\n private readonly scope = inject(NXE_VALIDATION_GROUP);\r\n\r\n /** The generated key descendants register under. Exposed for a caller that needs to name it. */\r\n get groupKey(): string {\r\n return this.scope.groupKey;\r\n }\r\n\r\n /** DevExtreme parity: `group.instance.validate()` / `.reset()`. */\r\n get instance(): NxeValidationGroupComponent {\r\n return this;\r\n }\r\n\r\n /** Validate every validator inside this group. */\r\n validate(): NxeValidationResult {\r\n return this.registry.validate(this.scope.groupKey);\r\n }\r\n\r\n /** Clear every validator inside this group without validating (dx `reset()`). */\r\n reset(): void {\r\n this.registry.reset(this.scope.groupKey);\r\n }\r\n}\r\n","// @nexterajs/ui/validation — public API.\r\nexport * from './lib/validation/nxe-validation-rule.component';\r\nexport * from './lib/validation/nxe-validator.component';\r\nexport * from './lib/validation/nxe-validators';\r\nexport * from './lib/validation/nxe-validation-group.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ export * from '@nexterajs/ui/file-uploader';
|
|
|
6
6
|
export * from '@nexterajs/ui/forms';
|
|
7
7
|
export * from '@nexterajs/ui/grid';
|
|
8
8
|
export * from '@nexterajs/ui/intl';
|
|
9
|
+
export * from '@nexterajs/ui/notify';
|
|
9
10
|
export * from '@nexterajs/ui/pivot';
|
|
10
11
|
export * from '@nexterajs/ui/styling';
|
|
11
12
|
export * from '@nexterajs/ui/tree-view';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nexterajs-ui.mjs","sources":["../../../projects/nextera-ui/src/public-api.ts","../../../projects/nextera-ui/src/nexterajs-ui.ts"],"sourcesContent":["// @nexterajs/ui — compatibility barrel.\r\n//\r\n// Re-exports every secondary entry point so importing from the bare specifier keeps working.\r\n// Prefer the specific entry point (@nexterajs/ui/grid) in new code: it keeps the pivot engine\r\n// and the xlsx writer out of your bundle and out of your dev-server rebuilds.\r\nexport * from '@nexterajs/ui/animations';\r\nexport * from '@nexterajs/ui/core';\r\nexport * from '@nexterajs/ui/dropdowns';\r\nexport * from '@nexterajs/ui/excel';\r\nexport * from '@nexterajs/ui/file-uploader';\r\nexport * from '@nexterajs/ui/forms';\r\nexport * from '@nexterajs/ui/grid';\r\nexport * from '@nexterajs/ui/intl';\r\nexport * from '@nexterajs/ui/pivot';\r\nexport * from '@nexterajs/ui/styling';\r\nexport * from '@nexterajs/ui/tree-view';\r\nexport * from '@nexterajs/ui/validation';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nexterajs-ui.mjs","sources":["../../../projects/nextera-ui/src/public-api.ts","../../../projects/nextera-ui/src/nexterajs-ui.ts"],"sourcesContent":["// @nexterajs/ui — compatibility barrel.\r\n//\r\n// Re-exports every secondary entry point so importing from the bare specifier keeps working.\r\n// Prefer the specific entry point (@nexterajs/ui/grid) in new code: it keeps the pivot engine\r\n// and the xlsx writer out of your bundle and out of your dev-server rebuilds.\r\nexport * from '@nexterajs/ui/animations';\r\nexport * from '@nexterajs/ui/core';\r\nexport * from '@nexterajs/ui/dropdowns';\r\nexport * from '@nexterajs/ui/excel';\r\nexport * from '@nexterajs/ui/file-uploader';\r\nexport * from '@nexterajs/ui/forms';\r\nexport * from '@nexterajs/ui/grid';\r\nexport * from '@nexterajs/ui/intl';\r\nexport * from '@nexterajs/ui/notify';\r\nexport * from '@nexterajs/ui/pivot';\r\nexport * from '@nexterajs/ui/styling';\r\nexport * from '@nexterajs/ui/tree-view';\r\nexport * from '@nexterajs/ui/validation';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;;ACJA;;AAEG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexterajs/ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/animations": "^22.0.0",
|
|
6
6
|
"@angular/cdk": "^22.0.0",
|
|
@@ -58,6 +58,10 @@
|
|
|
58
58
|
"types": "./types/nexterajs-ui-intl.d.ts",
|
|
59
59
|
"default": "./fesm2022/nexterajs-ui-intl.mjs"
|
|
60
60
|
},
|
|
61
|
+
"./notify": {
|
|
62
|
+
"types": "./types/nexterajs-ui-notify.d.ts",
|
|
63
|
+
"default": "./fesm2022/nexterajs-ui-notify.mjs"
|
|
64
|
+
},
|
|
61
65
|
"./pivot": {
|
|
62
66
|
"types": "./types/nexterajs-ui-pivot.d.ts",
|
|
63
67
|
"default": "./fesm2022/nexterajs-ui-pivot.mjs"
|