ngwr 14.7.0 → 14.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bar-chart/styles/_index.scss +1 -0
- package/calendar-heatmap/styles/_index.scss +1 -0
- package/cascader/styles/_rules.scss +86 -14
- package/date-picker/styles/_index.scss +30 -0
- package/density/styles/_index.scss +4 -2
- package/donut-chart/styles/_index.scss +10 -0
- package/dropdown/styles/_index.scss +67 -5
- package/event-calendar/styles/_index.scss +209 -35
- package/fesm2022/ngwr-bar-chart.mjs +29 -4
- package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-heatmap.mjs +59 -4
- package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
- package/fesm2022/ngwr-cascader.mjs +2 -2
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox.mjs +12 -2
- package/fesm2022/ngwr-checkbox.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker.mjs +705 -46
- package/fesm2022/ngwr-date-picker.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart.mjs +46 -4
- package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +166 -17
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar.mjs +9 -2
- package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-form.mjs +52 -1
- package/fesm2022/ngwr-form.mjs.map +1 -1
- package/fesm2022/ngwr-gauge.mjs +33 -4
- package/fesm2022/ngwr-gauge.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ar.mjs +2 -0
- package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-cs.mjs +2 -0
- package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-de.mjs +2 -0
- package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +5 -0
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-es.mjs +2 -0
- package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-fr.mjs +2 -0
- package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-he.mjs +2 -0
- package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-hi.mjs +2 -0
- package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-id.mjs +2 -0
- package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-it.mjs +2 -0
- package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ja.mjs +2 -0
- package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ko.mjs +2 -0
- package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-nl.mjs +2 -0
- package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pl.mjs +2 -0
- package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pt.mjs +2 -0
- package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +2 -0
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-sv.mjs +2 -0
- package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-tr.mjs +2 -0
- package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-uk.mjs +2 -0
- package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-vi.mjs +2 -0
- package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh-TW.mjs +2 -0
- package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh.mjs +2 -0
- package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
- package/fesm2022/ngwr-input-number.mjs +12 -0
- package/fesm2022/ngwr-input-number.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart.mjs +16 -5
- package/fesm2022/ngwr-line-chart.mjs.map +1 -1
- package/fesm2022/ngwr-meter-group-testing.mjs +7 -3
- package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
- package/fesm2022/ngwr-meter-group.mjs +24 -4
- package/fesm2022/ngwr-meter-group.mjs.map +1 -1
- package/fesm2022/ngwr-page-header.mjs +10 -2
- package/fesm2022/ngwr-page-header.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +569 -7
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-sidebar.mjs +7 -0
- package/fesm2022/ngwr-sidebar.mjs.map +1 -1
- package/fesm2022/ngwr-sparkline.mjs +82 -8
- package/fesm2022/ngwr-sparkline.mjs.map +1 -1
- package/fesm2022/ngwr-table.mjs +1 -1
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-toolbar.mjs +7 -0
- package/fesm2022/ngwr-toolbar.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/form/styles/_index.scss +11 -1
- package/gauge/styles/_index.scss +1 -0
- package/i18n/ar.json +3 -1
- package/i18n/cs.json +3 -1
- package/i18n/de.json +3 -1
- package/i18n/en.json +3 -1
- package/i18n/es.json +3 -1
- package/i18n/fr.json +3 -1
- package/i18n/he.json +3 -1
- package/i18n/hi.json +3 -1
- package/i18n/id.json +3 -1
- package/i18n/it.json +3 -1
- package/i18n/ja.json +3 -1
- package/i18n/ko.json +3 -1
- package/i18n/nl.json +3 -1
- package/i18n/pl.json +3 -1
- package/i18n/pt.json +3 -1
- package/i18n/ru.json +3 -1
- package/i18n/sv.json +3 -1
- package/i18n/tr.json +3 -1
- package/i18n/uk.json +3 -1
- package/i18n/vi.json +3 -1
- package/i18n/zh-TW.json +3 -1
- package/i18n/zh.json +3 -1
- package/input/styles/_index.scss +19 -0
- package/input-number/styles/_index.scss +69 -0
- package/line-chart/styles/_index.scss +30 -2
- package/llms-full.txt +3 -3
- package/meter-group/styles/_index.scss +1 -0
- package/overlay/styles/_arrow.scss +27 -2
- package/package.json +1 -1
- package/page-header/styles/_index.scss +37 -1
- package/pagination/styles/_index.scss +9 -5
- package/popover/styles/_index.scss +73 -5
- package/select/styles/_index.scss +48 -9
- package/sidebar/styles/_index.scss +34 -2
- package/sparkline/styles/_index.scss +19 -0
- package/toolbar/styles/_index.scss +35 -1
- package/tree/styles/_index.scss +45 -6
- package/types/ngwr-bar-chart.d.ts +19 -1
- package/types/ngwr-calendar-heatmap.d.ts +29 -1
- package/types/ngwr-checkbox.d.ts +2 -0
- package/types/ngwr-date-picker.d.ts +308 -43
- package/types/ngwr-donut-chart.d.ts +24 -1
- package/types/ngwr-dropdown.d.ts +22 -2
- package/types/ngwr-event-calendar.d.ts +8 -0
- package/types/ngwr-form.d.ts +35 -5
- package/types/ngwr-gauge.d.ts +20 -1
- package/types/ngwr-input-number.d.ts +7 -0
- package/types/ngwr-line-chart.d.ts +9 -1
- package/types/ngwr-meter-group-testing.d.ts +3 -2
- package/types/ngwr-meter-group.d.ts +14 -1
- package/types/ngwr-page-header.d.ts +10 -2
- package/types/ngwr-popover.d.ts +154 -3
- package/types/ngwr-sidebar.d.ts +7 -0
- package/types/ngwr-sparkline.d.ts +43 -1
- package/types/ngwr-toolbar.d.ts +7 -0
- package/types/ngwr-version.d.ts +1 -1
|
@@ -1,8 +1,71 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { ElementRef } from '@angular/core';
|
|
2
|
+
import { Signal, ElementRef } from '@angular/core';
|
|
3
3
|
import { FormValueControl } from '@angular/forms/signals';
|
|
4
4
|
import { WrDateFormat } from 'ngwr/date';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @license
|
|
8
|
+
*
|
|
9
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
10
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Why the text typed into a picker's field was not committed.
|
|
14
|
+
*
|
|
15
|
+
* A picker never guesses: text it cannot read, or a date the calendar would
|
|
16
|
+
* refuse, leaves the bound value exactly as it was. This is the reason it
|
|
17
|
+
* refused, in the shape Angular's forms carry an error — `kind` is the key
|
|
18
|
+
* `<wr-form-field>` resolves a message for (`validation.<kind>` in the
|
|
19
|
+
* `ngwr/i18n` catalogs), and `message` is that sentence already resolved, for
|
|
20
|
+
* a template that renders errors itself.
|
|
21
|
+
*
|
|
22
|
+
* - `dateFormat` — the text does not read as a date in the field's format.
|
|
23
|
+
* `example` is a date written in that format, for the message to show.
|
|
24
|
+
* - `minDate` / `maxDate` — the text reads, and the date is outside the bounds.
|
|
25
|
+
* - `dateFilter` — the text reads, and the `dateFilter` predicate rejects it.
|
|
26
|
+
*
|
|
27
|
+
* The same keys, and the same `min` / `max` payload, as `WrValidators.minDate`
|
|
28
|
+
* and `WrValidators.maxDate`, so one app-wide message covers both.
|
|
29
|
+
*/
|
|
30
|
+
type WrDateInputError = {
|
|
31
|
+
readonly kind: 'dateFormat';
|
|
32
|
+
readonly message: string;
|
|
33
|
+
readonly example: string;
|
|
34
|
+
} | {
|
|
35
|
+
readonly kind: 'minDate';
|
|
36
|
+
readonly message: string;
|
|
37
|
+
readonly date: Date;
|
|
38
|
+
readonly min: Date;
|
|
39
|
+
} | {
|
|
40
|
+
readonly kind: 'maxDate';
|
|
41
|
+
readonly message: string;
|
|
42
|
+
readonly date: Date;
|
|
43
|
+
readonly max: Date;
|
|
44
|
+
} | {
|
|
45
|
+
readonly kind: 'dateFilter';
|
|
46
|
+
readonly message: string;
|
|
47
|
+
readonly date: Date;
|
|
48
|
+
};
|
|
49
|
+
/** A {@link WrDateInputError} from one end of a `<wr-date-range-picker>`. */
|
|
50
|
+
type WrDateRangeInputError = WrDateInputError & {
|
|
51
|
+
readonly end: 'start' | 'end';
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @license
|
|
56
|
+
*
|
|
57
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
58
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
59
|
+
*/
|
|
60
|
+
/**
|
|
61
|
+
* The `<wr-date-range-picker>` value — `[start, end]`.
|
|
62
|
+
*
|
|
63
|
+
* Either end can be `null` while the range is half-picked, so a partially
|
|
64
|
+
* filled range is still representable. Structurally identical to
|
|
65
|
+
* `WrCalendarRange`, which the picker forwards it to.
|
|
66
|
+
*/
|
|
67
|
+
type WrDateRange = readonly [Date | null, Date | null];
|
|
68
|
+
|
|
6
69
|
/**
|
|
7
70
|
* Unified date / time / date-time picker. Same `<input>` + popover skeleton
|
|
8
71
|
* for every mode — the overlay content swaps based on `[mode]`:
|
|
@@ -20,8 +83,12 @@ import { WrDateFormat } from 'ngwr/date';
|
|
|
20
83
|
* `[(ngModel)]` / reactive forms keep working through Angular's bridge. Value
|
|
21
84
|
* type is `Date | null` for every mode.
|
|
22
85
|
*
|
|
23
|
-
* Parses the input on every keystroke
|
|
24
|
-
*
|
|
86
|
+
* Parses the input on every keystroke and emits only a date it can read and the
|
|
87
|
+
* calendar would accept. Anything else is REFUSED, never guessed: the bound value
|
|
88
|
+
* stays where it was, and the text stays in the field so it can be corrected.
|
|
89
|
+
* Enter and leaving the field turn a refusal visible — see {@link inputError}.
|
|
90
|
+
* A committed date is re-formatted canonical on blur and on Enter. Format is
|
|
91
|
+
* driven by {@link WrDateAdapter}: it
|
|
25
92
|
* accepts both named keys (`'shortDate'`, `'mediumDateTime'`, …) and raw
|
|
26
93
|
* token strings (`'dd.MM.yyyy'`, `'HH:mm'`). When `format` is left at the
|
|
27
94
|
* default (`null`), the picker derives the right named key from `mode`:
|
|
@@ -91,8 +158,8 @@ declare class WrDatePicker implements FormValueControl<Date | null> {
|
|
|
91
158
|
* simply reads as `ltr`.
|
|
92
159
|
*/
|
|
93
160
|
private readonly dir;
|
|
94
|
-
protected readonly inputEl:
|
|
95
|
-
protected readonly triggerEl:
|
|
161
|
+
protected readonly inputEl: Signal<ElementRef<HTMLInputElement>>;
|
|
162
|
+
protected readonly triggerEl: Signal<ElementRef<HTMLButtonElement> | undefined>;
|
|
96
163
|
/** The picked Date. Bound by `[formField]`, or two-way via `[(value)]`. */
|
|
97
164
|
readonly value: _angular_core.ModelSignal<Date | null>;
|
|
98
165
|
/** Emitted on blur so a bound field can mark itself touched. */
|
|
@@ -110,9 +177,9 @@ declare class WrDatePicker implements FormValueControl<Date | null> {
|
|
|
110
177
|
/** Whether the panel this open cycle should take focus. */
|
|
111
178
|
private autoFocusPanel;
|
|
112
179
|
/** Resolved format — falls back to a mode-appropriate default. */
|
|
113
|
-
protected readonly resolvedFormat:
|
|
114
|
-
protected readonly isTime:
|
|
115
|
-
protected readonly isDateTime:
|
|
180
|
+
protected readonly resolvedFormat: Signal<string>;
|
|
181
|
+
protected readonly isTime: Signal<boolean>;
|
|
182
|
+
protected readonly isDateTime: Signal<boolean>;
|
|
116
183
|
private readonly labelDate;
|
|
117
184
|
private readonly labelTime;
|
|
118
185
|
private readonly labelDateTime;
|
|
@@ -126,8 +193,8 @@ declare class WrDatePicker implements FormValueControl<Date | null> {
|
|
|
126
193
|
*/
|
|
127
194
|
readonly ariaLabel: _angular_core.InputSignal<string | null>;
|
|
128
195
|
private readonly fieldLabel;
|
|
129
|
-
protected readonly resolvedAriaLabel:
|
|
130
|
-
protected readonly triggerLabel:
|
|
196
|
+
protected readonly resolvedAriaLabel: Signal<string>;
|
|
197
|
+
protected readonly triggerLabel: Signal<string>;
|
|
131
198
|
/**
|
|
132
199
|
* Accessible name of the popup. The trigger advertises
|
|
133
200
|
* `aria-haspopup="dialog"`, so the panel is a `role="dialog"` — and an unnamed
|
|
@@ -137,8 +204,83 @@ declare class WrDatePicker implements FormValueControl<Date | null> {
|
|
|
137
204
|
readonly panelAriaLabel: _angular_core.InputSignal<string | null>;
|
|
138
205
|
/** Popup id — what the trigger's `aria-controls` points at while open. */
|
|
139
206
|
protected readonly panelId: string;
|
|
140
|
-
protected readonly resolvedPanelLabel:
|
|
141
|
-
|
|
207
|
+
protected readonly resolvedPanelLabel: Signal<string>;
|
|
208
|
+
private readonly refusals;
|
|
209
|
+
private readonly reportToForm;
|
|
210
|
+
private readonly inputField;
|
|
211
|
+
/**
|
|
212
|
+
* Why the text in the field was not committed — `null` while the text is the value.
|
|
213
|
+
* Raised on the keystroke that makes the text unusable, and reported to a bound form
|
|
214
|
+
* from that keystroke on.
|
|
215
|
+
*/
|
|
216
|
+
private readonly refusal;
|
|
217
|
+
/**
|
|
218
|
+
* Whether the refusal is on show. A refusal is raised on the keystroke but shown
|
|
219
|
+
* only once the user has finished — on Enter, or on leaving the field — because
|
|
220
|
+
* every date is unreadable for most of the time it takes to type one, and a field
|
|
221
|
+
* that turned red on the first digit would be telling the user off for typing.
|
|
222
|
+
* Once shown it follows the text live, so a correction clears it immediately.
|
|
223
|
+
*
|
|
224
|
+
* Leaving counts wherever focus goes, including by way of the open panel: moving
|
|
225
|
+
* into the panel waits, since a pick there replaces the text, but focus that leaves
|
|
226
|
+
* the panel for anything other than the field — or a panel that closes without a
|
|
227
|
+
* pick and without handing focus back to the field — has left too.
|
|
228
|
+
*/
|
|
229
|
+
private readonly revealed;
|
|
230
|
+
/**
|
|
231
|
+
* Why the text in the field is not the bound value, once the picker is showing it —
|
|
232
|
+
* `null` while the text is the value, and `null` while the user is still typing.
|
|
233
|
+
*
|
|
234
|
+
* A refusal is raised on the keystroke that makes the text unreadable (`dateFormat`),
|
|
235
|
+
* out of `min` / `max` (`minDate` / `maxDate`) or rejected by `dateFilter`, and goes
|
|
236
|
+
* on show on Enter or when the user leaves the field — the same moment the border
|
|
237
|
+
* turns and the reason is announced, so a message rendered from this signal never
|
|
238
|
+
* disagrees with them. Once on show it follows the text, and it clears the moment the
|
|
239
|
+
* text becomes a date the picker commits, is emptied, or is replaced by a pick from
|
|
240
|
+
* the panel, a value written from outside, or a form reset. The value itself is never
|
|
241
|
+
* touched by a refusal.
|
|
242
|
+
*
|
|
243
|
+
* A bound form does NOT wait: `[formField]`, `[formControl]`, `formControlName` and
|
|
244
|
+
* `[(ngModel)]` see the refusal as a parse error from the keystroke, so the form is
|
|
245
|
+
* invalid the whole time the field holds text it could not use, and
|
|
246
|
+
* `<wr-form-field>` shows `message` by its own rule — once the control is touched or
|
|
247
|
+
* dirty. Read this through a template reference when the picker is bound with
|
|
248
|
+
* `[(value)]` alone and the reason should be on screen.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```html
|
|
252
|
+
* <wr-date-picker #due [(value)]="due" format="dd.MM.yyyy" />
|
|
253
|
+
* @if (due.inputError(); as error) {
|
|
254
|
+
* <small>{{ error.message }}</small>
|
|
255
|
+
* }
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
readonly inputError: Signal<WrDateInputError | null>;
|
|
259
|
+
/**
|
|
260
|
+
* Blanked briefly so Enter on an unchanged refusal is announced again. A live region
|
|
261
|
+
* does not repeat text it already holds, and blanking it for one render is not
|
|
262
|
+
* enough: both changes land in the same task, and the accessibility tree sees
|
|
263
|
+
* only the end state. The gap is a timer for that reason — the CDK's
|
|
264
|
+
* `LiveAnnouncer` clears its region the same way.
|
|
265
|
+
*/
|
|
266
|
+
private readonly silenced;
|
|
267
|
+
private silenceTimer;
|
|
268
|
+
protected readonly statusId: string;
|
|
269
|
+
/**
|
|
270
|
+
* What the picker's own live region says: the refusal on show, unless a surrounding
|
|
271
|
+
* `<wr-form-field>` is already rendering a message for it — that message is a
|
|
272
|
+
* `role="alert"`, and a second voice would repeat it.
|
|
273
|
+
*/
|
|
274
|
+
protected readonly announcement: Signal<string>;
|
|
275
|
+
/**
|
|
276
|
+
* `aria-invalid` and `aria-describedby` for the text input, bound only with NO
|
|
277
|
+
* field around the picker. Inside one, `wrInput` writes both from the field — see
|
|
278
|
+
* `WrDateInputField` for why the picker feeds them through it rather than binding
|
|
279
|
+
* a second writer beside it.
|
|
280
|
+
*/
|
|
281
|
+
protected readonly ownAriaInvalid: Signal<"true" | null>;
|
|
282
|
+
protected readonly ownDescribedBy: Signal<string | null>;
|
|
283
|
+
protected readonly classes: Signal<string>;
|
|
142
284
|
private overlayRef;
|
|
143
285
|
/** Live calendar ref while the date popover is open — lets the panel track
|
|
144
286
|
* the typed value in real time (not just on reopen). */
|
|
@@ -164,7 +306,41 @@ declare class WrDatePicker implements FormValueControl<Date | null> {
|
|
|
164
306
|
* the text field silently moved the value to another day.
|
|
165
307
|
*/
|
|
166
308
|
private withKeptDate;
|
|
167
|
-
protected onBlur(): void;
|
|
309
|
+
protected onBlur(event: FocusEvent): void;
|
|
310
|
+
/**
|
|
311
|
+
* Enter is "this is the date". A date the picker committed is re-formatted
|
|
312
|
+
* canonical and the panel closes; text it refused turns invalid on the spot —
|
|
313
|
+
* border, `aria-invalid`, the reason announced — and emits `touch`, which is what
|
|
314
|
+
* makes a surrounding `<wr-form-field>` show its message. The panel closes in both
|
|
315
|
+
* cases: it opens directly below the field, which is exactly where that message
|
|
316
|
+
* renders.
|
|
317
|
+
*
|
|
318
|
+
* Never `preventDefault`: Enter inside a `<form>` still submits it, and a form
|
|
319
|
+
* bound to this picker is invalid while the refusal stands.
|
|
320
|
+
*/
|
|
321
|
+
private onEnter;
|
|
322
|
+
/** Show the committed value canonically, or commit an emptied field as `null`. */
|
|
323
|
+
private settleText;
|
|
324
|
+
/**
|
|
325
|
+
* Record why the current text was not committed, or that it was. Clearing a
|
|
326
|
+
* refusal also takes it off show, so the next one waits for Enter or blur again.
|
|
327
|
+
*/
|
|
328
|
+
private refuse;
|
|
329
|
+
/** Put a standing refusal on show — the user has left the field. */
|
|
330
|
+
private reveal;
|
|
331
|
+
/**
|
|
332
|
+
* The bound form was reset while the model stayed where it was — Angular has thrown
|
|
333
|
+
* the parse error away, so the text it was about goes too, and the field shows the
|
|
334
|
+
* value again. (A reset that MOVES the model reaches the text through the sync
|
|
335
|
+
* effect instead, like any other outside write.)
|
|
336
|
+
*/
|
|
337
|
+
private onFormReset;
|
|
338
|
+
/**
|
|
339
|
+
* Focus leaving the open panel. Moving within it, or back to the text field, is
|
|
340
|
+
* still the same visit; anywhere else — the page, the trigger, the next control — is
|
|
341
|
+
* leaving, so a refusal that waited while focus went into the panel shows now.
|
|
342
|
+
*/
|
|
343
|
+
private readonly onPaneFocusOut;
|
|
168
344
|
/** Called by the input's click — opens the overlay if it isn't open already. */
|
|
169
345
|
protected openOnInput(): void;
|
|
170
346
|
protected toggleOverlay(): void;
|
|
@@ -203,29 +379,16 @@ declare class WrDatePicker implements FormValueControl<Date | null> {
|
|
|
203
379
|
*/
|
|
204
380
|
private closeOverlay;
|
|
205
381
|
private dispose;
|
|
206
|
-
private
|
|
382
|
+
private outOfBounds;
|
|
207
383
|
private sameDate;
|
|
208
384
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrDatePicker, never>;
|
|
209
385
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrDatePicker, "wr-date-picker", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "dateFilter": { "alias": "dateFilter"; "required": false; "isSignal": true; }; "timeFormat": { "alias": "timeFormat"; "required": false; "isSignal": true; }; "showSeconds": { "alias": "showSeconds"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "panelAriaLabel": { "alias": "panelAriaLabel"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touch": "touch"; }, never, never, true, never>;
|
|
210
386
|
}
|
|
211
387
|
|
|
212
|
-
/**
|
|
213
|
-
* @license
|
|
214
|
-
*
|
|
215
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
216
|
-
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
217
|
-
*/
|
|
218
|
-
/**
|
|
219
|
-
* The `<wr-date-range-picker>` value — `[start, end]`.
|
|
220
|
-
*
|
|
221
|
-
* Either end can be `null` while the range is half-picked, so a partially
|
|
222
|
-
* filled range is still representable. Structurally identical to
|
|
223
|
-
* `WrCalendarRange`, which the picker forwards it to.
|
|
224
|
-
*/
|
|
225
|
-
type WrDateRange = readonly [Date | null, Date | null];
|
|
226
|
-
|
|
227
388
|
/** Which end of the range an edit applies to. */
|
|
228
389
|
type RangeEnd = 0 | 1;
|
|
390
|
+
/** One refusal per end, start first — `null` where that end's text is its date. */
|
|
391
|
+
type EndRefusals = readonly [WrDateInputError | null, WrDateInputError | null];
|
|
229
392
|
/**
|
|
230
393
|
* Date-range picker — two text inputs sharing one range calendar.
|
|
231
394
|
*
|
|
@@ -248,6 +411,10 @@ type RangeEnd = 0 | 1;
|
|
|
248
411
|
* Either end may be `null` while the range is half-picked. Out-of-order ends
|
|
249
412
|
* are swapped on commit, matching the calendar's own behaviour.
|
|
250
413
|
*
|
|
414
|
+
* Each end refuses text it cannot use exactly as `<wr-date-picker>` does — never
|
|
415
|
+
* guessing, keeping the text, and showing the refusal on Enter or when focus
|
|
416
|
+
* leaves that end. See {@link inputErrors}.
|
|
417
|
+
*
|
|
251
418
|
* @example
|
|
252
419
|
* ```html
|
|
253
420
|
* <!-- signal forms -->
|
|
@@ -322,9 +489,9 @@ declare class WrDateRangePicker implements FormValueControl<WrDateRange | null>
|
|
|
322
489
|
* simply reads as `ltr`.
|
|
323
490
|
*/
|
|
324
491
|
private readonly dir;
|
|
325
|
-
protected readonly startEl:
|
|
326
|
-
protected readonly endEl:
|
|
327
|
-
protected readonly triggerEl:
|
|
492
|
+
protected readonly startEl: Signal<ElementRef<HTMLInputElement>>;
|
|
493
|
+
protected readonly endEl: Signal<ElementRef<HTMLInputElement>>;
|
|
494
|
+
protected readonly triggerEl: Signal<ElementRef<HTMLButtonElement> | undefined>;
|
|
328
495
|
/** The picked range. Bound by `[formField]`, or two-way via `[(value)]`. */
|
|
329
496
|
readonly value: _angular_core.ModelSignal<WrDateRange | null>;
|
|
330
497
|
/** Emitted on blur so a bound field can mark itself touched. */
|
|
@@ -345,11 +512,11 @@ declare class WrDateRangePicker implements FormValueControl<WrDateRange | null>
|
|
|
345
512
|
/** Whether the panel this open cycle should take focus. */
|
|
346
513
|
private autoFocusPanel;
|
|
347
514
|
/** Resolved format — falls back to a mode-appropriate default. */
|
|
348
|
-
protected readonly resolvedFormat:
|
|
349
|
-
protected readonly isDateTime:
|
|
350
|
-
protected readonly triggerLabel:
|
|
351
|
-
protected readonly startLabel:
|
|
352
|
-
protected readonly endLabel:
|
|
515
|
+
protected readonly resolvedFormat: Signal<string>;
|
|
516
|
+
protected readonly isDateTime: Signal<boolean>;
|
|
517
|
+
protected readonly triggerLabel: Signal<string>;
|
|
518
|
+
protected readonly startLabel: Signal<string>;
|
|
519
|
+
protected readonly endLabel: Signal<string>;
|
|
353
520
|
private readonly panelLabelRange;
|
|
354
521
|
private readonly panelLabelRangeDateTime;
|
|
355
522
|
/**
|
|
@@ -361,8 +528,74 @@ declare class WrDateRangePicker implements FormValueControl<WrDateRange | null>
|
|
|
361
528
|
readonly panelAriaLabel: _angular_core.InputSignal<string | null>;
|
|
362
529
|
/** Popup id — what the trigger's `aria-controls` points at while open. */
|
|
363
530
|
protected readonly panelId: string;
|
|
364
|
-
protected readonly resolvedPanelLabel:
|
|
365
|
-
|
|
531
|
+
protected readonly resolvedPanelLabel: Signal<string>;
|
|
532
|
+
private readonly refusalBuilder;
|
|
533
|
+
private readonly reportToForm;
|
|
534
|
+
private readonly inputField;
|
|
535
|
+
/** Why each end's text was not committed. */
|
|
536
|
+
private readonly refusals;
|
|
537
|
+
/**
|
|
538
|
+
* Every refusal standing, on show or not, each marked with its end — what a bound form
|
|
539
|
+
* hears, from the keystroke.
|
|
540
|
+
*/
|
|
541
|
+
private readonly raised;
|
|
542
|
+
/**
|
|
543
|
+
* Which ends have their refusal on show — raised on the keystroke, shown on Enter
|
|
544
|
+
* or when focus leaves that end, for the reason `wr-date-picker` gives at the same
|
|
545
|
+
* name: a date is unreadable for most of the time it takes to type one. Leaving
|
|
546
|
+
* includes leaving by way of the open panel, as it does there.
|
|
547
|
+
*/
|
|
548
|
+
private readonly revealed;
|
|
549
|
+
protected readonly shownErrors: Signal<EndRefusals>;
|
|
550
|
+
/**
|
|
551
|
+
* Why the text in either field is not that end of the bound range, for the ends
|
|
552
|
+
* whose refusal the picker is SHOWING — one entry per end, marked with the `end` it
|
|
553
|
+
* came from, and empty while both fields hold their dates or the user is still
|
|
554
|
+
* typing.
|
|
555
|
+
*
|
|
556
|
+
* An end's refusal is raised on the keystroke and goes on show on Enter or when
|
|
557
|
+
* focus leaves that end — the moment its input turns invalid and the reason is
|
|
558
|
+
* announced, so a message rendered from this never disagrees with them. It clears
|
|
559
|
+
* the moment that end's text commits, is emptied, or is replaced by a pick from the
|
|
560
|
+
* panel, a value written from outside, or a form reset.
|
|
561
|
+
*
|
|
562
|
+
* A bound form does NOT wait: it sees every refusal as a parse error from the
|
|
563
|
+
* keystroke, so it is invalid the whole time either field holds text the picker
|
|
564
|
+
* could not use — including while the OTHER end commits — and `<wr-form-field>`
|
|
565
|
+
* shows `message` by its own rule. Read this through a template reference to put
|
|
566
|
+
* the reason on screen for a picker bound with `[(value)]` alone.
|
|
567
|
+
*/
|
|
568
|
+
readonly inputErrors: Signal<readonly WrDateRangeInputError[]>;
|
|
569
|
+
/**
|
|
570
|
+
* Blanked briefly so Enter on an unchanged refusal is announced again. A live region
|
|
571
|
+
* does not repeat text it already holds, and blanking it for one render is not
|
|
572
|
+
* enough: both changes land in the same task, and the accessibility tree sees
|
|
573
|
+
* only the end state. The gap is a timer for that reason — the CDK's
|
|
574
|
+
* `LiveAnnouncer` clears its region the same way.
|
|
575
|
+
*/
|
|
576
|
+
private readonly silenced;
|
|
577
|
+
private silenceTimer;
|
|
578
|
+
protected readonly statusId: string;
|
|
579
|
+
/**
|
|
580
|
+
* The live region's text: every refusal on show that a surrounding `<wr-form-field>`
|
|
581
|
+
* is not already rendering a message for, each sentence once.
|
|
582
|
+
*/
|
|
583
|
+
protected readonly announcement: Signal<string>;
|
|
584
|
+
/**
|
|
585
|
+
* `aria-invalid` / `aria-describedby` for each input, where the picker binds them.
|
|
586
|
+
*
|
|
587
|
+
* The START input reads a surrounding field through `wrInput`, so inside one the
|
|
588
|
+
* picker feeds its refusal through `WrDateInputField` rather than binding a second
|
|
589
|
+
* writer beside `wrInput`, and binds these only with no field around it. The END
|
|
590
|
+
* input is hidden from the field on purpose (see `wrDateRangeEnd`), so its `wrInput`
|
|
591
|
+
* never writes either attribute and the picker always owns them: an unreadable end
|
|
592
|
+
* date marks the end field, not only the start.
|
|
593
|
+
*/
|
|
594
|
+
protected readonly startAriaInvalid: Signal<"true" | null>;
|
|
595
|
+
protected readonly endAriaInvalid: Signal<"true" | null>;
|
|
596
|
+
protected readonly startDescribedBy: Signal<string | null>;
|
|
597
|
+
protected readonly endDescribedBy: Signal<string | null>;
|
|
598
|
+
protected readonly classes: Signal<string>;
|
|
366
599
|
private overlayRef;
|
|
367
600
|
/** Live panel ref while the popover is open — lets typed edits move the
|
|
368
601
|
* displayed month in real time (not just on reopen). */
|
|
@@ -374,6 +607,38 @@ declare class WrDateRangePicker implements FormValueControl<WrDateRange | null>
|
|
|
374
607
|
protected onStartInput(event: Event): void;
|
|
375
608
|
protected onEndInput(event: Event): void;
|
|
376
609
|
protected onBlur(event: FocusEvent): void;
|
|
610
|
+
/**
|
|
611
|
+
* Enter in either field is "this is the range". Committed ends are settled — sorted
|
|
612
|
+
* and re-formatted canonical — and the panel closes; a refused end turns invalid on
|
|
613
|
+
* the spot, and `touch` is emitted so a surrounding `<wr-form-field>` shows its
|
|
614
|
+
* message, which the panel would otherwise cover. Never `preventDefault`: Enter in a
|
|
615
|
+
* `<form>` still submits it, and a bound form is invalid while a refusal stands.
|
|
616
|
+
*/
|
|
617
|
+
private onEnter;
|
|
618
|
+
/** Put the refusals of the given ends on show; an end with no refusal stays clear. */
|
|
619
|
+
private reveal;
|
|
620
|
+
/**
|
|
621
|
+
* Record why one end's text was not committed, or that it was. Clearing a refusal
|
|
622
|
+
* takes it off show too, so the next one waits for Enter or blur again.
|
|
623
|
+
*/
|
|
624
|
+
private refuse;
|
|
625
|
+
/**
|
|
626
|
+
* Put the refusals on show for wherever focus has gone: back into one field leaves
|
|
627
|
+
* the OTHER end, and anywhere outside the pair leaves both.
|
|
628
|
+
*/
|
|
629
|
+
private revealFor;
|
|
630
|
+
/**
|
|
631
|
+
* The bound form was reset while the model stayed where it was — Angular has thrown
|
|
632
|
+
* the parse errors away, so the text they were about goes too, and both fields show
|
|
633
|
+
* the range again. (A reset that MOVES the model reaches the text through the sync
|
|
634
|
+
* effect, like any other outside write.)
|
|
635
|
+
*/
|
|
636
|
+
private onFormReset;
|
|
637
|
+
/**
|
|
638
|
+
* Focus leaving the open panel. Moving within it is the same visit; anywhere else has
|
|
639
|
+
* left whichever end focus is not going back to — see {@link revealFor}.
|
|
640
|
+
*/
|
|
641
|
+
private readonly onPaneFocusOut;
|
|
377
642
|
/** Called by an input's click — opens the overlay if it isn't open already. */
|
|
378
643
|
protected openOnInput(end: RangeEnd): void;
|
|
379
644
|
protected toggleOverlay(): void;
|
|
@@ -432,11 +697,11 @@ declare class WrDateRangePicker implements FormValueControl<WrDateRange | null>
|
|
|
432
697
|
*/
|
|
433
698
|
private compareEnds;
|
|
434
699
|
/**
|
|
435
|
-
*
|
|
436
|
-
* bounds — the calendar disables filtered days, so accepting them from the
|
|
700
|
+
* Why a typed date must be rejected, or `null`. Covers `dateFilter` as well as
|
|
701
|
+
* the bounds — the calendar disables filtered days, so accepting them from the
|
|
437
702
|
* keyboard would make the two entry paths disagree.
|
|
438
703
|
*/
|
|
439
|
-
private
|
|
704
|
+
private outOfBounds;
|
|
440
705
|
private sameDate;
|
|
441
706
|
/**
|
|
442
707
|
* `null` and `[null, null]` are the same VALUE — an empty range — and treating
|
|
@@ -453,4 +718,4 @@ declare class WrDateRangePicker implements FormValueControl<WrDateRange | null>
|
|
|
453
718
|
}
|
|
454
719
|
|
|
455
720
|
export { WrDatePicker, WrDateRangePicker };
|
|
456
|
-
export type { WrDateRange };
|
|
721
|
+
export type { WrDateInputError, WrDateRange, WrDateRangeInputError };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as ngwr_popover from 'ngwr/popover';
|
|
1
2
|
import * as _angular_core from '@angular/core';
|
|
2
3
|
|
|
3
4
|
interface WrDonutSegment {
|
|
@@ -39,6 +40,13 @@ declare class WrDonutChart {
|
|
|
39
40
|
readonly centerValue: _angular_core.InputSignal<string>;
|
|
40
41
|
/** Smaller label under the value. */
|
|
41
42
|
readonly centerLabel: _angular_core.InputSignal<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Show a tooltip with the slice's label and value on hover. Pointer only — the
|
|
45
|
+
* legend prints the same numbers, and with `showLegend` off `ariaLabel` is where
|
|
46
|
+
* to say them. @default true
|
|
47
|
+
*/
|
|
48
|
+
readonly tooltip: _angular_core.InputSignalWithTransform<boolean, any>;
|
|
49
|
+
private readonly svg;
|
|
42
50
|
private readonly outerR;
|
|
43
51
|
protected readonly innerR: _angular_core.Signal<number>;
|
|
44
52
|
protected readonly total: _angular_core.Signal<number>;
|
|
@@ -49,11 +57,26 @@ declare class WrDonutChart {
|
|
|
49
57
|
color: string;
|
|
50
58
|
path: string;
|
|
51
59
|
percent: number;
|
|
60
|
+
midAngle: number;
|
|
52
61
|
}[]>;
|
|
62
|
+
/**
|
|
63
|
+
* One tooltip for the whole chart, pointing at the hovered slice: at the middle of
|
|
64
|
+
* its OUTER arc, on the side that part of the ring faces — above for a slice whose
|
|
65
|
+
* middle is in the top quarter, below for the bottom one, beside it for the two at
|
|
66
|
+
* three and nine o'clock. From there the chip sits clear of the ring, and the way
|
|
67
|
+
* onto it runs straight out of the slice that opened it, over nothing else.
|
|
68
|
+
*
|
|
69
|
+
* Not the slice's `<path>` element: its box is most of the ring for any slice past
|
|
70
|
+
* a quarter, so the chip would point at the middle of the chart. And not the middle
|
|
71
|
+
* of the band: a chip there lies over the ring, under a pointer resting on it —
|
|
72
|
+
* measured in Chromium, the inner half of a lower slice landed on its own chip. A
|
|
73
|
+
* tiny slice keeps its own mid-angle, so the arrow says which sliver it is.
|
|
74
|
+
*/
|
|
75
|
+
protected readonly tip: ngwr_popover.WrChartTooltip;
|
|
53
76
|
/** SVG path for one donut slice using outer and inner arcs. */
|
|
54
77
|
private arcPath;
|
|
55
78
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrDonutChart, never>;
|
|
56
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrDonutChart, "wr-donut-chart", never, { "segments": { "alias": "segments"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "thickness": { "alias": "thickness"; "required": false; "isSignal": true; }; "showLegend": { "alias": "showLegend"; "required": false; "isSignal": true; }; "centerValue": { "alias": "centerValue"; "required": false; "isSignal": true; }; "centerLabel": { "alias": "centerLabel"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
79
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrDonutChart, "wr-donut-chart", never, { "segments": { "alias": "segments"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "thickness": { "alias": "thickness"; "required": false; "isSignal": true; }; "showLegend": { "alias": "showLegend"; "required": false; "isSignal": true; }; "centerValue": { "alias": "centerValue"; "required": false; "isSignal": true; }; "centerLabel": { "alias": "centerLabel"; "required": false; "isSignal": true; }; "tooltip": { "alias": "tooltip"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
57
80
|
}
|
|
58
81
|
|
|
59
82
|
export { WrDonutChart };
|
package/types/ngwr-dropdown.d.ts
CHANGED
|
@@ -58,8 +58,28 @@ declare class WrDropdown {
|
|
|
58
58
|
readonly menu: _angular_core.InputSignal<WrDropdownMenu>;
|
|
59
59
|
/** How the menu opens. @default 'click' */
|
|
60
60
|
readonly trigger: _angular_core.InputSignal<WrDropdownTrigger>;
|
|
61
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Where the menu anchors relative to the trigger. A placement that does not
|
|
63
|
+
* fit flips to the opposite side (a `left` / `right` menu may also drop below
|
|
64
|
+
* or above, and then stays there until it closes), and the pane's
|
|
65
|
+
* `wr-dropdown-overlay--<placement>` class names the side it actually took.
|
|
66
|
+
* @default 'bottom-start'
|
|
67
|
+
*/
|
|
62
68
|
readonly position: _angular_core.InputSignal<WrDropdownPosition>;
|
|
69
|
+
/**
|
|
70
|
+
* Draw a small arrow on the menu's edge, pointing at the trigger — the one
|
|
71
|
+
* `wr-popover` and `wr-popconfirm` draw, from the same shared rule. It follows
|
|
72
|
+
* the placement the menu actually took, so a flipped menu points the right
|
|
73
|
+
* way, and it widens the gap to the trigger from 0.25rem to popover's 0.5rem
|
|
74
|
+
* so the tip does not touch the control.
|
|
75
|
+
*
|
|
76
|
+
* Never drawn on a bottom sheet (`responsive`), which is anchored to nothing.
|
|
77
|
+
* Turn it off on a menu with no padding of its own (`--wr-dropdown-padding: 0`)
|
|
78
|
+
* or one that clips its overflow: the square reaches about 3px inside the
|
|
79
|
+
* menu's border, over the first row, and `overflow` cuts its tip off.
|
|
80
|
+
* Read when the menu opens. @default true
|
|
81
|
+
*/
|
|
82
|
+
readonly arrow: _angular_core.InputSignalWithTransform<boolean, any>;
|
|
63
83
|
/**
|
|
64
84
|
* Present the menu as a full-width bottom-sheet on small viewports instead
|
|
65
85
|
* of an anchored panel. `undefined` follows the app-wide
|
|
@@ -161,7 +181,7 @@ declare class WrDropdown {
|
|
|
161
181
|
private focusItemAt;
|
|
162
182
|
private readonly onOverlayMouseLeave;
|
|
163
183
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrDropdown, never>;
|
|
164
|
-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrDropdown, "[wrDropdown]", ["wrDropdown"], { "menu": { "alias": "wrDropdown"; "required": true; "isSignal": true; }; "trigger": { "alias": "trigger"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; }, { "opened": "opened"; "closed": "closed"; }, never, never, true, never>;
|
|
184
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrDropdown, "[wrDropdown]", ["wrDropdown"], { "menu": { "alias": "wrDropdown"; "required": true; "isSignal": true; }; "trigger": { "alias": "trigger"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "arrow": { "alias": "arrow"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; }, { "opened": "opened"; "closed": "closed"; }, never, never, true, never>;
|
|
165
185
|
}
|
|
166
186
|
|
|
167
187
|
/**
|
|
@@ -126,6 +126,11 @@ interface DayCell {
|
|
|
126
126
|
interface MonthWeek {
|
|
127
127
|
readonly key: string;
|
|
128
128
|
readonly days: readonly DayCell[];
|
|
129
|
+
/**
|
|
130
|
+
* How many lanes the row's chips fill. The chips are absolutely positioned,
|
|
131
|
+
* so this is the only way the row's height can know about them.
|
|
132
|
+
*/
|
|
133
|
+
readonly lanes: number;
|
|
129
134
|
}
|
|
130
135
|
interface TimeCell {
|
|
131
136
|
readonly key: string;
|
|
@@ -291,6 +296,8 @@ declare class WrEventCalendar {
|
|
|
291
296
|
bands: readonly BandChip[];
|
|
292
297
|
}[]>;
|
|
293
298
|
protected readonly hasAllDay: _angular_core.Signal<boolean>;
|
|
299
|
+
/** Lanes the all-day band fills — it has no `maxLanes` cap, so its row has to grow instead. */
|
|
300
|
+
protected readonly allDayLanes: _angular_core.Signal<number>;
|
|
294
301
|
protected readonly rows: _angular_core.Signal<readonly TimeRow[]>;
|
|
295
302
|
protected step(direction: -1 | 1): void;
|
|
296
303
|
protected goToday(): void;
|
|
@@ -323,6 +330,7 @@ declare class WrEventCalendar {
|
|
|
323
330
|
* the cell can say how much it is hiding.
|
|
324
331
|
*/
|
|
325
332
|
private bandLayout;
|
|
333
|
+
private laneCount;
|
|
326
334
|
/**
|
|
327
335
|
* Column layout inside one day: events that overlap in time share the width.
|
|
328
336
|
* Clusters are built by a running high-water mark — a new cluster starts the
|
package/types/ngwr-form.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { InjectionToken, Signal, EnvironmentProviders } from '@angular/core';
|
|
3
|
-
import
|
|
4
|
-
import { NgControl } from '@angular/forms';
|
|
2
|
+
import { InjectionToken, Signal, AfterContentChecked, EnvironmentProviders } from '@angular/core';
|
|
3
|
+
import { NgControl, ValidationErrors } from '@angular/forms';
|
|
5
4
|
import * as _angular_forms_signals from '@angular/forms/signals';
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -153,7 +152,7 @@ declare class WrFormError {
|
|
|
153
152
|
*
|
|
154
153
|
* @see https://ngwr.dev/reference/components/form-field
|
|
155
154
|
*/
|
|
156
|
-
declare class WrFormField implements WrFormFieldContext {
|
|
155
|
+
declare class WrFormField implements WrFormFieldContext, AfterContentChecked {
|
|
157
156
|
/** Label text shown above the control. */
|
|
158
157
|
readonly label: _angular_core.InputSignal<string>;
|
|
159
158
|
/** Hint text shown below the control. Hidden when an error is visible. */
|
|
@@ -205,10 +204,41 @@ declare class WrFormField implements WrFormFieldContext {
|
|
|
205
204
|
* Angular does expose, so the computed depends on this counter instead.
|
|
206
205
|
* Signal Forms needs none of this — its interop getters read live signals —
|
|
207
206
|
* and harmlessly contributes no events.
|
|
207
|
+
*
|
|
208
|
+
* Events are not the whole story, which is what {@link ngAfterContentChecked} is for.
|
|
208
209
|
*/
|
|
209
210
|
private readonly revision;
|
|
211
|
+
/** What the last check saw on a reactive control — see {@link ngAfterContentChecked}. */
|
|
212
|
+
private seen;
|
|
213
|
+
/**
|
|
214
|
+
* Catch the changes a reactive control makes WITHOUT an event.
|
|
215
|
+
*
|
|
216
|
+
* `updateValueAndValidity({ emitEvent: false })`, `markAsTouched({ emitEvent: false })`
|
|
217
|
+
* and their siblings change `errors`, `touched` and `dirty` and emit nothing, so the
|
|
218
|
+
* subscription above never hears them and the message stays whatever it was. That is
|
|
219
|
+
* not only an app's own silent write: Angular reports a custom control's PARSE errors
|
|
220
|
+
* to a `FormControl` exactly that way — a validator re-run with `emitEvent: false` —
|
|
221
|
+
* so a `wr-date-picker` refusing typed text made its control invalid while the field
|
|
222
|
+
* went on showing the message from before, or nothing — and a later pass of change
|
|
223
|
+
* detection did not help, because the message was memoised on a revision only events
|
|
224
|
+
* move.
|
|
225
|
+
*
|
|
226
|
+
* This runs whenever the view holding the field is checked, which is when the page
|
|
227
|
+
* around the control changes — for the date picker, the moment its refusal turns
|
|
228
|
+
* visible. It is `ngAfterContentChecked` and not `ngDoCheck` for an ordering reason
|
|
229
|
+
* read out of Angular's `refreshView`: check hooks run BEFORE the view's effects, and
|
|
230
|
+
* Angular's parse-error validator is re-run from an effect in that same view, so a
|
|
231
|
+
* `DoCheck` saw the errors one pass late and lost the message whenever nothing
|
|
232
|
+
* refreshed the view again. Content-checked hooks run after those effects and before
|
|
233
|
+
* the field's own bindings. Only a change moves the revision.
|
|
234
|
+
*
|
|
235
|
+
* Signal Forms' interop control is skipped: it is reactive already, and its `errors`
|
|
236
|
+
* getter builds a fresh object on every read, which a reference check would call a
|
|
237
|
+
* change on every pass — and re-resolve every message with it.
|
|
238
|
+
*/
|
|
239
|
+
ngAfterContentChecked(): void;
|
|
210
240
|
constructor();
|
|
211
|
-
protected readonly errors: _angular_core.Signal<
|
|
241
|
+
protected readonly errors: _angular_core.Signal<ValidationErrors | null>;
|
|
212
242
|
protected readonly hasError: _angular_core.Signal<boolean>;
|
|
213
243
|
/** @internal Read by the projected `<wr-form-error>` children to decide which of them renders. */
|
|
214
244
|
readonly errorKeys: _angular_core.Signal<readonly string[]>;
|