@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,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ElementRef, input, booleanAttribute, computed, output, ViewEncapsulation, ChangeDetectionStrategy, Component, signal, forwardRef, ViewContainerRef
|
|
3
|
-
import { NxeValidationGroupRegistry, NxeFormControlBase, nxeOptionalBoolean, NXE_VALIDATION_TARGET } from '@nexterajs/ui/core';
|
|
2
|
+
import { inject, ElementRef, input, booleanAttribute, computed, output, ViewEncapsulation, ChangeDetectionStrategy, Component, signal, viewChild, linkedSignal, forwardRef, ViewContainerRef } from '@angular/core';
|
|
3
|
+
import { NxeValidationGroupRegistry, NXE_VALIDATION_GROUP, NxeFormControlBase, nxeOptionalBoolean, NXE_VALIDATION_TARGET } from '@nexterajs/ui/core';
|
|
4
4
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
5
5
|
import { parseNumberFormat, NXE_NUMBER_SEPARATORS, formatNumber, parseNumber, roundHalfAwayFromZero, parseDateValue, NXE_DEFAULT_DISPLAY_FORMAT, NXE_DEFAULT_DATETIME_DISPLAY_FORMAT, NXE_DEFAULT_TIME_DISPLAY_FORMAT, formatDisplay, buildCalendarWeeks, buildPeriodCells, parseDisplay, serializeDate } from '@nexterajs/ui/intl';
|
|
6
6
|
import { Overlay } from '@angular/cdk/overlay';
|
|
@@ -22,21 +22,22 @@ function cssSize(value) {
|
|
|
22
22
|
/**
|
|
23
23
|
* `nxe-button` — drop-in replacement for DevExtreme `dx-button`.
|
|
24
24
|
*
|
|
25
|
-
* The host element IS the button (mirrors DevExtreme's `
|
|
26
|
-
* styling classes and contains a single `.
|
|
27
|
-
* `.nxe-btn*` / `.
|
|
28
|
-
* shared `buttonLoading` directive working, which swaps `.
|
|
29
|
-
* spinner (`getElementsByClassName('
|
|
25
|
+
* The host element IS the button (mirrors DevExtreme's `nxe-button` DOM: the host carries the
|
|
26
|
+
* styling classes and contains a single `.nxe-button-content` child). This keeps every existing
|
|
27
|
+
* `.nxe-btn*` / `.nxe-button-content` global rule matching verbatim, and — critically — keeps the
|
|
28
|
+
* shared `buttonLoading` directive working, which swaps `.nxe-button-content` innerHTML for a
|
|
29
|
+
* spinner (`getElementsByClassName('nxe-button-content')[0]`).
|
|
30
30
|
*
|
|
31
31
|
* Content is projected (`<nxe-icon> + <span>`, the dominant pattern). The legacy `text`/`type`
|
|
32
|
-
* inputs render a `.
|
|
32
|
+
* inputs render a `.nxe-button-text` label for the ~25 attribute-styled buttons.
|
|
33
33
|
*
|
|
34
34
|
* `onClick` emits {@link NxeButtonClickEvent}; native `(click)` also fires (27 sites bind it).
|
|
35
35
|
*/
|
|
36
36
|
class NxeButtonComponent {
|
|
37
37
|
registry = inject(NxeValidationGroupRegistry);
|
|
38
|
+
groupScope = inject(NXE_VALIDATION_GROUP, { optional: true });
|
|
38
39
|
elementRef = inject(ElementRef);
|
|
39
|
-
/** Legacy `text` label (rendered as `.
|
|
40
|
+
/** Legacy `text` label (rendered as `.nxe-button-text` when set, no projected content). */
|
|
40
41
|
text = input(/* @ts-ignore */
|
|
41
42
|
...(ngDevMode ? [undefined, { debugName: "text" }] : /* istanbul ignore next */ []));
|
|
42
43
|
/** Style intent (`default`=blue, `success`=green, `danger`=red, `normal`=white). */
|
|
@@ -50,8 +51,8 @@ class NxeButtonComponent {
|
|
|
50
51
|
/** DevExtreme parity input; only ever `false` in this codebase (suppresses tab focus). */
|
|
51
52
|
focusStateEnabled = input(true, { ...(ngDevMode ? { debugName: "focusStateEnabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
52
53
|
/**
|
|
53
|
-
* dx `icon` — renders `<i class="
|
|
54
|
-
* `.
|
|
54
|
+
* dx `icon` — renders `<i class="nxe-icon nxe-icon-NAME">` as the first child of
|
|
55
|
+
* `.nxe-button-content`, before any projected content. Projection is the dominant pattern
|
|
55
56
|
* here (a `mat-icon` plus a `span`), so the two must coexist rather than compete.
|
|
56
57
|
*/
|
|
57
58
|
icon = input(undefined, /* @ts-ignore */
|
|
@@ -79,7 +80,10 @@ class NxeButtonComponent {
|
|
|
79
80
|
event.stopImmediatePropagation();
|
|
80
81
|
return;
|
|
81
82
|
}
|
|
82
|
-
|
|
83
|
+
// A named group wins; otherwise a surrounding nxe-validation-group; otherwise dx's
|
|
84
|
+
// implicit global group. Same precedence the validator applies, so a button and the
|
|
85
|
+
// fields beside it always resolve to the same group.
|
|
86
|
+
const group = this.validationGroup() || this.groupScope?.groupKey || '';
|
|
83
87
|
this.onClick.emit({
|
|
84
88
|
event,
|
|
85
89
|
validationGroup: { validate: () => this.registry.validate(group) },
|
|
@@ -88,28 +92,28 @@ class NxeButtonComponent {
|
|
|
88
92
|
});
|
|
89
93
|
}
|
|
90
94
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
91
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeButtonComponent, isStandalone: true, selector: "nxe-button", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, validationGroup: { classPropertyName: "validationGroup", publicName: "validationGroup", isSignal: true, isRequired: false, transformFunction: null }, focusStateEnabled: { classPropertyName: "focusStateEnabled", publicName: "focusStateEnabled", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, host: { attributes: { "role": "button" }, listeners: { "click": "handleClick($event)", "keydown.enter": "handleKeydown($event)", "keydown.space": "handleKeydown($event)" }, properties: { "attr.tabindex": "disabled() || !focusStateEnabled() ? null : 0", "attr.aria-disabled": "disabled() ? true : null", "class.nxe-button-default": "type() === 'default'", "class.nxe-button-success": "type() === 'success'", "class.nxe-button-danger": "type() === 'danger'", "class.nxe-button-has-text": "!!text()", "class.
|
|
92
|
-
<span class="
|
|
95
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeButtonComponent, isStandalone: true, selector: "nxe-button", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, validationGroup: { classPropertyName: "validationGroup", publicName: "validationGroup", isSignal: true, isRequired: false, transformFunction: null }, focusStateEnabled: { classPropertyName: "focusStateEnabled", publicName: "focusStateEnabled", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, host: { attributes: { "role": "button" }, listeners: { "click": "handleClick($event)", "keydown.enter": "handleKeydown($event)", "keydown.space": "handleKeydown($event)" }, properties: { "attr.tabindex": "disabled() || !focusStateEnabled() ? null : 0", "attr.aria-disabled": "disabled() ? true : null", "class.nxe-button-default": "type() === 'default'", "class.nxe-button-success": "type() === 'success'", "class.nxe-button-danger": "type() === 'danger'", "class.nxe-button-has-text": "!!text()", "class.nxe-button-has-icon": "!!icon()", "style.height": "heightStyle()", "style.width": "widthStyle()", "class.nxe-disabled": "disabled()" }, classAttribute: "nxe-widget" }, ngImport: i0, template: `
|
|
96
|
+
<span class="nxe-button-content">
|
|
93
97
|
@if (icon()) {
|
|
94
|
-
<i class="
|
|
98
|
+
<i class="nxe-icon nxe-icon-{{ icon() }}"></i>
|
|
95
99
|
}
|
|
96
100
|
<ng-content />
|
|
97
101
|
@if (text()) {
|
|
98
|
-
<span class="
|
|
102
|
+
<span class="nxe-button-text">{{ text() }}</span>
|
|
99
103
|
}
|
|
100
104
|
</span>
|
|
101
|
-
`, isInline: true, styles: ["nxe-button{display:inline-flex;box-sizing:border-box;cursor:pointer;max-width:100%;overflow:hidden;text-align:center;vertical-align:middle;-webkit-user-select:none;user-select:none;border:1px solid #ddd;border-radius:4px;background-color:#fff;color:#333;font-weight:400;line-height:1.35715}nxe-button:focus{outline:none}nxe-button .
|
|
105
|
+
`, isInline: true, styles: ["nxe-button{display:inline-flex;box-sizing:border-box;cursor:pointer;max-width:100%;overflow:hidden;text-align:center;vertical-align:middle;-webkit-user-select:none;user-select:none;border:1px solid #ddd;border-radius:4px;background-color:#fff;color:#333;font-weight:400;line-height:1.35715}nxe-button:focus{outline:none}nxe-button .nxe-button-content{flex:1 1 auto;display:flex;align-items:center;justify-content:center;gap:var(--nxe-ui-button-gap, 0px);line-height:1.35715;padding:8px}nxe-button.nxe-button-has-text .nxe-button-content{padding-inline:12px}nxe-button.nxe-button-has-text .nxe-button-content>i.nxe-icon{margin-inline-start:0;margin-inline-end:calc(9px - var(--nxe-ui-button-gap, 0px))}nxe-button .nxe-button-text{line-height:1.2858;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nxe-button:hover{background-color:#f4f4f4}nxe-button:active{background-color:#c2c2c2}nxe-button.nxe-button-default{background-color:#337ab7;border-color:transparent;color:#fff}nxe-button.nxe-button-default:hover{background-color:#2d6ca3}nxe-button.nxe-button-default:active{background-color:#19405b}nxe-button.nxe-button-success{background-color:#5cb85c;border-color:transparent;color:#fff}nxe-button.nxe-button-success:hover{background-color:#46a046}nxe-button.nxe-button-success:active{background-color:#306e30}nxe-button.nxe-button-danger{background-color:#d9534f;border-color:transparent;color:#fff}nxe-button.nxe-button-danger:hover{background-color:#cd312c}nxe-button.nxe-button-danger:active{background-color:#932320}nxe-button[disabled]{opacity:.5;cursor:default}nxe-button.nxe-disabled{opacity:.5;cursor:default;pointer-events:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
102
106
|
}
|
|
103
107
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeButtonComponent, decorators: [{
|
|
104
108
|
type: Component,
|
|
105
109
|
args: [{ selector: 'nxe-button', standalone: true, template: `
|
|
106
|
-
<span class="
|
|
110
|
+
<span class="nxe-button-content">
|
|
107
111
|
@if (icon()) {
|
|
108
|
-
<i class="
|
|
112
|
+
<i class="nxe-icon nxe-icon-{{ icon() }}"></i>
|
|
109
113
|
}
|
|
110
114
|
<ng-content />
|
|
111
115
|
@if (text()) {
|
|
112
|
-
<span class="
|
|
116
|
+
<span class="nxe-button-text">{{ text() }}</span>
|
|
113
117
|
}
|
|
114
118
|
</span>
|
|
115
119
|
`, host: {
|
|
@@ -121,15 +125,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
121
125
|
'[class.nxe-button-success]': "type() === 'success'",
|
|
122
126
|
'[class.nxe-button-danger]': "type() === 'danger'",
|
|
123
127
|
'[class.nxe-button-has-text]': '!!text()',
|
|
124
|
-
'[class.
|
|
125
|
-
'[class.dx-button-has-icon]': '!!icon()',
|
|
128
|
+
'[class.nxe-button-has-icon]': '!!icon()',
|
|
126
129
|
'[style.height]': 'heightStyle()',
|
|
127
130
|
'[style.width]': 'widthStyle()',
|
|
128
131
|
'[class.nxe-disabled]': 'disabled()',
|
|
129
132
|
'(click)': 'handleClick($event)',
|
|
130
133
|
'(keydown.enter)': 'handleKeydown($event)',
|
|
131
134
|
'(keydown.space)': 'handleKeydown($event)',
|
|
132
|
-
}, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-button{display:inline-flex;box-sizing:border-box;cursor:pointer;max-width:100%;overflow:hidden;text-align:center;vertical-align:middle;-webkit-user-select:none;user-select:none;border:1px solid #ddd;border-radius:4px;background-color:#fff;color:#333;font-weight:400;line-height:1.35715}nxe-button:focus{outline:none}nxe-button .
|
|
135
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-button{display:inline-flex;box-sizing:border-box;cursor:pointer;max-width:100%;overflow:hidden;text-align:center;vertical-align:middle;-webkit-user-select:none;user-select:none;border:1px solid #ddd;border-radius:4px;background-color:#fff;color:#333;font-weight:400;line-height:1.35715}nxe-button:focus{outline:none}nxe-button .nxe-button-content{flex:1 1 auto;display:flex;align-items:center;justify-content:center;gap:var(--nxe-ui-button-gap, 0px);line-height:1.35715;padding:8px}nxe-button.nxe-button-has-text .nxe-button-content{padding-inline:12px}nxe-button.nxe-button-has-text .nxe-button-content>i.nxe-icon{margin-inline-start:0;margin-inline-end:calc(9px - var(--nxe-ui-button-gap, 0px))}nxe-button .nxe-button-text{line-height:1.2858;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nxe-button:hover{background-color:#f4f4f4}nxe-button:active{background-color:#c2c2c2}nxe-button.nxe-button-default{background-color:#337ab7;border-color:transparent;color:#fff}nxe-button.nxe-button-default:hover{background-color:#2d6ca3}nxe-button.nxe-button-default:active{background-color:#19405b}nxe-button.nxe-button-success{background-color:#5cb85c;border-color:transparent;color:#fff}nxe-button.nxe-button-success:hover{background-color:#46a046}nxe-button.nxe-button-success:active{background-color:#306e30}nxe-button.nxe-button-danger{background-color:#d9534f;border-color:transparent;color:#fff}nxe-button.nxe-button-danger:hover{background-color:#cd312c}nxe-button.nxe-button-danger:active{background-color:#932320}nxe-button[disabled]{opacity:.5;cursor:default}nxe-button.nxe-disabled{opacity:.5;cursor:default;pointer-events:none}\n"] }]
|
|
133
136
|
}], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], validationGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationGroup", required: false }] }], focusStateEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusStateEnabled", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], onClick: [{ type: i0.Output, args: ["onClick"] }] } });
|
|
134
137
|
|
|
135
138
|
/**
|
|
@@ -139,6 +142,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
139
142
|
* `[(ngModel)]`, one-way `[value]`, and `[readOnly]`. Like DevExtreme's default
|
|
140
143
|
* (`valueChangeEvent='change'`), the value commits on **blur** — not on every keystroke.
|
|
141
144
|
*
|
|
145
|
+
* `showClearButton` (dx default `false`) adds dx's clear area after the input while the field
|
|
146
|
+
* holds text and is neither read-only nor disabled; it sets the value to `''`, dx's own empty
|
|
147
|
+
* value for a text box, and focuses the input.
|
|
148
|
+
*
|
|
142
149
|
* It provides {@link NXE_VALIDATION_TARGET} so a projected `nxe-validator` can read its value
|
|
143
150
|
* and push back the invalid message, which renders as the red `.nxe-invalid-message` bubble.
|
|
144
151
|
*/
|
|
@@ -152,38 +159,99 @@ class NxeTextBoxComponent extends NxeFormControlBase {
|
|
|
152
159
|
hoverStateEnabledInput = input(undefined, { ...(ngDevMode ? { debugName: "hoverStateEnabledInput" } : /* istanbul ignore next */ {}), alias: 'hoverStateEnabled', transform: nxeOptionalBoolean });
|
|
153
160
|
hoverStateEnabled = computed(() => this.hoverStateEnabledInput() ?? this.nxeDefaults.textBox?.hoverStateEnabled ?? false, /* @ts-ignore */
|
|
154
161
|
...(ngDevMode ? [{ debugName: "hoverStateEnabled" }] : /* istanbul ignore next */ []));
|
|
162
|
+
/** dx `showClearButton` — off by default, as in dx; `NXE_DEFAULT_OPTIONS.textBox` can turn it on app-wide. */
|
|
163
|
+
showClearButtonInput = input(undefined, { ...(ngDevMode ? { debugName: "showClearButtonInput" } : /* istanbul ignore next */ {}), alias: 'showClearButton', transform: nxeOptionalBoolean });
|
|
164
|
+
showClearButton = computed(() => this.showClearButtonInput() ?? this.nxeDefaults.textBox?.showClearButton ?? false, /* @ts-ignore */
|
|
165
|
+
...(ngDevMode ? [{ debugName: "showClearButton" }] : /* istanbul ignore next */ []));
|
|
155
166
|
focused = signal(false, /* @ts-ignore */
|
|
156
167
|
...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
|
|
157
168
|
displayValue = computed(() => this.value() ?? '', /* @ts-ignore */
|
|
158
169
|
...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
170
|
+
fieldRef = viewChild.required('field', /* @ts-ignore */
|
|
171
|
+
...(ngDevMode ? [{ debugName: "fieldRef" }] : /* istanbul ignore next */ []));
|
|
172
|
+
/**
|
|
173
|
+
* The text in the field right now, typed or not. dx shows the clear button by the field's
|
|
174
|
+
* emptiness (`.dx-texteditor-empty`), which follows every keystroke, not the committed value.
|
|
175
|
+
*/
|
|
176
|
+
fieldText = linkedSignal(() => this.displayValue(), /* @ts-ignore */
|
|
177
|
+
...(ngDevMode ? [{ debugName: "fieldText" }] : /* istanbul ignore next */ []));
|
|
178
|
+
clearButtonVisible = computed(() => this.showClearButton() && !this.readOnly() && !this.disabled() && this.fieldText() !== '', /* @ts-ignore */
|
|
179
|
+
...(ngDevMode ? [{ debugName: "clearButtonVisible" }] : /* istanbul ignore next */ []));
|
|
180
|
+
/** dx `valueChangeEvent: 'input'` — the search-as-you-type case. */
|
|
181
|
+
onTypedInput(event) {
|
|
182
|
+
const text = event.target.value;
|
|
183
|
+
this.fieldText.set(text);
|
|
184
|
+
this.commitOn('input', text, event);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* dx `_clearValueHandler`: value back to `''`, then focus on the input. The field is emptied by
|
|
188
|
+
* hand as well — typed-but-uncommitted text over an already-empty value would otherwise survive,
|
|
189
|
+
* because the `[value]` binding has not changed.
|
|
190
|
+
*/
|
|
191
|
+
onClear(event) {
|
|
192
|
+
const field = this.fieldRef().nativeElement;
|
|
193
|
+
this.commitValue('', event);
|
|
194
|
+
field.value = '';
|
|
195
|
+
this.fieldText.set('');
|
|
196
|
+
if (!this.focused()) {
|
|
197
|
+
field.focus();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
onTypedKeyup(event) {
|
|
201
|
+
this.commitOn('keyup', event.target.value, event);
|
|
202
|
+
}
|
|
159
203
|
onBlur(event) {
|
|
204
|
+
// Blur commits whatever the mode: a value typed and left must not be discarded because
|
|
205
|
+
// the configured event never fired.
|
|
160
206
|
this.commitValue(event.target.value, event);
|
|
161
207
|
this.focused.set(false);
|
|
162
208
|
this.markAsTouched();
|
|
163
209
|
}
|
|
164
210
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeTextBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
165
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeTextBoxComponent, isStandalone: true, selector: "nxe-text-box", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hoverStateEnabledInput: { classPropertyName: "hoverStateEnabledInput", publicName: "hoverStateEnabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()" }, classAttribute: "nxe-widget nxe-editor nxe-textbox" }, providers: [
|
|
211
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeTextBoxComponent, isStandalone: true, selector: "nxe-text-box", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, placeholderInput: { classPropertyName: "placeholderInput", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hoverStateEnabledInput: { classPropertyName: "hoverStateEnabledInput", publicName: "hoverStateEnabled", isSignal: true, isRequired: false, transformFunction: null }, showClearButtonInput: { classPropertyName: "showClearButtonInput", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()" }, classAttribute: "nxe-widget nxe-editor nxe-textbox" }, providers: [
|
|
166
212
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeTextBoxComponent), multi: true },
|
|
167
213
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeTextBoxComponent) },
|
|
168
|
-
], usesInheritance: true, ngImport: i0, template: `
|
|
169
|
-
<div class="nxe-editor-container">
|
|
170
|
-
<input
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
[
|
|
174
|
-
[
|
|
175
|
-
[
|
|
176
|
-
[attr.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
214
|
+
], viewQueries: [{ propertyName: "fieldRef", first: true, predicate: ["field"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
215
|
+
<div class="nxe-editor-container">
|
|
216
|
+
<input
|
|
217
|
+
#field
|
|
218
|
+
class="nxe-editor-input nxe-textbox-input"
|
|
219
|
+
[attr.tabindex]="tabIndex()"
|
|
220
|
+
[id]="controlId()"
|
|
221
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
222
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
223
|
+
[attr.aria-invalid]="validationError() ? true : null"
|
|
224
|
+
[attr.aria-required]="required() ? true : null"
|
|
225
|
+
[type]="mode()"
|
|
226
|
+
[value]="displayValue()"
|
|
227
|
+
[readOnly]="readOnly()"
|
|
228
|
+
[disabled]="disabled()"
|
|
229
|
+
[attr.placeholder]="placeholder() || null"
|
|
230
|
+
autocomplete="off"
|
|
231
|
+
(input)="onTypedInput($event)"
|
|
232
|
+
(keyup)="onTypedKeyup($event)"
|
|
233
|
+
(blur)="onBlur($event)"
|
|
234
|
+
(focus)="focused.set(true)" />
|
|
235
|
+
@if (clearButtonVisible()) {
|
|
236
|
+
<span
|
|
237
|
+
class="nxe-clear-button-area"
|
|
238
|
+
(mousedown)="$event.preventDefault()"
|
|
239
|
+
(click)="onClear($event)"
|
|
240
|
+
aria-hidden="true">
|
|
241
|
+
<!-- A Ø16 disc with a 2px × cut out (the dropdown editors' clear glyph). -->
|
|
242
|
+
<svg viewBox="0 0 18 18" focusable="false">
|
|
243
|
+
<path fill-rule="evenodd" transform="rotate(45 9 9)"
|
|
244
|
+
d="M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z" />
|
|
245
|
+
</svg>
|
|
246
|
+
</span>
|
|
247
|
+
}
|
|
248
|
+
</div>
|
|
249
|
+
<ng-content />
|
|
250
|
+
@if (validationError(); as error) {
|
|
251
|
+
@if (focused()) {
|
|
252
|
+
<div class="nxe-invalid-message">{{ error }}</div>
|
|
253
|
+
}
|
|
254
|
+
}
|
|
187
255
|
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
188
256
|
}
|
|
189
257
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeTextBoxComponent, decorators: [{
|
|
@@ -191,25 +259,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
191
259
|
args: [{
|
|
192
260
|
selector: 'nxe-text-box',
|
|
193
261
|
standalone: true,
|
|
194
|
-
template: `
|
|
195
|
-
<div class="nxe-editor-container">
|
|
196
|
-
<input
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
[
|
|
200
|
-
[
|
|
201
|
-
[
|
|
202
|
-
[attr.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
262
|
+
template: `
|
|
263
|
+
<div class="nxe-editor-container">
|
|
264
|
+
<input
|
|
265
|
+
#field
|
|
266
|
+
class="nxe-editor-input nxe-textbox-input"
|
|
267
|
+
[attr.tabindex]="tabIndex()"
|
|
268
|
+
[id]="controlId()"
|
|
269
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
270
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
271
|
+
[attr.aria-invalid]="validationError() ? true : null"
|
|
272
|
+
[attr.aria-required]="required() ? true : null"
|
|
273
|
+
[type]="mode()"
|
|
274
|
+
[value]="displayValue()"
|
|
275
|
+
[readOnly]="readOnly()"
|
|
276
|
+
[disabled]="disabled()"
|
|
277
|
+
[attr.placeholder]="placeholder() || null"
|
|
278
|
+
autocomplete="off"
|
|
279
|
+
(input)="onTypedInput($event)"
|
|
280
|
+
(keyup)="onTypedKeyup($event)"
|
|
281
|
+
(blur)="onBlur($event)"
|
|
282
|
+
(focus)="focused.set(true)" />
|
|
283
|
+
@if (clearButtonVisible()) {
|
|
284
|
+
<span
|
|
285
|
+
class="nxe-clear-button-area"
|
|
286
|
+
(mousedown)="$event.preventDefault()"
|
|
287
|
+
(click)="onClear($event)"
|
|
288
|
+
aria-hidden="true">
|
|
289
|
+
<!-- A Ø16 disc with a 2px × cut out (the dropdown editors' clear glyph). -->
|
|
290
|
+
<svg viewBox="0 0 18 18" focusable="false">
|
|
291
|
+
<path fill-rule="evenodd" transform="rotate(45 9 9)"
|
|
292
|
+
d="M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z" />
|
|
293
|
+
</svg>
|
|
294
|
+
</span>
|
|
295
|
+
}
|
|
296
|
+
</div>
|
|
297
|
+
<ng-content />
|
|
298
|
+
@if (validationError(); as error) {
|
|
299
|
+
@if (focused()) {
|
|
300
|
+
<div class="nxe-invalid-message">{{ error }}</div>
|
|
301
|
+
}
|
|
302
|
+
}
|
|
213
303
|
`,
|
|
214
304
|
host: {
|
|
215
305
|
class: 'nxe-widget nxe-editor nxe-textbox',
|
|
@@ -223,7 +313,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
223
313
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
224
314
|
encapsulation: ViewEncapsulation.None,
|
|
225
315
|
}]
|
|
226
|
-
}], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hoverStateEnabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverStateEnabled", required: false }] }] } });
|
|
316
|
+
}], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hoverStateEnabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverStateEnabled", required: false }] }], showClearButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], fieldRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }] } });
|
|
227
317
|
|
|
228
318
|
/**
|
|
229
319
|
* `nxe-text-area` — drop-in replacement for DevExtreme `dx-text-area`.
|
|
@@ -244,7 +334,16 @@ class NxeTextAreaComponent extends NxeFormControlBase {
|
|
|
244
334
|
...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
|
|
245
335
|
displayValue = computed(() => this.value() ?? '', /* @ts-ignore */
|
|
246
336
|
...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
337
|
+
/** dx `valueChangeEvent: 'input'` — the search-as-you-type case. */
|
|
338
|
+
onTypedInput(event) {
|
|
339
|
+
this.commitOn('input', event.target.value, event);
|
|
340
|
+
}
|
|
341
|
+
onTypedKeyup(event) {
|
|
342
|
+
this.commitOn('keyup', event.target.value, event);
|
|
343
|
+
}
|
|
247
344
|
onBlur(event) {
|
|
345
|
+
// Blur commits whatever the mode: a value typed and left must not be discarded because
|
|
346
|
+
// the configured event never fired.
|
|
248
347
|
this.commitValue(event.target.value, event);
|
|
249
348
|
this.focused.set(false);
|
|
250
349
|
this.markAsTouched();
|
|
@@ -257,11 +356,19 @@ class NxeTextAreaComponent extends NxeFormControlBase {
|
|
|
257
356
|
<div class="nxe-editor-container">
|
|
258
357
|
<textarea
|
|
259
358
|
class="nxe-editor-input nxe-textarea-input"
|
|
359
|
+
[attr.tabindex]="tabIndex()"
|
|
360
|
+
[id]="controlId()"
|
|
361
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
362
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
363
|
+
[attr.aria-invalid]="validationError() ? true : null"
|
|
364
|
+
[attr.aria-required]="required() ? true : null"
|
|
260
365
|
[value]="displayValue()"
|
|
261
366
|
[readOnly]="readOnly()"
|
|
262
367
|
[disabled]="disabled()"
|
|
263
368
|
[attr.placeholder]="placeholder() || null"
|
|
264
369
|
[style.height.px]="height() || null"
|
|
370
|
+
(input)="onTypedInput($event)"
|
|
371
|
+
(keyup)="onTypedKeyup($event)"
|
|
265
372
|
(blur)="onBlur($event)"
|
|
266
373
|
(focus)="focused.set(true)"></textarea>
|
|
267
374
|
</div>
|
|
@@ -279,11 +386,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
279
386
|
<div class="nxe-editor-container">
|
|
280
387
|
<textarea
|
|
281
388
|
class="nxe-editor-input nxe-textarea-input"
|
|
389
|
+
[attr.tabindex]="tabIndex()"
|
|
390
|
+
[id]="controlId()"
|
|
391
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
392
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
393
|
+
[attr.aria-invalid]="validationError() ? true : null"
|
|
394
|
+
[attr.aria-required]="required() ? true : null"
|
|
282
395
|
[value]="displayValue()"
|
|
283
396
|
[readOnly]="readOnly()"
|
|
284
397
|
[disabled]="disabled()"
|
|
285
398
|
[attr.placeholder]="placeholder() || null"
|
|
286
399
|
[style.height.px]="height() || null"
|
|
400
|
+
(input)="onTypedInput($event)"
|
|
401
|
+
(keyup)="onTypedKeyup($event)"
|
|
287
402
|
(blur)="onBlur($event)"
|
|
288
403
|
(focus)="focused.set(true)"></textarea>
|
|
289
404
|
</div>
|
|
@@ -306,16 +421,43 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
306
421
|
/**
|
|
307
422
|
* `nxe-check-box` — drop-in replacement for DevExtreme `dx-check-box`.
|
|
308
423
|
*
|
|
309
|
-
* A
|
|
310
|
-
*
|
|
311
|
-
* `
|
|
312
|
-
*
|
|
424
|
+
* A signal-CVA editor (extends {@link NxeFormControlBase}) over `true` / `false` / `null`. As in
|
|
425
|
+
* dx, a `null` value is the indeterminate state: the box shows a 12px square and reports
|
|
426
|
+
* `aria-checked="mixed"`. That is what a `new FormControl()` (or a `reset()`) looks like, and what
|
|
427
|
+
* `[value]="null"` looks like; an unbound box starts unchecked, like dx's default `false`. A click
|
|
428
|
+
* or Space always lands on `true` or `false` — there is no `enableThreeStateBehavior` cycling back
|
|
429
|
+
* to `null`.
|
|
430
|
+
*
|
|
431
|
+
* Supports `formControlName`/`[(ngModel)]`/`[(value)]`/`[value]`, `[readOnly]`, `[disabled]`, an
|
|
432
|
+
* inline `text` label, `(onValueChanged)` (`{value}`) and `(valueChange)` (raw value). A read-only
|
|
433
|
+
* box stays focusable (tabindex 0) and still shows hover and focus, as in dx; it just never
|
|
434
|
+
* toggles. Provides {@link NXE_VALIDATION_TARGET} for a projected `nxe-validator` (a `required`
|
|
313
435
|
* rule is invalid while unchecked, matching DevExtreme's RequiredRule treating `false` as empty).
|
|
314
436
|
*/
|
|
315
437
|
class NxeCheckBoxComponent extends NxeFormControlBase {
|
|
316
438
|
/** Inline label rendered next to the box. */
|
|
317
439
|
text = input(/* @ts-ignore */
|
|
318
440
|
...(ngDevMode ? [undefined, { debugName: "text" }] : /* istanbul ignore next */ []));
|
|
441
|
+
/**
|
|
442
|
+
* Whether a value has been handed in at all — by the forms API or a `[value]` binding.
|
|
443
|
+
*
|
|
444
|
+
* The base class starts `value` at `null`, which is also the indeterminate value, so `null`
|
|
445
|
+
* alone cannot tell "given null" from "given nothing". dx can: its unset value is `false`.
|
|
446
|
+
*/
|
|
447
|
+
valueProvided = signal(false, /* @ts-ignore */
|
|
448
|
+
...(ngDevMode ? [{ debugName: "valueProvided" }] : /* istanbul ignore next */ []));
|
|
449
|
+
/** dx `.dx-checkbox-indeterminate`: the value was given, and it is `null`. */
|
|
450
|
+
indeterminate = computed(() => this.valueProvided() && this.value() === null, /* @ts-ignore */
|
|
451
|
+
...(ngDevMode ? [{ debugName: "indeterminate" }] : /* istanbul ignore next */ []));
|
|
452
|
+
writeValue(value) {
|
|
453
|
+
super.writeValue(value);
|
|
454
|
+
this.valueProvided.set(true);
|
|
455
|
+
}
|
|
456
|
+
ngOnChanges(changes) {
|
|
457
|
+
if (changes['value']) {
|
|
458
|
+
this.valueProvided.set(true);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
319
461
|
toggle(event) {
|
|
320
462
|
if (this.disabled() || this.readOnly()) {
|
|
321
463
|
return;
|
|
@@ -328,10 +470,10 @@ class NxeCheckBoxComponent extends NxeFormControlBase {
|
|
|
328
470
|
this.toggle(event);
|
|
329
471
|
}
|
|
330
472
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeCheckBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
331
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeCheckBoxComponent, isStandalone: true, selector: "nxe-check-box", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "checkbox" }, listeners: { "click": "toggle($event)", "keydown.space": "onSpace($event)", "blur": "markAsTouched()" }, properties: { "attr.aria-checked": "!!value()", "attr.aria-disabled": "disabled() ? true : null", "attr.aria-readonly": "readOnly() ? true : null", "attr.
|
|
473
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeCheckBoxComponent, isStandalone: true, selector: "nxe-check-box", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "checkbox" }, listeners: { "click": "toggle($event)", "keydown.space": "onSpace($event)", "blur": "markAsTouched()" }, properties: { "attr.aria-checked": "indeterminate() ? 'mixed' : !!value()", "attr.aria-disabled": "disabled() ? true : null", "attr.aria-readonly": "readOnly() ? true : null", "attr.aria-invalid": "validationError() ? true : null", "attr.aria-required": "required() ? true : null", "attr.id": "inputId() ? controlId() : null", "attr.aria-label": "ariaLabel() || null", "attr.aria-labelledby": "ariaLabelledBy() || null", "attr.tabindex": "disabled() ? null : 0", "class.nxe-checkbox-checked": "!!value()", "class.nxe-checkbox-indeterminate": "indeterminate()", "class.nxe-disabled": "disabled()", "class.nxe-readonly": "readOnly()", "class.nxe-invalid": "!!validationError()" }, classAttribute: "nxe-widget nxe-checkbox" }, providers: [
|
|
332
474
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeCheckBoxComponent), multi: true },
|
|
333
475
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeCheckBoxComponent) },
|
|
334
|
-
], usesInheritance: true, ngImport: i0, template: `
|
|
476
|
+
], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
|
|
335
477
|
<span class="nxe-checkbox-container">
|
|
336
478
|
<span class="nxe-checkbox-icon" aria-hidden="true"></span>
|
|
337
479
|
@if (text()) {
|
|
@@ -339,7 +481,7 @@ class NxeCheckBoxComponent extends NxeFormControlBase {
|
|
|
339
481
|
}
|
|
340
482
|
</span>
|
|
341
483
|
<ng-content />
|
|
342
|
-
`, isInline: true, styles: ["nxe-check-box{display:inline-flex;align-items:center;box-sizing:border-box;cursor:pointer;vertical-align:middle;-webkit-user-select:none;user-select:none;line-height:normal}nxe-check-box:focus{outline:none}nxe-check-box .nxe-checkbox-container{display:inline-flex;align-items:center;max-width:100%;overflow:hidden}nxe-check-box .nxe-checkbox-icon{box-sizing:border-box;position:relative;flex-shrink:0;width:22px;height:22px;border:1px solid #ddd;border-radius:2px;background-color:#fff
|
|
484
|
+
`, isInline: true, styles: ["nxe-check-box{display:inline-flex;align-items:center;box-sizing:border-box;cursor:pointer;vertical-align:middle;-webkit-user-select:none;user-select:none;line-height:normal}nxe-check-box:focus{outline:none}nxe-check-box .nxe-checkbox-container{display:inline-flex;align-items:center;max-width:100%;overflow:hidden}nxe-check-box .nxe-checkbox-icon{box-sizing:border-box;position:relative;flex-shrink:0;width:22px;height:22px;border:1px solid #ddd;border-radius:2px;background-color:#fff}nxe-check-box .nxe-checkbox-text{padding-inline-start:5px;white-space:pre-wrap;word-wrap:break-word;line-height:normal}nxe-check-box.nxe-checkbox-checked .nxe-checkbox-icon:after{content:\"\";position:absolute;box-sizing:border-box;top:5px;inset-inline-start:2.5px;width:15px;height:11px;background-color:var(--nxe-ui-accent, #337ab7);clip-path:polygon(0 5.586px,5.414px 11px,15px 1.414px,13.586px 0,5.414px 8.172px,1.414px 4.172px)}@media(forced-colors:active){nxe-check-box.nxe-checkbox-checked .nxe-checkbox-icon:after{forced-color-adjust:none;background-color:CanvasText}}nxe-check-box.nxe-checkbox-indeterminate .nxe-checkbox-icon:after{content:\"\";position:absolute;box-sizing:border-box;top:50%;inset-inline-start:50%;width:12px;height:12px;margin-top:-6px;margin-inline-start:-6px;border-radius:2px;background-color:var(--nxe-ui-accent, #337ab7)}@media(forced-colors:active){nxe-check-box.nxe-checkbox-indeterminate .nxe-checkbox-icon:after{forced-color-adjust:none;background-color:CanvasText}}nxe-check-box.nxe-readonly{cursor:default}nxe-check-box.nxe-readonly .nxe-checkbox-icon{border-color:#f4f4f4;background-color:#fff}nxe-check-box:not(.nxe-disabled):hover .nxe-checkbox-icon{border-color:var(--nxe-ui-checkbox-hover-border, #265a87)}nxe-check-box:not(.nxe-disabled):focus .nxe-checkbox-icon{border-color:var(--nxe-ui-accent, #337ab7)}nxe-check-box:not(.nxe-disabled):active .nxe-checkbox-icon{background-color:#60606033}nxe-check-box.nxe-disabled{cursor:default}nxe-check-box.nxe-disabled .nxe-checkbox-icon,nxe-check-box.nxe-disabled .nxe-checkbox-text{opacity:.4}nxe-check-box.nxe-invalid .nxe-checkbox-icon,nxe-check-box.nxe-invalid:hover .nxe-checkbox-icon{border-color:#d9534f66}nxe-check-box.nxe-invalid:focus .nxe-checkbox-icon{border-color:#d9534f}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
343
485
|
}
|
|
344
486
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeCheckBoxComponent, decorators: [{
|
|
345
487
|
type: Component,
|
|
@@ -354,11 +496,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
354
496
|
`, host: {
|
|
355
497
|
class: 'nxe-widget nxe-checkbox',
|
|
356
498
|
role: 'checkbox',
|
|
357
|
-
'[attr.aria-checked]': '!!value()
|
|
499
|
+
'[attr.aria-checked]': "indeterminate() ? 'mixed' : !!value()",
|
|
358
500
|
'[attr.aria-disabled]': 'disabled() ? true : null',
|
|
359
501
|
'[attr.aria-readonly]': 'readOnly() ? true : null',
|
|
360
|
-
'[attr.
|
|
502
|
+
'[attr.aria-invalid]': 'validationError() ? true : null',
|
|
503
|
+
'[attr.aria-required]': 'required() ? true : null',
|
|
504
|
+
// The host IS the control here, so the id and name belong on it rather than on a child.
|
|
505
|
+
'[attr.id]': 'inputId() ? controlId() : null',
|
|
506
|
+
'[attr.aria-label]': 'ariaLabel() || null',
|
|
507
|
+
'[attr.aria-labelledby]': 'ariaLabelledBy() || null',
|
|
508
|
+
// dx keeps a read-only box in the tab order (tabindex 0); only disabled takes it out.
|
|
509
|
+
'[attr.tabindex]': 'disabled() ? null : 0',
|
|
361
510
|
'[class.nxe-checkbox-checked]': '!!value()',
|
|
511
|
+
'[class.nxe-checkbox-indeterminate]': 'indeterminate()',
|
|
362
512
|
'[class.nxe-disabled]': 'disabled()',
|
|
363
513
|
'[class.nxe-readonly]': 'readOnly()',
|
|
364
514
|
'[class.nxe-invalid]': '!!validationError()',
|
|
@@ -368,7 +518,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
368
518
|
}, providers: [
|
|
369
519
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeCheckBoxComponent), multi: true },
|
|
370
520
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeCheckBoxComponent) },
|
|
371
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-check-box{display:inline-flex;align-items:center;box-sizing:border-box;cursor:pointer;vertical-align:middle;-webkit-user-select:none;user-select:none;line-height:normal}nxe-check-box:focus{outline:none}nxe-check-box .nxe-checkbox-container{display:inline-flex;align-items:center;max-width:100%;overflow:hidden}nxe-check-box .nxe-checkbox-icon{box-sizing:border-box;position:relative;flex-shrink:0;width:22px;height:22px;border:1px solid #ddd;border-radius:2px;background-color:#fff
|
|
521
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-check-box{display:inline-flex;align-items:center;box-sizing:border-box;cursor:pointer;vertical-align:middle;-webkit-user-select:none;user-select:none;line-height:normal}nxe-check-box:focus{outline:none}nxe-check-box .nxe-checkbox-container{display:inline-flex;align-items:center;max-width:100%;overflow:hidden}nxe-check-box .nxe-checkbox-icon{box-sizing:border-box;position:relative;flex-shrink:0;width:22px;height:22px;border:1px solid #ddd;border-radius:2px;background-color:#fff}nxe-check-box .nxe-checkbox-text{padding-inline-start:5px;white-space:pre-wrap;word-wrap:break-word;line-height:normal}nxe-check-box.nxe-checkbox-checked .nxe-checkbox-icon:after{content:\"\";position:absolute;box-sizing:border-box;top:5px;inset-inline-start:2.5px;width:15px;height:11px;background-color:var(--nxe-ui-accent, #337ab7);clip-path:polygon(0 5.586px,5.414px 11px,15px 1.414px,13.586px 0,5.414px 8.172px,1.414px 4.172px)}@media(forced-colors:active){nxe-check-box.nxe-checkbox-checked .nxe-checkbox-icon:after{forced-color-adjust:none;background-color:CanvasText}}nxe-check-box.nxe-checkbox-indeterminate .nxe-checkbox-icon:after{content:\"\";position:absolute;box-sizing:border-box;top:50%;inset-inline-start:50%;width:12px;height:12px;margin-top:-6px;margin-inline-start:-6px;border-radius:2px;background-color:var(--nxe-ui-accent, #337ab7)}@media(forced-colors:active){nxe-check-box.nxe-checkbox-indeterminate .nxe-checkbox-icon:after{forced-color-adjust:none;background-color:CanvasText}}nxe-check-box.nxe-readonly{cursor:default}nxe-check-box.nxe-readonly .nxe-checkbox-icon{border-color:#f4f4f4;background-color:#fff}nxe-check-box:not(.nxe-disabled):hover .nxe-checkbox-icon{border-color:var(--nxe-ui-checkbox-hover-border, #265a87)}nxe-check-box:not(.nxe-disabled):focus .nxe-checkbox-icon{border-color:var(--nxe-ui-accent, #337ab7)}nxe-check-box:not(.nxe-disabled):active .nxe-checkbox-icon{background-color:#60606033}nxe-check-box.nxe-disabled{cursor:default}nxe-check-box.nxe-disabled .nxe-checkbox-icon,nxe-check-box.nxe-disabled .nxe-checkbox-text{opacity:.4}nxe-check-box.nxe-invalid .nxe-checkbox-icon,nxe-check-box.nxe-invalid:hover .nxe-checkbox-icon{border-color:#d9534f66}nxe-check-box.nxe-invalid:focus .nxe-checkbox-icon{border-color:#d9534f}\n"] }]
|
|
372
522
|
}], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }] } });
|
|
373
523
|
|
|
374
524
|
/** Coerce a static (`min="1"`) or bound (`[min]="0"`) attribute to a number, or undefined. */
|
|
@@ -389,6 +539,10 @@ function toNumber(value) {
|
|
|
389
539
|
*
|
|
390
540
|
* Supports `formControlName`/`[(ngModel)]`/`[(value)]`/`[value]`, `[readOnly]`, `[min]`/`[max]`,
|
|
391
541
|
* `format` (string LDML pattern), `(valueChange)` (numeric), and a projected `nxe-validator`.
|
|
542
|
+
*
|
|
543
|
+
* `showClearButton` (dx default `false`) adds dx's clear area after the input while the field
|
|
544
|
+
* holds text and is neither read-only nor disabled; it sets the value to `null`, as dx's
|
|
545
|
+
* `clear()` does for a number box, and focuses the input.
|
|
392
546
|
*/
|
|
393
547
|
class NxeNumberBoxComponent extends NxeFormControlBase {
|
|
394
548
|
/** LDML format pattern (e.g. `#,##0.00`); empty = raw number. */
|
|
@@ -397,10 +551,16 @@ class NxeNumberBoxComponent extends NxeFormControlBase {
|
|
|
397
551
|
...(ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []));
|
|
398
552
|
min = input(undefined, { ...(ngDevMode ? { debugName: "min" } : /* istanbul ignore next */ {}), transform: toNumber });
|
|
399
553
|
max = input(undefined, { ...(ngDevMode ? { debugName: "max" } : /* istanbul ignore next */ {}), transform: toNumber });
|
|
554
|
+
/** dx `showClearButton` — off by default, as in dx; `NXE_DEFAULT_OPTIONS.numberBox` can turn it on app-wide. */
|
|
555
|
+
showClearButtonInput = input(undefined, { ...(ngDevMode ? { debugName: "showClearButtonInput" } : /* istanbul ignore next */ {}), alias: 'showClearButton', transform: nxeOptionalBoolean });
|
|
556
|
+
showClearButton = computed(() => this.showClearButtonInput() ?? this.nxeDefaults.numberBox?.showClearButton ?? false, /* @ts-ignore */
|
|
557
|
+
...(ngDevMode ? [{ debugName: "showClearButton" }] : /* istanbul ignore next */ []));
|
|
400
558
|
focused = signal(false, /* @ts-ignore */
|
|
401
559
|
...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
|
|
402
560
|
parsedFormat = computed(() => parseNumberFormat(this.format()), /* @ts-ignore */
|
|
403
561
|
...(ngDevMode ? [{ debugName: "parsedFormat" }] : /* istanbul ignore next */ []));
|
|
562
|
+
fieldRef = viewChild.required('field', /* @ts-ignore */
|
|
563
|
+
...(ngDevMode ? [{ debugName: "fieldRef" }] : /* istanbul ignore next */ []));
|
|
404
564
|
/** Locale characters, configured once by the application. Defaults to en-US. */
|
|
405
565
|
separators = inject(NXE_NUMBER_SEPARATORS);
|
|
406
566
|
displayValue = computed(() => {
|
|
@@ -413,6 +573,27 @@ class NxeNumberBoxComponent extends NxeFormControlBase {
|
|
|
413
573
|
return formatNumber(value, this.parsedFormat(), this.separators);
|
|
414
574
|
}, /* @ts-ignore */
|
|
415
575
|
...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
576
|
+
/** The text in the field right now; dx shows the clear button by the field's emptiness. */
|
|
577
|
+
fieldText = linkedSignal(() => this.displayValue(), /* @ts-ignore */
|
|
578
|
+
...(ngDevMode ? [{ debugName: "fieldText" }] : /* istanbul ignore next */ []));
|
|
579
|
+
clearButtonVisible = computed(() => this.showClearButton() && !this.readOnly() && !this.disabled() && this.fieldText() !== '', /* @ts-ignore */
|
|
580
|
+
...(ngDevMode ? [{ debugName: "clearButtonVisible" }] : /* istanbul ignore next */ []));
|
|
581
|
+
onFieldInput(event) {
|
|
582
|
+
this.fieldText.set(event.target.value);
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* dx `_clearValueHandler`: value to `null`, then focus on the input. The field is emptied by hand
|
|
586
|
+
* too, for typed-but-uncommitted text over a value that was already `null`.
|
|
587
|
+
*/
|
|
588
|
+
onClear(event) {
|
|
589
|
+
const field = this.fieldRef().nativeElement;
|
|
590
|
+
this.commitValue(null, event);
|
|
591
|
+
field.value = '';
|
|
592
|
+
this.fieldText.set('');
|
|
593
|
+
if (!this.focused()) {
|
|
594
|
+
field.focus();
|
|
595
|
+
}
|
|
596
|
+
}
|
|
416
597
|
onBlur(event) {
|
|
417
598
|
let num = parseNumber(event.target.value, this.separators);
|
|
418
599
|
if (num != null) {
|
|
@@ -434,51 +615,93 @@ class NxeNumberBoxComponent extends NxeFormControlBase {
|
|
|
434
615
|
this.markAsTouched();
|
|
435
616
|
}
|
|
436
617
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeNumberBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
437
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeNumberBoxComponent, isStandalone: true, selector: "nxe-number-box", inputs: { formatInput: { classPropertyName: "formatInput", publicName: "format", 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 } }, host: { properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()" }, classAttribute: "nxe-widget nxe-editor nxe-numberbox" }, providers: [
|
|
618
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeNumberBoxComponent, isStandalone: true, selector: "nxe-number-box", inputs: { formatInput: { classPropertyName: "formatInput", publicName: "format", 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 }, showClearButtonInput: { classPropertyName: "showClearButtonInput", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()" }, classAttribute: "nxe-widget nxe-editor nxe-numberbox" }, providers: [
|
|
438
619
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeNumberBoxComponent), multi: true },
|
|
439
620
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeNumberBoxComponent) },
|
|
440
|
-
], usesInheritance: true, ngImport: i0, template: `
|
|
441
|
-
<div class="nxe-editor-container">
|
|
442
|
-
<input
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
[
|
|
447
|
-
[
|
|
448
|
-
[
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
621
|
+
], viewQueries: [{ propertyName: "fieldRef", first: true, predicate: ["field"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
622
|
+
<div class="nxe-editor-container">
|
|
623
|
+
<input
|
|
624
|
+
#field
|
|
625
|
+
class="nxe-editor-input nxe-numberbox-input"
|
|
626
|
+
[attr.tabindex]="tabIndex()"
|
|
627
|
+
[id]="controlId()"
|
|
628
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
629
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
630
|
+
[attr.aria-invalid]="validationError() ? true : null"
|
|
631
|
+
[attr.aria-required]="required() ? true : null"
|
|
632
|
+
type="text"
|
|
633
|
+
inputmode="decimal"
|
|
634
|
+
[value]="displayValue()"
|
|
635
|
+
[readOnly]="readOnly()"
|
|
636
|
+
[disabled]="disabled()"
|
|
637
|
+
autocomplete="off"
|
|
638
|
+
(input)="onFieldInput($event)"
|
|
639
|
+
(focus)="focused.set(true)"
|
|
640
|
+
(blur)="onBlur($event)" />
|
|
641
|
+
@if (clearButtonVisible()) {
|
|
642
|
+
<span
|
|
643
|
+
class="nxe-clear-button-area"
|
|
644
|
+
(mousedown)="$event.preventDefault()"
|
|
645
|
+
(click)="onClear($event)"
|
|
646
|
+
aria-hidden="true">
|
|
647
|
+
<!-- A Ø16 disc with a 2px × cut out (the dropdown editors' clear glyph). -->
|
|
648
|
+
<svg viewBox="0 0 18 18" focusable="false">
|
|
649
|
+
<path fill-rule="evenodd" transform="rotate(45 9 9)"
|
|
650
|
+
d="M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z" />
|
|
651
|
+
</svg>
|
|
652
|
+
</span>
|
|
653
|
+
}
|
|
654
|
+
</div>
|
|
655
|
+
<ng-content />
|
|
656
|
+
@if (validationError(); as error) {
|
|
657
|
+
@if (focused()) {
|
|
658
|
+
<div class="nxe-invalid-message">{{ error }}</div>
|
|
659
|
+
}
|
|
660
|
+
}
|
|
459
661
|
`, isInline: true, styles: ["nxe-number-box.text-right .nxe-numberbox-input{text-align:right}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
460
662
|
}
|
|
461
663
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeNumberBoxComponent, decorators: [{
|
|
462
664
|
type: Component,
|
|
463
|
-
args: [{ selector: 'nxe-number-box', standalone: true, template: `
|
|
464
|
-
<div class="nxe-editor-container">
|
|
465
|
-
<input
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
[
|
|
470
|
-
[
|
|
471
|
-
[
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
665
|
+
args: [{ selector: 'nxe-number-box', standalone: true, template: `
|
|
666
|
+
<div class="nxe-editor-container">
|
|
667
|
+
<input
|
|
668
|
+
#field
|
|
669
|
+
class="nxe-editor-input nxe-numberbox-input"
|
|
670
|
+
[attr.tabindex]="tabIndex()"
|
|
671
|
+
[id]="controlId()"
|
|
672
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
673
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
674
|
+
[attr.aria-invalid]="validationError() ? true : null"
|
|
675
|
+
[attr.aria-required]="required() ? true : null"
|
|
676
|
+
type="text"
|
|
677
|
+
inputmode="decimal"
|
|
678
|
+
[value]="displayValue()"
|
|
679
|
+
[readOnly]="readOnly()"
|
|
680
|
+
[disabled]="disabled()"
|
|
681
|
+
autocomplete="off"
|
|
682
|
+
(input)="onFieldInput($event)"
|
|
683
|
+
(focus)="focused.set(true)"
|
|
684
|
+
(blur)="onBlur($event)" />
|
|
685
|
+
@if (clearButtonVisible()) {
|
|
686
|
+
<span
|
|
687
|
+
class="nxe-clear-button-area"
|
|
688
|
+
(mousedown)="$event.preventDefault()"
|
|
689
|
+
(click)="onClear($event)"
|
|
690
|
+
aria-hidden="true">
|
|
691
|
+
<!-- A Ø16 disc with a 2px × cut out (the dropdown editors' clear glyph). -->
|
|
692
|
+
<svg viewBox="0 0 18 18" focusable="false">
|
|
693
|
+
<path fill-rule="evenodd" transform="rotate(45 9 9)"
|
|
694
|
+
d="M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z" />
|
|
695
|
+
</svg>
|
|
696
|
+
</span>
|
|
697
|
+
}
|
|
698
|
+
</div>
|
|
699
|
+
<ng-content />
|
|
700
|
+
@if (validationError(); as error) {
|
|
701
|
+
@if (focused()) {
|
|
702
|
+
<div class="nxe-invalid-message">{{ error }}</div>
|
|
703
|
+
}
|
|
704
|
+
}
|
|
482
705
|
`, host: {
|
|
483
706
|
class: 'nxe-widget nxe-editor nxe-numberbox',
|
|
484
707
|
'[class.nxe-focused]': 'focused()',
|
|
@@ -487,7 +710,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
487
710
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeNumberBoxComponent), multi: true },
|
|
488
711
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeNumberBoxComponent) },
|
|
489
712
|
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-number-box.text-right .nxe-numberbox-input{text-align:right}\n"] }]
|
|
490
|
-
}], propDecorators: { formatInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }] } });
|
|
713
|
+
}], propDecorators: { formatInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], showClearButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], fieldRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }] } });
|
|
491
714
|
|
|
492
715
|
/** Normalize a `[min]`/`[max]` binding (Date object or serialized string) to a DateTime. */
|
|
493
716
|
function toBoundDate(bound) {
|
|
@@ -508,6 +731,15 @@ function toBoundDate(bound) {
|
|
|
508
731
|
* typeable (parsed on blur per `displayFormat`) and opens a CDK-overlay calendar from the icon
|
|
509
732
|
* button. Built on Luxon. Default `displayFormat` is `dd-MMM-yyyy`. Hosts a projected
|
|
510
733
|
* `nxe-validator` via {@link NXE_VALIDATION_TARGET}.
|
|
734
|
+
*
|
|
735
|
+
* `showClearButton` (dx default `false`) adds dx's clear area between the input and the calendar
|
|
736
|
+
* button while the field holds text and is neither read-only nor disabled; it sets the value to
|
|
737
|
+
* `null` and focuses the input.
|
|
738
|
+
*
|
|
739
|
+
* The button and calendar glyphs are drawn in an 18-unit viewBox (1 unit = 1px) to the ink measured
|
|
740
|
+
* off dx's `event` (`date`), `eventall` (`datetime`) and `clock` (`time`) glyphs and its chevrons,
|
|
741
|
+
* each laid out from those metrics in rects, stroked rects and circles, and straight-edged polygons;
|
|
742
|
+
* the templates state each construction.
|
|
511
743
|
*/
|
|
512
744
|
class NxeDateBoxComponent extends NxeFormControlBase {
|
|
513
745
|
overlay = inject(Overlay);
|
|
@@ -529,6 +761,10 @@ class NxeDateBoxComponent extends NxeFormControlBase {
|
|
|
529
761
|
...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
|
|
530
762
|
max = input(null, /* @ts-ignore */
|
|
531
763
|
...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
|
|
764
|
+
/** dx `showClearButton` — off by default, as in dx; `NXE_DEFAULT_OPTIONS.dateBox` can turn it on app-wide. */
|
|
765
|
+
showClearButtonInput = input(undefined, { ...(ngDevMode ? { debugName: "showClearButtonInput" } : /* istanbul ignore next */ {}), alias: 'showClearButton', transform: nxeOptionalBoolean });
|
|
766
|
+
showClearButton = computed(() => this.showClearButtonInput() ?? this.nxeDefaults.dateBox?.showClearButton ?? false, /* @ts-ignore */
|
|
767
|
+
...(ngDevMode ? [{ debugName: "showClearButton" }] : /* istanbul ignore next */ []));
|
|
532
768
|
focused = signal(false, /* @ts-ignore */
|
|
533
769
|
...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
|
|
534
770
|
opened = signal(false, /* @ts-ignore */
|
|
@@ -562,6 +798,11 @@ class NxeDateBoxComponent extends NxeFormControlBase {
|
|
|
562
798
|
...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
|
|
563
799
|
displayValue = computed(() => formatDisplay(this.selected(), this.effectiveDisplayFormat()), /* @ts-ignore */
|
|
564
800
|
...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
801
|
+
/** The text in the field right now; dx shows the clear button by the field's emptiness. */
|
|
802
|
+
fieldText = linkedSignal(() => this.displayValue(), /* @ts-ignore */
|
|
803
|
+
...(ngDevMode ? [{ debugName: "fieldText" }] : /* istanbul ignore next */ []));
|
|
804
|
+
clearButtonVisible = computed(() => this.showClearButton() && !this.readOnly() && !this.disabled() && this.fieldText() !== '', /* @ts-ignore */
|
|
805
|
+
...(ngDevMode ? [{ debugName: "clearButtonVisible" }] : /* istanbul ignore next */ []));
|
|
565
806
|
weeks = computed(() => buildCalendarWeeks(this.viewMonth()), /* @ts-ignore */
|
|
566
807
|
...(ngDevMode ? [{ debugName: "weeks" }] : /* istanbul ignore next */ []));
|
|
567
808
|
/** Two-digit hour/minute for the popup's time strip; blank when nothing is selected. */
|
|
@@ -670,6 +911,21 @@ class NxeDateBoxComponent extends NxeFormControlBase {
|
|
|
670
911
|
}
|
|
671
912
|
this.opened() ? this.close() : this.open();
|
|
672
913
|
}
|
|
914
|
+
onFieldInput(event) {
|
|
915
|
+
this.fieldText.set(event.target.value);
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* dx `_clearValueHandler`: value to `null` (dx's `clear()` for a date box), then focus on the
|
|
919
|
+
* input. `syncField` repaints the field, so typed-but-uncommitted text over a value that was
|
|
920
|
+
* already `null` goes too.
|
|
921
|
+
*/
|
|
922
|
+
onClear(event) {
|
|
923
|
+
this.commitValue(null, event);
|
|
924
|
+
this.syncField();
|
|
925
|
+
if (!this.focused()) {
|
|
926
|
+
this.fieldRef().nativeElement.focus();
|
|
927
|
+
}
|
|
928
|
+
}
|
|
673
929
|
onFocus(event) {
|
|
674
930
|
this.textAtFocus = event.target.value;
|
|
675
931
|
this.focused.set(true);
|
|
@@ -721,6 +977,7 @@ class NxeDateBoxComponent extends NxeFormControlBase {
|
|
|
721
977
|
const element = this.fieldRef().nativeElement;
|
|
722
978
|
element.value = this.displayValue();
|
|
723
979
|
this.textAtFocus = element.value;
|
|
980
|
+
this.fieldText.set(element.value);
|
|
724
981
|
}
|
|
725
982
|
selectDay(day) {
|
|
726
983
|
if (this.isDisabledDay(day)) {
|
|
@@ -809,263 +1066,365 @@ class NxeDateBoxComponent extends NxeFormControlBase {
|
|
|
809
1066
|
this.overlayRef?.dispose();
|
|
810
1067
|
}
|
|
811
1068
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeDateBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
812
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeDateBoxComponent, isStandalone: true, selector: "nxe-date-box", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, displayFormat: { classPropertyName: "displayFormat", publicName: "displayFormat", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", 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 } }, host: { properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()" }, classAttribute: "nxe-widget nxe-editor nxe-datebox" }, providers: [
|
|
1069
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeDateBoxComponent, isStandalone: true, selector: "nxe-date-box", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, displayFormat: { classPropertyName: "displayFormat", publicName: "displayFormat", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", 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 }, showClearButtonInput: { classPropertyName: "showClearButtonInput", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.nxe-focused": "focused()", "class.nxe-invalid": "!!validationError()" }, classAttribute: "nxe-widget nxe-editor nxe-datebox" }, providers: [
|
|
813
1070
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeDateBoxComponent), multi: true },
|
|
814
1071
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeDateBoxComponent) },
|
|
815
|
-
], viewQueries: [{ propertyName: "calendarTemplate", first: true, predicate: ["calendarTemplate"], descendants: true, isSignal: true }, { propertyName: "fieldRef", first: true, predicate: ["field"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
816
|
-
<div class="nxe-editor-container">
|
|
817
|
-
<input
|
|
818
|
-
#field
|
|
819
|
-
class="nxe-editor-input nxe-datebox-input"
|
|
820
|
-
|
|
821
|
-
[
|
|
822
|
-
[
|
|
823
|
-
[
|
|
824
|
-
[attr.
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
<
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
<svg class="nxe-
|
|
869
|
-
<
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
(
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1072
|
+
], viewQueries: [{ propertyName: "calendarTemplate", first: true, predicate: ["calendarTemplate"], descendants: true, isSignal: true }, { propertyName: "fieldRef", first: true, predicate: ["field"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
1073
|
+
<div class="nxe-editor-container">
|
|
1074
|
+
<input
|
|
1075
|
+
#field
|
|
1076
|
+
class="nxe-editor-input nxe-datebox-input"
|
|
1077
|
+
[attr.tabindex]="tabIndex()"
|
|
1078
|
+
[id]="controlId()"
|
|
1079
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
1080
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
1081
|
+
[attr.aria-invalid]="validationError() ? true : null"
|
|
1082
|
+
[attr.aria-required]="required() ? true : null"
|
|
1083
|
+
type="text"
|
|
1084
|
+
[value]="displayValue()"
|
|
1085
|
+
[readOnly]="readOnly()"
|
|
1086
|
+
[disabled]="disabled()"
|
|
1087
|
+
[attr.placeholder]="effectivePlaceholder() || null"
|
|
1088
|
+
autocomplete="off"
|
|
1089
|
+
(input)="onFieldInput($event)"
|
|
1090
|
+
(focus)="onFocus($event)"
|
|
1091
|
+
(blur)="onBlur($event)" />
|
|
1092
|
+
@if (clearButtonVisible()) {
|
|
1093
|
+
<span
|
|
1094
|
+
class="nxe-clear-button-area"
|
|
1095
|
+
(mousedown)="$event.preventDefault()"
|
|
1096
|
+
(click)="onClear($event)"
|
|
1097
|
+
aria-hidden="true">
|
|
1098
|
+
<!-- A Ø16 disc with a 2px × cut out (the dropdown editors' clear glyph). -->
|
|
1099
|
+
<svg viewBox="0 0 18 18" focusable="false">
|
|
1100
|
+
<path fill-rule="evenodd" transform="rotate(45 9 9)"
|
|
1101
|
+
d="M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z" />
|
|
1102
|
+
</svg>
|
|
1103
|
+
</span>
|
|
1104
|
+
}
|
|
1105
|
+
@if (!readOnly()) {
|
|
1106
|
+
<span
|
|
1107
|
+
class="nxe-datebox-button"
|
|
1108
|
+
[class.nxe-datebox-open]="opened()"
|
|
1109
|
+
(mousedown)="onButtonMousedown($event)"
|
|
1110
|
+
aria-hidden="true">
|
|
1111
|
+
@switch (type()) {
|
|
1112
|
+
@case ('time') {
|
|
1113
|
+
<!-- dx clock, a 16x16 ink box round the box centre: a 2px ring (an r 7
|
|
1114
|
+
circle stroked 2px), a 2x4 hand straight up from the centre, a 1.5x4
|
|
1115
|
+
hand turned 45° down-right, and a Ø2 hub where they meet. -->
|
|
1116
|
+
<svg class="nxe-datebox-icon nxe-datebox-icon-time" viewBox="0 0 18 18" focusable="false">
|
|
1117
|
+
<circle cx="9" cy="9" r="7" fill="none" stroke="currentColor" stroke-width="2" />
|
|
1118
|
+
<rect x="8" y="5" width="2" height="4" />
|
|
1119
|
+
<rect x="9" y="8.25" width="4" height="1.5" transform="rotate(45 9 9)" />
|
|
1120
|
+
<circle cx="9" cy="9" r="1" />
|
|
1121
|
+
</svg>
|
|
1122
|
+
}
|
|
1123
|
+
@case ('datetime') {
|
|
1124
|
+
<!-- dx eventall: the calendar page below, without its day marker. -->
|
|
1125
|
+
<svg class="nxe-datebox-icon nxe-datebox-icon-datetime" viewBox="0 0 18 18" focusable="false">
|
|
1126
|
+
<rect x="3" y="3" width="12" height="12" rx="1" fill="none" stroke="currentColor" stroke-width="2" />
|
|
1127
|
+
<rect x="3" y="3" width="12" height="3" />
|
|
1128
|
+
<rect x="4" y="1" width="2" height="1.5" />
|
|
1129
|
+
<rect x="12" y="1" width="2" height="1.5" />
|
|
1130
|
+
</svg>
|
|
1131
|
+
}
|
|
1132
|
+
@default {
|
|
1133
|
+
<!-- dx event, a 14x15 ink box from 1px below the top of the 18px box
|
|
1134
|
+
(where dx's glyph renders): the page is a 12x12 rect with 1px corners
|
|
1135
|
+
stroked 2px, so 14x14 with 2px corners outside and square inside; a
|
|
1136
|
+
12x3 bar under its top wall makes the 4px header band; two 2x1.5
|
|
1137
|
+
binder tabs stand 1px proud of it; a 4x4 day marker at (9, 9). -->
|
|
1138
|
+
<svg class="nxe-datebox-icon nxe-datebox-icon-date" viewBox="0 0 18 18" focusable="false">
|
|
1139
|
+
<rect x="3" y="3" width="12" height="12" rx="1" fill="none" stroke="currentColor" stroke-width="2" />
|
|
1140
|
+
<rect x="3" y="3" width="12" height="3" />
|
|
1141
|
+
<rect x="4" y="1" width="2" height="1.5" />
|
|
1142
|
+
<rect x="12" y="1" width="2" height="1.5" />
|
|
1143
|
+
<rect x="9" y="9" width="4" height="4" />
|
|
1144
|
+
</svg>
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
</span>
|
|
1148
|
+
}
|
|
1149
|
+
</div>
|
|
1150
|
+
<ng-content />
|
|
1151
|
+
@if (validationError(); as error) {
|
|
1152
|
+
@if (focused()) {
|
|
1153
|
+
<div class="nxe-invalid-message">{{ error }}</div>
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
<ng-template #calendarTemplate>
|
|
1158
|
+
<div class="nxe-calendar" (mousedown)="$event.preventDefault()">
|
|
1159
|
+
@if (type() !== 'time') {
|
|
1160
|
+
<div class="nxe-calendar-navigator">
|
|
1161
|
+
<button type="button" class="nxe-calendar-nav" (click)="navigate(-1)">
|
|
1162
|
+
<!-- dx chevronleft (8x14 ink, centred in its 18px box): two 45° arms
|
|
1163
|
+
whose outer edges run 7px out and 7px up and down from the point,
|
|
1164
|
+
their ends cut square 1.25px across and down (a 1.77px stroke),
|
|
1165
|
+
meeting 2.5px behind it. That draws 8.25x14, centred by putting the
|
|
1166
|
+
point at x 4.875, and rasterises to dx's 8x14. -->
|
|
1167
|
+
<svg class="nxe-calendar-chevron" viewBox="0 0 18 18" focusable="false">
|
|
1168
|
+
<polygon points="4.875 9 11.875 2 13.125 3.25 7.375 9 13.125 14.75 11.875 16" />
|
|
1169
|
+
</svg>
|
|
1170
|
+
</button>
|
|
1171
|
+
<button type="button" class="nxe-calendar-caption" (click)="zoomOut()">
|
|
1172
|
+
{{ caption() }}
|
|
1173
|
+
</button>
|
|
1174
|
+
<button type="button" class="nxe-calendar-nav" (click)="navigate(1)">
|
|
1175
|
+
<!-- dx chevronright: the same chevron mirrored about x 9. -->
|
|
1176
|
+
<svg class="nxe-calendar-chevron" viewBox="0 0 18 18" focusable="false">
|
|
1177
|
+
<polygon points="13.125 9 6.125 2 4.875 3.25 10.625 9 4.875 14.75 6.125 16" />
|
|
1178
|
+
</svg>
|
|
1179
|
+
</button>
|
|
1180
|
+
</div>
|
|
1181
|
+
@if (zoomLevel() === 'month') {
|
|
1182
|
+
<div class="nxe-calendar-weekdays">
|
|
1183
|
+
@for (wd of weekdays; track wd) {
|
|
1184
|
+
<span>{{ wd }}</span>
|
|
1185
|
+
}
|
|
1186
|
+
</div>
|
|
1187
|
+
<div class="nxe-calendar-grid">
|
|
1188
|
+
@for (week of weeks(); track $index) {
|
|
1189
|
+
@for (day of week; track day.toMillis()) {
|
|
1190
|
+
<button
|
|
1191
|
+
type="button"
|
|
1192
|
+
class="nxe-calendar-day"
|
|
1193
|
+
[class.nxe-calendar-other]="day.month !== viewMonth().month"
|
|
1194
|
+
[class.nxe-calendar-selected]="isSelected(day)"
|
|
1195
|
+
[class.nxe-calendar-today]="isToday(day)"
|
|
1196
|
+
[disabled]="isDisabledDay(day)"
|
|
1197
|
+
(click)="selectDay(day)">
|
|
1198
|
+
<span>{{ day.day }}</span>
|
|
1199
|
+
</button>
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
</div>
|
|
1203
|
+
} @else {
|
|
1204
|
+
<div
|
|
1205
|
+
class="nxe-calendar-periods"
|
|
1206
|
+
[class.nxe-calendar-periods-century]="zoomLevel() === 'century'">
|
|
1207
|
+
@for (cell of periodCells(); track cell.anchor.toMillis()) {
|
|
1208
|
+
<button
|
|
1209
|
+
type="button"
|
|
1210
|
+
class="nxe-calendar-period"
|
|
1211
|
+
[class.nxe-calendar-other]="cell.other"
|
|
1212
|
+
[class.nxe-calendar-today]="cell.isNow"
|
|
1213
|
+
[disabled]="cell.disabled"
|
|
1214
|
+
(click)="selectPeriod(cell)">
|
|
1215
|
+
<span>{{ cell.label }}</span>
|
|
1216
|
+
</button>
|
|
1217
|
+
}
|
|
1218
|
+
</div>
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
@if (type() !== 'date') {
|
|
1222
|
+
<div class="nxe-calendar-time">
|
|
1223
|
+
<input
|
|
1224
|
+
class="nxe-calendar-time-part"
|
|
1225
|
+
type="text"
|
|
1226
|
+
inputmode="numeric"
|
|
1227
|
+
maxlength="2"
|
|
1228
|
+
aria-label="Hour"
|
|
1229
|
+
[value]="hourText()"
|
|
1230
|
+
(change)="setTimePart('hour', $event)" />
|
|
1231
|
+
<span class="nxe-calendar-time-sep" aria-hidden="true">:</span>
|
|
1232
|
+
<input
|
|
1233
|
+
class="nxe-calendar-time-part"
|
|
1234
|
+
type="text"
|
|
1235
|
+
inputmode="numeric"
|
|
1236
|
+
maxlength="2"
|
|
1237
|
+
aria-label="Minute"
|
|
1238
|
+
[value]="minuteText()"
|
|
1239
|
+
(change)="setTimePart('minute', $event)" />
|
|
1240
|
+
<button type="button" class="nxe-calendar-time-btn" (click)="setNow()">Now</button>
|
|
1241
|
+
<button type="button" class="nxe-calendar-time-btn nxe-calendar-time-done" (click)="close()">
|
|
1242
|
+
Done
|
|
1243
|
+
</button>
|
|
1244
|
+
</div>
|
|
1245
|
+
}
|
|
1246
|
+
</div>
|
|
1247
|
+
</ng-template>
|
|
1248
|
+
`, isInline: true, styles: ["nxe-date-box .nxe-datebox-button{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-date-box .nxe-datebox-button svg{display:block;width:18px;height:18px;fill:currentColor}nxe-date-box:hover:not(.nxe-disabled) .nxe-datebox-button,nxe-date-box:active:not(.nxe-disabled) .nxe-datebox-button{background-color:#e6e6e6}nxe-date-box .nxe-datebox-button.nxe-datebox-open{background-color:#b3b3b3}nxe-date-box .nxe-datebox-icon{width:18px;height:18px;fill:currentColor}nxe-date-box .nxe-editor-container:has(>.nxe-datebox-button){--nxe-invalid-badge-inset: 38px}nxe-date-box .nxe-editor-container:has(>.nxe-clear-button-area):has(>.nxe-datebox-button){--nxe-invalid-badge-inset: 72px}nxe-date-box.nxe-readonly .nxe-datebox-button,nxe-date-box.nxe-disabled .nxe-datebox-button{cursor:default}nxe-date-box.nxe-readonly .nxe-datebox-button:hover,nxe-date-box.nxe-disabled .nxe-datebox-button:hover{background-color:transparent}.nxe-calendar{width:298px;box-sizing:border-box;padding:8px;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 6px 12px #0000002e;color:#333;font-size:var(--nxe-ui-font-size, 12px);-webkit-user-select:none;user-select:none}.nxe-calendar-navigator{display:flex;height:36px;margin-bottom:8px}.nxe-calendar-nav,.nxe-calendar-caption{display:inline-flex;align-items:center;justify-content:center;border:1px solid #ddd;background:transparent;color:#333;cursor:pointer;padding:0}.nxe-calendar-nav:hover,.nxe-calendar-caption:hover{background:#0000000a}.nxe-calendar-nav:active,.nxe-calendar-caption:active{background:#0000003d}.nxe-calendar-nav{flex:0 0 36px}.nxe-calendar-nav:first-child{border-radius:4px 0 0 4px}.nxe-calendar-nav:last-child{border-radius:0 4px 4px 0}.nxe-calendar-caption{flex:1;margin:0 -1px;font-size:inherit;font-weight:600}.nxe-calendar-chevron{width:18px;height:18px;fill:currentColor}.nxe-calendar-weekdays{display:grid;grid-template-columns:repeat(7,1fr);align-items:center;height:24px;text-align:center;color:#333;font-size:10px;font-weight:500}.nxe-calendar-grid{display:grid;grid-template-columns:repeat(7,1fr)}.nxe-calendar-day,.nxe-calendar-period{display:flex;align-items:center;justify-content:center;border:0;background:transparent;cursor:pointer;padding:0;font-size:14px;line-height:1;color:#333}.nxe-calendar-day span,.nxe-calendar-period span{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;border-radius:4px}.nxe-calendar-day:hover:not(:disabled) span,.nxe-calendar-period:hover:not(:disabled) span{background:#337ab73d}.nxe-calendar-day:disabled,.nxe-calendar-period:disabled{cursor:default;color:#33333361}.nxe-calendar-day{height:33px}.nxe-calendar-day span{width:28px;height:28px}.nxe-calendar-periods{display:grid;grid-template-columns:repeat(4,1fr);grid-auto-rows:74px}.nxe-calendar-period span{min-width:54px;height:54px;padding:0 4px}.nxe-calendar-periods-century .nxe-calendar-period span{width:40px;min-width:0;height:auto;min-height:56px;padding:4px 0;white-space:normal;text-align:center;line-height:1.4}.nxe-calendar-other{color:#33333361}.nxe-calendar-today span{border:2px solid #337ab7}.nxe-calendar-selected span,.nxe-calendar-selected:hover:not(:disabled) span{background:#337ab7;color:#fff;box-shadow:0 0 0 2px #337ab780;border:0}.nxe-calendar-time{display:flex;align-items:center;gap:4px;margin-top:8px;padding-top:8px;border-top:1px solid #ddd}.nxe-calendar-time-part{width:2.6em;height:2.2em;box-sizing:border-box;padding:0 .25em;border:1px solid #ddd;border-radius:4px;background:#fff;color:#333;font-size:inherit;font-variant-numeric:tabular-nums;text-align:center}.nxe-calendar-time-part:focus{outline:2px solid #337ab7;outline-offset:-2px}.nxe-calendar-time-sep{font-weight:600}.nxe-calendar-time-btn{height:2.2em;padding:0 .75em;border:1px solid #ddd;border-radius:4px;background:transparent;color:#333;font-size:inherit;cursor:pointer}.nxe-calendar-time-btn:hover{background:#0000000a}.nxe-calendar-time-btn:focus-visible{outline:2px solid #337ab7;outline-offset:-2px}.nxe-calendar-time-done{margin-left:auto}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
941
1249
|
}
|
|
942
1250
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeDateBoxComponent, decorators: [{
|
|
943
1251
|
type: Component,
|
|
944
|
-
args: [{ selector: 'nxe-date-box', standalone: true, template: `
|
|
945
|
-
<div class="nxe-editor-container">
|
|
946
|
-
<input
|
|
947
|
-
#field
|
|
948
|
-
class="nxe-editor-input nxe-datebox-input"
|
|
949
|
-
|
|
950
|
-
[
|
|
951
|
-
[
|
|
952
|
-
[
|
|
953
|
-
[attr.
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
<
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
<svg class="nxe-
|
|
998
|
-
<
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
(
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1252
|
+
args: [{ selector: 'nxe-date-box', standalone: true, template: `
|
|
1253
|
+
<div class="nxe-editor-container">
|
|
1254
|
+
<input
|
|
1255
|
+
#field
|
|
1256
|
+
class="nxe-editor-input nxe-datebox-input"
|
|
1257
|
+
[attr.tabindex]="tabIndex()"
|
|
1258
|
+
[id]="controlId()"
|
|
1259
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
1260
|
+
[attr.aria-labelledby]="ariaLabelledBy() || null"
|
|
1261
|
+
[attr.aria-invalid]="validationError() ? true : null"
|
|
1262
|
+
[attr.aria-required]="required() ? true : null"
|
|
1263
|
+
type="text"
|
|
1264
|
+
[value]="displayValue()"
|
|
1265
|
+
[readOnly]="readOnly()"
|
|
1266
|
+
[disabled]="disabled()"
|
|
1267
|
+
[attr.placeholder]="effectivePlaceholder() || null"
|
|
1268
|
+
autocomplete="off"
|
|
1269
|
+
(input)="onFieldInput($event)"
|
|
1270
|
+
(focus)="onFocus($event)"
|
|
1271
|
+
(blur)="onBlur($event)" />
|
|
1272
|
+
@if (clearButtonVisible()) {
|
|
1273
|
+
<span
|
|
1274
|
+
class="nxe-clear-button-area"
|
|
1275
|
+
(mousedown)="$event.preventDefault()"
|
|
1276
|
+
(click)="onClear($event)"
|
|
1277
|
+
aria-hidden="true">
|
|
1278
|
+
<!-- A Ø16 disc with a 2px × cut out (the dropdown editors' clear glyph). -->
|
|
1279
|
+
<svg viewBox="0 0 18 18" focusable="false">
|
|
1280
|
+
<path fill-rule="evenodd" transform="rotate(45 9 9)"
|
|
1281
|
+
d="M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z" />
|
|
1282
|
+
</svg>
|
|
1283
|
+
</span>
|
|
1284
|
+
}
|
|
1285
|
+
@if (!readOnly()) {
|
|
1286
|
+
<span
|
|
1287
|
+
class="nxe-datebox-button"
|
|
1288
|
+
[class.nxe-datebox-open]="opened()"
|
|
1289
|
+
(mousedown)="onButtonMousedown($event)"
|
|
1290
|
+
aria-hidden="true">
|
|
1291
|
+
@switch (type()) {
|
|
1292
|
+
@case ('time') {
|
|
1293
|
+
<!-- dx clock, a 16x16 ink box round the box centre: a 2px ring (an r 7
|
|
1294
|
+
circle stroked 2px), a 2x4 hand straight up from the centre, a 1.5x4
|
|
1295
|
+
hand turned 45° down-right, and a Ø2 hub where they meet. -->
|
|
1296
|
+
<svg class="nxe-datebox-icon nxe-datebox-icon-time" viewBox="0 0 18 18" focusable="false">
|
|
1297
|
+
<circle cx="9" cy="9" r="7" fill="none" stroke="currentColor" stroke-width="2" />
|
|
1298
|
+
<rect x="8" y="5" width="2" height="4" />
|
|
1299
|
+
<rect x="9" y="8.25" width="4" height="1.5" transform="rotate(45 9 9)" />
|
|
1300
|
+
<circle cx="9" cy="9" r="1" />
|
|
1301
|
+
</svg>
|
|
1302
|
+
}
|
|
1303
|
+
@case ('datetime') {
|
|
1304
|
+
<!-- dx eventall: the calendar page below, without its day marker. -->
|
|
1305
|
+
<svg class="nxe-datebox-icon nxe-datebox-icon-datetime" viewBox="0 0 18 18" focusable="false">
|
|
1306
|
+
<rect x="3" y="3" width="12" height="12" rx="1" fill="none" stroke="currentColor" stroke-width="2" />
|
|
1307
|
+
<rect x="3" y="3" width="12" height="3" />
|
|
1308
|
+
<rect x="4" y="1" width="2" height="1.5" />
|
|
1309
|
+
<rect x="12" y="1" width="2" height="1.5" />
|
|
1310
|
+
</svg>
|
|
1311
|
+
}
|
|
1312
|
+
@default {
|
|
1313
|
+
<!-- dx event, a 14x15 ink box from 1px below the top of the 18px box
|
|
1314
|
+
(where dx's glyph renders): the page is a 12x12 rect with 1px corners
|
|
1315
|
+
stroked 2px, so 14x14 with 2px corners outside and square inside; a
|
|
1316
|
+
12x3 bar under its top wall makes the 4px header band; two 2x1.5
|
|
1317
|
+
binder tabs stand 1px proud of it; a 4x4 day marker at (9, 9). -->
|
|
1318
|
+
<svg class="nxe-datebox-icon nxe-datebox-icon-date" viewBox="0 0 18 18" focusable="false">
|
|
1319
|
+
<rect x="3" y="3" width="12" height="12" rx="1" fill="none" stroke="currentColor" stroke-width="2" />
|
|
1320
|
+
<rect x="3" y="3" width="12" height="3" />
|
|
1321
|
+
<rect x="4" y="1" width="2" height="1.5" />
|
|
1322
|
+
<rect x="12" y="1" width="2" height="1.5" />
|
|
1323
|
+
<rect x="9" y="9" width="4" height="4" />
|
|
1324
|
+
</svg>
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
</span>
|
|
1328
|
+
}
|
|
1329
|
+
</div>
|
|
1330
|
+
<ng-content />
|
|
1331
|
+
@if (validationError(); as error) {
|
|
1332
|
+
@if (focused()) {
|
|
1333
|
+
<div class="nxe-invalid-message">{{ error }}</div>
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
<ng-template #calendarTemplate>
|
|
1338
|
+
<div class="nxe-calendar" (mousedown)="$event.preventDefault()">
|
|
1339
|
+
@if (type() !== 'time') {
|
|
1340
|
+
<div class="nxe-calendar-navigator">
|
|
1341
|
+
<button type="button" class="nxe-calendar-nav" (click)="navigate(-1)">
|
|
1342
|
+
<!-- dx chevronleft (8x14 ink, centred in its 18px box): two 45° arms
|
|
1343
|
+
whose outer edges run 7px out and 7px up and down from the point,
|
|
1344
|
+
their ends cut square 1.25px across and down (a 1.77px stroke),
|
|
1345
|
+
meeting 2.5px behind it. That draws 8.25x14, centred by putting the
|
|
1346
|
+
point at x 4.875, and rasterises to dx's 8x14. -->
|
|
1347
|
+
<svg class="nxe-calendar-chevron" viewBox="0 0 18 18" focusable="false">
|
|
1348
|
+
<polygon points="4.875 9 11.875 2 13.125 3.25 7.375 9 13.125 14.75 11.875 16" />
|
|
1349
|
+
</svg>
|
|
1350
|
+
</button>
|
|
1351
|
+
<button type="button" class="nxe-calendar-caption" (click)="zoomOut()">
|
|
1352
|
+
{{ caption() }}
|
|
1353
|
+
</button>
|
|
1354
|
+
<button type="button" class="nxe-calendar-nav" (click)="navigate(1)">
|
|
1355
|
+
<!-- dx chevronright: the same chevron mirrored about x 9. -->
|
|
1356
|
+
<svg class="nxe-calendar-chevron" viewBox="0 0 18 18" focusable="false">
|
|
1357
|
+
<polygon points="13.125 9 6.125 2 4.875 3.25 10.625 9 4.875 14.75 6.125 16" />
|
|
1358
|
+
</svg>
|
|
1359
|
+
</button>
|
|
1360
|
+
</div>
|
|
1361
|
+
@if (zoomLevel() === 'month') {
|
|
1362
|
+
<div class="nxe-calendar-weekdays">
|
|
1363
|
+
@for (wd of weekdays; track wd) {
|
|
1364
|
+
<span>{{ wd }}</span>
|
|
1365
|
+
}
|
|
1366
|
+
</div>
|
|
1367
|
+
<div class="nxe-calendar-grid">
|
|
1368
|
+
@for (week of weeks(); track $index) {
|
|
1369
|
+
@for (day of week; track day.toMillis()) {
|
|
1370
|
+
<button
|
|
1371
|
+
type="button"
|
|
1372
|
+
class="nxe-calendar-day"
|
|
1373
|
+
[class.nxe-calendar-other]="day.month !== viewMonth().month"
|
|
1374
|
+
[class.nxe-calendar-selected]="isSelected(day)"
|
|
1375
|
+
[class.nxe-calendar-today]="isToday(day)"
|
|
1376
|
+
[disabled]="isDisabledDay(day)"
|
|
1377
|
+
(click)="selectDay(day)">
|
|
1378
|
+
<span>{{ day.day }}</span>
|
|
1379
|
+
</button>
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
</div>
|
|
1383
|
+
} @else {
|
|
1384
|
+
<div
|
|
1385
|
+
class="nxe-calendar-periods"
|
|
1386
|
+
[class.nxe-calendar-periods-century]="zoomLevel() === 'century'">
|
|
1387
|
+
@for (cell of periodCells(); track cell.anchor.toMillis()) {
|
|
1388
|
+
<button
|
|
1389
|
+
type="button"
|
|
1390
|
+
class="nxe-calendar-period"
|
|
1391
|
+
[class.nxe-calendar-other]="cell.other"
|
|
1392
|
+
[class.nxe-calendar-today]="cell.isNow"
|
|
1393
|
+
[disabled]="cell.disabled"
|
|
1394
|
+
(click)="selectPeriod(cell)">
|
|
1395
|
+
<span>{{ cell.label }}</span>
|
|
1396
|
+
</button>
|
|
1397
|
+
}
|
|
1398
|
+
</div>
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
@if (type() !== 'date') {
|
|
1402
|
+
<div class="nxe-calendar-time">
|
|
1403
|
+
<input
|
|
1404
|
+
class="nxe-calendar-time-part"
|
|
1405
|
+
type="text"
|
|
1406
|
+
inputmode="numeric"
|
|
1407
|
+
maxlength="2"
|
|
1408
|
+
aria-label="Hour"
|
|
1409
|
+
[value]="hourText()"
|
|
1410
|
+
(change)="setTimePart('hour', $event)" />
|
|
1411
|
+
<span class="nxe-calendar-time-sep" aria-hidden="true">:</span>
|
|
1412
|
+
<input
|
|
1413
|
+
class="nxe-calendar-time-part"
|
|
1414
|
+
type="text"
|
|
1415
|
+
inputmode="numeric"
|
|
1416
|
+
maxlength="2"
|
|
1417
|
+
aria-label="Minute"
|
|
1418
|
+
[value]="minuteText()"
|
|
1419
|
+
(change)="setTimePart('minute', $event)" />
|
|
1420
|
+
<button type="button" class="nxe-calendar-time-btn" (click)="setNow()">Now</button>
|
|
1421
|
+
<button type="button" class="nxe-calendar-time-btn nxe-calendar-time-done" (click)="close()">
|
|
1422
|
+
Done
|
|
1423
|
+
</button>
|
|
1424
|
+
</div>
|
|
1425
|
+
}
|
|
1426
|
+
</div>
|
|
1427
|
+
</ng-template>
|
|
1069
1428
|
`, host: {
|
|
1070
1429
|
class: 'nxe-widget nxe-editor nxe-datebox',
|
|
1071
1430
|
'[class.nxe-focused]': 'focused()',
|
|
@@ -1073,13 +1432,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
1073
1432
|
}, providers: [
|
|
1074
1433
|
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxeDateBoxComponent), multi: true },
|
|
1075
1434
|
{ provide: NXE_VALIDATION_TARGET, useExisting: forwardRef(() => NxeDateBoxComponent) },
|
|
1076
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-date-box .nxe-datebox-button{flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;
|
|
1077
|
-
}], propDecorators: { calendarTemplate: [{ type: i0.ViewChild, args: ['calendarTemplate', { isSignal: true }] }], fieldRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], displayFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayFormat", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }] } });
|
|
1435
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-date-box .nxe-datebox-button{box-sizing:border-box;position:relative;flex:0 0 34px;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;width:34px;min-width:34px;padding:1px;border-radius:4px;background-clip:content-box;color:#333;cursor:pointer}nxe-date-box .nxe-datebox-button svg{display:block;width:18px;height:18px;fill:currentColor}nxe-date-box:hover:not(.nxe-disabled) .nxe-datebox-button,nxe-date-box:active:not(.nxe-disabled) .nxe-datebox-button{background-color:#e6e6e6}nxe-date-box .nxe-datebox-button.nxe-datebox-open{background-color:#b3b3b3}nxe-date-box .nxe-datebox-icon{width:18px;height:18px;fill:currentColor}nxe-date-box .nxe-editor-container:has(>.nxe-datebox-button){--nxe-invalid-badge-inset: 38px}nxe-date-box .nxe-editor-container:has(>.nxe-clear-button-area):has(>.nxe-datebox-button){--nxe-invalid-badge-inset: 72px}nxe-date-box.nxe-readonly .nxe-datebox-button,nxe-date-box.nxe-disabled .nxe-datebox-button{cursor:default}nxe-date-box.nxe-readonly .nxe-datebox-button:hover,nxe-date-box.nxe-disabled .nxe-datebox-button:hover{background-color:transparent}.nxe-calendar{width:298px;box-sizing:border-box;padding:8px;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 6px 12px #0000002e;color:#333;font-size:var(--nxe-ui-font-size, 12px);-webkit-user-select:none;user-select:none}.nxe-calendar-navigator{display:flex;height:36px;margin-bottom:8px}.nxe-calendar-nav,.nxe-calendar-caption{display:inline-flex;align-items:center;justify-content:center;border:1px solid #ddd;background:transparent;color:#333;cursor:pointer;padding:0}.nxe-calendar-nav:hover,.nxe-calendar-caption:hover{background:#0000000a}.nxe-calendar-nav:active,.nxe-calendar-caption:active{background:#0000003d}.nxe-calendar-nav{flex:0 0 36px}.nxe-calendar-nav:first-child{border-radius:4px 0 0 4px}.nxe-calendar-nav:last-child{border-radius:0 4px 4px 0}.nxe-calendar-caption{flex:1;margin:0 -1px;font-size:inherit;font-weight:600}.nxe-calendar-chevron{width:18px;height:18px;fill:currentColor}.nxe-calendar-weekdays{display:grid;grid-template-columns:repeat(7,1fr);align-items:center;height:24px;text-align:center;color:#333;font-size:10px;font-weight:500}.nxe-calendar-grid{display:grid;grid-template-columns:repeat(7,1fr)}.nxe-calendar-day,.nxe-calendar-period{display:flex;align-items:center;justify-content:center;border:0;background:transparent;cursor:pointer;padding:0;font-size:14px;line-height:1;color:#333}.nxe-calendar-day span,.nxe-calendar-period span{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;border-radius:4px}.nxe-calendar-day:hover:not(:disabled) span,.nxe-calendar-period:hover:not(:disabled) span{background:#337ab73d}.nxe-calendar-day:disabled,.nxe-calendar-period:disabled{cursor:default;color:#33333361}.nxe-calendar-day{height:33px}.nxe-calendar-day span{width:28px;height:28px}.nxe-calendar-periods{display:grid;grid-template-columns:repeat(4,1fr);grid-auto-rows:74px}.nxe-calendar-period span{min-width:54px;height:54px;padding:0 4px}.nxe-calendar-periods-century .nxe-calendar-period span{width:40px;min-width:0;height:auto;min-height:56px;padding:4px 0;white-space:normal;text-align:center;line-height:1.4}.nxe-calendar-other{color:#33333361}.nxe-calendar-today span{border:2px solid #337ab7}.nxe-calendar-selected span,.nxe-calendar-selected:hover:not(:disabled) span{background:#337ab7;color:#fff;box-shadow:0 0 0 2px #337ab780;border:0}.nxe-calendar-time{display:flex;align-items:center;gap:4px;margin-top:8px;padding-top:8px;border-top:1px solid #ddd}.nxe-calendar-time-part{width:2.6em;height:2.2em;box-sizing:border-box;padding:0 .25em;border:1px solid #ddd;border-radius:4px;background:#fff;color:#333;font-size:inherit;font-variant-numeric:tabular-nums;text-align:center}.nxe-calendar-time-part:focus{outline:2px solid #337ab7;outline-offset:-2px}.nxe-calendar-time-sep{font-weight:600}.nxe-calendar-time-btn{height:2.2em;padding:0 .75em;border:1px solid #ddd;border-radius:4px;background:transparent;color:#333;font-size:inherit;cursor:pointer}.nxe-calendar-time-btn:hover{background:#0000000a}.nxe-calendar-time-btn:focus-visible{outline:2px solid #337ab7;outline-offset:-2px}.nxe-calendar-time-done{margin-left:auto}\n"] }]
|
|
1436
|
+
}], propDecorators: { calendarTemplate: [{ type: i0.ViewChild, args: ['calendarTemplate', { isSignal: true }] }], fieldRef: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], displayFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayFormat", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], showClearButtonInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }] } });
|
|
1078
1437
|
|
|
1079
1438
|
/**
|
|
1080
1439
|
* `nxe-scroll-view` — drop-in replacement for DevExtreme `dx-scroll-view`.
|
|
1081
1440
|
*
|
|
1082
|
-
* In this app `
|
|
1441
|
+
* In this app `nxe-scroll-view` is used purely as a dumb scroll container: no `@ViewChild`, no
|
|
1083
1442
|
* `.instance` methods, no events (see survey). Every live tag is the same literal triple
|
|
1084
1443
|
* `[scrollByContent]="true" [scrollByThumb]="true" [showScrollbar]="'onScroll'"`. So this is a
|
|
1085
1444
|
* styled `overflow:auto` wrapper that projects its content inside a `.nxe-scrollview-content`
|
|
@@ -1096,11 +1455,11 @@ class NxeScrollViewComponent {
|
|
|
1096
1455
|
showScrollbar = input('onScroll', /* @ts-ignore */
|
|
1097
1456
|
...(ngDevMode ? [{ debugName: "showScrollbar" }] : /* istanbul ignore next */ []));
|
|
1098
1457
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeScrollViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1099
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.5", type: NxeScrollViewComponent, isStandalone: true, selector: "nxe-scroll-view", inputs: { scrollByContent: { classPropertyName: "scrollByContent", publicName: "scrollByContent", isSignal: true, isRequired: false, transformFunction: null }, scrollByThumb: { classPropertyName: "scrollByThumb", publicName: "scrollByThumb", isSignal: true, isRequired: false, transformFunction: null }, showScrollbar: { classPropertyName: "showScrollbar", publicName: "showScrollbar", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "nxe-widget nxe-scroll-view" }, ngImport: i0, template: '<div class="nxe-scrollview-content"><ng-content /></div>', isInline: true, styles: ["nxe-scroll-view{display:block;height:100%;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(191,191,191,.7) transparent}nxe-scroll-view::-webkit-scrollbar{width:8px;height:8px}nxe-scroll-view::-webkit-scrollbar-track{background:transparent}nxe-scroll-view::-webkit-scrollbar-thumb{background-color:#bfbfbfb3;border-radius:4px}nxe-scroll-view:hover::-webkit-scrollbar-thumb{background-color:#bfbfbf}nxe-scroll-view>.nxe-scrollview-content{display:flex;flex-direction:column;min-height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1458
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.5", type: NxeScrollViewComponent, isStandalone: true, selector: "nxe-scroll-view", inputs: { scrollByContent: { classPropertyName: "scrollByContent", publicName: "scrollByContent", isSignal: true, isRequired: false, transformFunction: null }, scrollByThumb: { classPropertyName: "scrollByThumb", publicName: "scrollByThumb", isSignal: true, isRequired: false, transformFunction: null }, showScrollbar: { classPropertyName: "showScrollbar", publicName: "showScrollbar", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "nxe-widget nxe-scroll-view" }, ngImport: i0, template: '<div class="nxe-scrollview-content"><ng-content /></div>', isInline: true, styles: ["nxe-scroll-view{display:block;height:100%;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(191,191,191,.7) transparent}@supports not (scrollbar-width: thin){nxe-scroll-view::-webkit-scrollbar{width:8px;height:8px}nxe-scroll-view::-webkit-scrollbar-track{background:transparent}nxe-scroll-view::-webkit-scrollbar-thumb{background-color:#bfbfbfb3;border-radius:4px}nxe-scroll-view:hover::-webkit-scrollbar-thumb{background-color:#bfbfbf}}nxe-scroll-view>.nxe-scrollview-content{display:flex;flex-direction:column;min-height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1100
1459
|
}
|
|
1101
1460
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeScrollViewComponent, decorators: [{
|
|
1102
1461
|
type: Component,
|
|
1103
|
-
args: [{ selector: 'nxe-scroll-view', standalone: true, template: '<div class="nxe-scrollview-content"><ng-content /></div>', host: { class: 'nxe-widget nxe-scroll-view' }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-scroll-view{display:block;height:100%;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(191,191,191,.7) transparent}nxe-scroll-view::-webkit-scrollbar{width:8px;height:8px}nxe-scroll-view::-webkit-scrollbar-track{background:transparent}nxe-scroll-view::-webkit-scrollbar-thumb{background-color:#bfbfbfb3;border-radius:4px}nxe-scroll-view:hover::-webkit-scrollbar-thumb{background-color:#bfbfbf}nxe-scroll-view>.nxe-scrollview-content{display:flex;flex-direction:column;min-height:100%}\n"] }]
|
|
1462
|
+
args: [{ selector: 'nxe-scroll-view', standalone: true, template: '<div class="nxe-scrollview-content"><ng-content /></div>', host: { class: 'nxe-widget nxe-scroll-view' }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["nxe-scroll-view{display:block;height:100%;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(191,191,191,.7) transparent}@supports not (scrollbar-width: thin){nxe-scroll-view::-webkit-scrollbar{width:8px;height:8px}nxe-scroll-view::-webkit-scrollbar-track{background:transparent}nxe-scroll-view::-webkit-scrollbar-thumb{background-color:#bfbfbfb3;border-radius:4px}nxe-scroll-view:hover::-webkit-scrollbar-thumb{background-color:#bfbfbf}}nxe-scroll-view>.nxe-scrollview-content{display:flex;flex-direction:column;min-height:100%}\n"] }]
|
|
1104
1463
|
}], propDecorators: { scrollByContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollByContent", required: false }] }], scrollByThumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollByThumb", required: false }] }], showScrollbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showScrollbar", required: false }] }] } });
|
|
1105
1464
|
|
|
1106
1465
|
// @nexterajs/ui/forms — public API.
|