ngwr 13.0.0 → 14.0.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/README.md +13 -6
- package/color-picker/styles/_index.scss +43 -5
- package/fesm2022/ngwr-alert.mjs +5 -5
- package/fesm2022/ngwr-alert.mjs.map +1 -1
- package/fesm2022/ngwr-back-top.mjs +11 -1
- package/fesm2022/ngwr-back-top.mjs.map +1 -1
- package/fesm2022/ngwr-blur-text.mjs +13 -2
- package/fesm2022/ngwr-blur-text.mjs.map +1 -1
- package/fesm2022/ngwr-border-glow.mjs +12 -3
- package/fesm2022/ngwr-border-glow.mjs.map +1 -1
- package/fesm2022/ngwr-breadcrumbs.mjs +14 -3
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ngwr-button.mjs +4 -4
- package/fesm2022/ngwr-button.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-testing.mjs +15 -0
- package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
- package/fesm2022/ngwr-calendar.mjs +51 -5
- package/fesm2022/ngwr-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-circular-text.mjs +20 -1
- package/fesm2022/ngwr-circular-text.mjs.map +1 -1
- package/fesm2022/ngwr-collapse.mjs.map +1 -1
- package/fesm2022/ngwr-color-picker-testing.mjs +23 -7
- package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-color-picker.mjs +89 -10
- package/fesm2022/ngwr-color-picker.mjs.map +1 -1
- package/fesm2022/ngwr-command-palette.mjs +27 -3
- package/fesm2022/ngwr-command-palette.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu.mjs +13 -3
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-date-adapters-fns.mjs +101 -33
- package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker-testing.mjs +10 -2
- package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker.mjs +103 -13
- package/fesm2022/ngwr-date-picker.mjs.map +1 -1
- package/fesm2022/ngwr-date.mjs +480 -79
- package/fesm2022/ngwr-date.mjs.map +1 -1
- package/fesm2022/ngwr-dialog.mjs +22 -16
- package/fesm2022/ngwr-dialog.mjs.map +1 -1
- package/fesm2022/ngwr-directives.mjs +5 -2
- package/fesm2022/ngwr-directives.mjs.map +1 -1
- package/fesm2022/ngwr-drag-drop.mjs +30 -2
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-drawer.mjs +24 -18
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +8 -3
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar.mjs +1 -1
- package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-file-upload.mjs +52 -12
- package/fesm2022/ngwr-file-upload.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text.mjs +21 -4
- package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
- package/fesm2022/ngwr-gradient-text.mjs +9 -2
- package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +63 -1
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +28 -1
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-i18n.mjs +150 -22
- package/fesm2022/ngwr-i18n.mjs.map +1 -1
- package/fesm2022/ngwr-icon-adapters-feather.mjs +11 -0
- package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
- package/fesm2022/ngwr-icon-adapters-lucide.mjs +22 -2
- package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
- package/fesm2022/ngwr-icon.mjs +474 -37
- package/fesm2022/ngwr-icon.mjs.map +1 -1
- package/fesm2022/ngwr-input-number.mjs +3 -3
- package/fesm2022/ngwr-input-number.mjs.map +1 -1
- package/fesm2022/ngwr-input-otp.mjs +21 -3
- package/fesm2022/ngwr-input-otp.mjs.map +1 -1
- package/fesm2022/ngwr-input.mjs +14 -7
- package/fesm2022/ngwr-input.mjs.map +1 -1
- package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
- package/fesm2022/ngwr-knob.mjs +20 -2
- package/fesm2022/ngwr-knob.mjs.map +1 -1
- package/fesm2022/ngwr-loading-bar-router.mjs +73 -0
- package/fesm2022/ngwr-loading-bar-router.mjs.map +1 -0
- package/fesm2022/ngwr-loading-bar.mjs +21 -32
- package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
- package/fesm2022/ngwr-markdown.mjs +63 -11
- package/fesm2022/ngwr-markdown.mjs.map +1 -1
- package/fesm2022/ngwr-mention.mjs +104 -14
- package/fesm2022/ngwr-mention.mjs.map +1 -1
- package/fesm2022/ngwr-overlay.mjs +36 -7
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-pagination-testing.mjs +11 -10
- package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
- package/fesm2022/ngwr-pagination.mjs +65 -30
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-popconfirm.mjs +3 -2
- package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +2 -1
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-qr.mjs +38 -1
- package/fesm2022/ngwr-qr.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +93 -34
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text.mjs +10 -3
- package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
- package/fesm2022/ngwr-splitter-testing.mjs.map +1 -1
- package/fesm2022/ngwr-squircle.mjs +2 -1
- package/fesm2022/ngwr-squircle.mjs.map +1 -1
- package/fesm2022/ngwr-statistic.mjs +35 -4
- package/fesm2022/ngwr-statistic.mjs.map +1 -1
- package/fesm2022/ngwr-table.mjs +35 -12
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs-router.mjs +158 -0
- package/fesm2022/ngwr-tabs-router.mjs.map +1 -0
- package/fesm2022/ngwr-tabs-testing.mjs +13 -11
- package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +104 -12
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-textarea.mjs +20 -1
- package/fesm2022/ngwr-textarea.mjs.map +1 -1
- package/fesm2022/ngwr-tour.mjs +1 -1
- package/fesm2022/ngwr-tour.mjs.map +1 -1
- package/fesm2022/ngwr-transfer.mjs +2 -2
- package/fesm2022/ngwr-transfer.mjs.map +1 -1
- package/fesm2022/ngwr-tree.mjs +18 -2
- package/fesm2022/ngwr-tree.mjs.map +1 -1
- package/fesm2022/ngwr-utils.mjs +143 -1
- package/fesm2022/ngwr-utils.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/fesm2022/ngwr-window-testing.mjs +10 -2
- package/fesm2022/ngwr-window-testing.mjs.map +1 -1
- package/fesm2022/ngwr-window.mjs +4 -4
- package/fesm2022/ngwr-window.mjs.map +1 -1
- package/i18n/en.json +33 -6
- package/i18n/ru.json +33 -6
- package/llms-full.txt +20 -11
- package/llms.txt +47 -16
- package/mcp/catalog.js +3 -3
- package/mcp/providers.js +11 -0
- package/package.json +11 -3
- package/schematics/migrations/v13/index.js +101 -0
- package/schematics/migrations/v14/index.js +422 -0
- package/schematics/migrations.json +10 -0
- package/schematics/page/templates.js +1 -1
- package/schematics/use/symbol-map.json +1 -0
- package/skills/ngwr/SKILL.md +4 -1
- package/skills/ngwr/references/catalog.md +2 -0
- package/skills/ngwr/references/setup.md +4 -0
- package/stepper/styles/_index.scss +19 -1
- package/textarea/styles/_index.scss +14 -6
- package/toast/styles/_index.scss +12 -4
- package/types/ngwr-alert.d.ts +3 -3
- package/types/ngwr-blur-text.d.ts +8 -0
- package/types/ngwr-breadcrumbs.d.ts +1 -0
- package/types/ngwr-button.d.ts +2 -2
- package/types/ngwr-calendar-testing.d.ts +21 -4
- package/types/ngwr-calendar.d.ts +37 -0
- package/types/ngwr-circular-text.d.ts +9 -0
- package/types/ngwr-collapse.d.ts +19 -15
- package/types/ngwr-color-picker-testing.d.ts +10 -4
- package/types/ngwr-color-picker.d.ts +70 -2
- package/types/ngwr-command-palette.d.ts +14 -0
- package/types/ngwr-context-menu.d.ts +1 -1
- package/types/ngwr-date-adapters-fns.d.ts +71 -29
- package/types/ngwr-date-picker-testing.d.ts +206 -185
- package/types/ngwr-date-picker.d.ts +7 -0
- package/types/ngwr-date.d.ts +143 -13
- package/types/ngwr-drag-drop.d.ts +19 -0
- package/types/ngwr-dropdown.d.ts +1 -1
- package/types/ngwr-event-calendar-testing.d.ts +12 -9
- package/types/ngwr-file-upload.d.ts +31 -3
- package/types/ngwr-fuzzy-text.d.ts +5 -0
- package/types/ngwr-i18n.d.ts +89 -7
- package/types/ngwr-icon-adapters-feather.d.ts +11 -0
- package/types/ngwr-icon.d.ts +42 -1
- package/types/ngwr-input-number.d.ts +1 -1
- package/types/ngwr-input-otp.d.ts +3 -0
- package/types/ngwr-input.d.ts +11 -4
- package/types/ngwr-knob-testing.d.ts +8 -4
- package/types/ngwr-knob.d.ts +18 -0
- package/types/ngwr-loading-bar-router.d.ts +35 -0
- package/types/ngwr-loading-bar.d.ts +19 -9
- package/types/ngwr-mention.d.ts +13 -0
- package/types/ngwr-pagination-testing.d.ts +11 -10
- package/types/ngwr-pagination.d.ts +39 -10
- package/types/ngwr-popconfirm.d.ts +1 -1
- package/types/ngwr-popover.d.ts +1 -1
- package/types/ngwr-select.d.ts +65 -10
- package/types/ngwr-shiny-text.d.ts +1 -0
- package/types/ngwr-splitter-testing.d.ts +9 -4
- package/types/ngwr-squircle.d.ts +1 -1
- package/types/ngwr-statistic.d.ts +22 -2
- package/types/ngwr-table.d.ts +24 -5
- package/types/ngwr-tabs-router.d.ts +67 -0
- package/types/ngwr-tabs-testing.d.ts +12 -10
- package/types/ngwr-tabs.d.ts +103 -6
- package/types/ngwr-textarea.d.ts +9 -0
- package/types/ngwr-tree.d.ts +7 -0
- package/types/ngwr-utils.d.ts +79 -1
- package/types/ngwr-version.d.ts +1 -1
- package/types/ngwr-window-testing.d.ts +11 -3
- package/types/ngwr-window.d.ts +11 -4
- package/window/styles/_index.scss +1 -1
|
@@ -1,83 +1,6 @@
|
|
|
1
1
|
import { WrCalendarDayHarness } from 'ngwr/calendar/testing';
|
|
2
2
|
export { WrCalendarDayHarness as WrDatePickerDayHarness } from 'ngwr/calendar/testing';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @license
|
|
7
|
-
*
|
|
8
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
9
|
-
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/** Narrows which `<wr-date-picker>` a harness query matches. */
|
|
13
|
-
interface WrDatePickerHarnessFilters extends BaseHarnessFilters {
|
|
14
|
-
/**
|
|
15
|
-
* Match the text the field is showing — the formatted value, or `''` when the
|
|
16
|
-
* picker is empty and the placeholder is up. A string is an exact match, a
|
|
17
|
-
* RegExp is tested.
|
|
18
|
-
*/
|
|
19
|
-
readonly text?: string | RegExp;
|
|
20
|
-
/** Match the field's placeholder — a string is an exact match, a RegExp is tested. */
|
|
21
|
-
readonly placeholder?: string | RegExp;
|
|
22
|
-
/** Match one mode only. */
|
|
23
|
-
readonly mode?: 'date' | 'time' | 'datetime';
|
|
24
|
-
/** Match only enabled (`false`) or only disabled (`true`) pickers. */
|
|
25
|
-
readonly disabled?: boolean;
|
|
26
|
-
/** Match only pickers whose popup is up (`true`) or down (`false`). */
|
|
27
|
-
readonly open?: boolean;
|
|
28
|
-
}
|
|
29
|
-
/** Narrows which `<wr-date-range-picker>` a harness query matches. */
|
|
30
|
-
interface WrDateRangePickerHarnessFilters extends BaseHarnessFilters {
|
|
31
|
-
/** Match the text in the START field. A string is an exact match, a RegExp is tested. */
|
|
32
|
-
readonly startText?: string | RegExp;
|
|
33
|
-
/** Match the text in the END field. A string is an exact match, a RegExp is tested. */
|
|
34
|
-
readonly endText?: string | RegExp;
|
|
35
|
-
/** Match one mode only. The range picker has no `time` mode. */
|
|
36
|
-
readonly mode?: 'date' | 'datetime';
|
|
37
|
-
/** Match only enabled (`false`) or only disabled (`true`) pickers. */
|
|
38
|
-
readonly disabled?: boolean;
|
|
39
|
-
/** Match only pickers whose popup is up (`true`) or down (`false`). */
|
|
40
|
-
readonly open?: boolean;
|
|
41
|
-
}
|
|
42
|
-
/** Narrows which day cell inside a picker's calendar a harness query matches. */
|
|
43
|
-
interface WrDatePickerDayHarnessFilters extends BaseHarnessFilters {
|
|
44
|
-
/**
|
|
45
|
-
* Match the cell's day number as rendered (`'1'` … `'31'`). A string is an
|
|
46
|
-
* exact match, a RegExp is tested — note the grid spills into the neighbouring
|
|
47
|
-
* months, so a number appears twice on most months.
|
|
48
|
-
*/
|
|
49
|
-
readonly text?: string | RegExp;
|
|
50
|
-
/** Match only selected (`true`) or only unselected (`false`) cells. */
|
|
51
|
-
readonly selected?: boolean;
|
|
52
|
-
/** Match only enabled (`false`) or only disabled (`true`) cells. */
|
|
53
|
-
readonly disabled?: boolean;
|
|
54
|
-
/**
|
|
55
|
-
* Match cells strictly BETWEEN the two ends of a picked range — the ends
|
|
56
|
-
* themselves are `selected`, not `inRange`. Always `false` for
|
|
57
|
-
* `<wr-date-picker>`, whose calendar has a single value.
|
|
58
|
-
*/
|
|
59
|
-
readonly inRange?: boolean;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @license
|
|
64
|
-
*
|
|
65
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
66
|
-
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
67
|
-
*/
|
|
68
|
-
/**
|
|
69
|
-
* Which boxes of a time stepper to type into. Omitted fields are left alone, so
|
|
70
|
-
* `{ minutes: 45 }` changes the minutes and nothing else.
|
|
71
|
-
*
|
|
72
|
-
* Hours are given the way the stepper SHOWS them: 0-23 for a 24-hour panel,
|
|
73
|
-
* 1-12 for a 12-hour one (where AM/PM stays where it was — flip it with
|
|
74
|
-
* `toggleMeridiem()`).
|
|
75
|
-
*/
|
|
76
|
-
interface WrDatePickerTimeFields {
|
|
77
|
-
readonly hours?: number;
|
|
78
|
-
readonly minutes?: number;
|
|
79
|
-
readonly seconds?: number;
|
|
80
|
-
}
|
|
3
|
+
import { ComponentHarness, TestElement, HarnessLoader, HarnessPredicate, BaseHarnessFilters } from '@angular/cdk/testing';
|
|
81
4
|
|
|
82
5
|
/**
|
|
83
6
|
* @license
|
|
@@ -155,8 +78,16 @@ declare class WrTimePanelHarness extends ComponentHarness {
|
|
|
155
78
|
* their popup's id through the trigger's `aria-controls`, so the scoping story is
|
|
156
79
|
* shared too.
|
|
157
80
|
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
81
|
+
* **Deliberately not exported, and `WrAnyDatePickerHarness` is what replaces it.**
|
|
82
|
+
* The reason a consumer wanted this name was to write a helper taking "either
|
|
83
|
+
* picker", which the union in `interfaces/` says directly and without publishing
|
|
84
|
+
* anything else. Exporting the class instead would publish the `protected` members
|
|
85
|
+
* below as a subclassing contract — including `timePanels()`, which hands back the
|
|
86
|
+
* harness for `<wr-time-panel>`, a component this package does not ship as public
|
|
87
|
+
* API. A type-only re-export is not the middle ground it looks like: the base is a
|
|
88
|
+
* value in two `extends` clauses, so d.ts flattening promotes `export type` back to
|
|
89
|
+
* a value export while the FESM bundle exports nothing — an import that type-checks
|
|
90
|
+
* and is `undefined` at runtime.
|
|
160
91
|
*
|
|
161
92
|
* @internal
|
|
162
93
|
*/
|
|
@@ -258,6 +189,200 @@ declare abstract class WrDatePickerHarnessBase extends ComponentHarness {
|
|
|
258
189
|
private noCalendar;
|
|
259
190
|
}
|
|
260
191
|
|
|
192
|
+
/**
|
|
193
|
+
* @license
|
|
194
|
+
*
|
|
195
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
196
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Test harness for `<wr-date-range-picker>` — two text fields over one range
|
|
201
|
+
* calendar.
|
|
202
|
+
*
|
|
203
|
+
* A separate harness rather than a mode of {@link WrDatePickerHarness}, because
|
|
204
|
+
* the DOM a spec has to reach is genuinely different: two fields with a separator
|
|
205
|
+
* between them, and in `datetime` mode two time steppers instead of one. Every
|
|
206
|
+
* call that could mean either field takes an explicit `'start'` / `'end'` — the
|
|
207
|
+
* component's own bugs were nearly all "which end did that belong to", and a
|
|
208
|
+
* harness that guessed would reproduce them.
|
|
209
|
+
*
|
|
210
|
+
* The popup, the calendar and the scoping work exactly as they do for the single
|
|
211
|
+
* picker: a pane in the overlay container, addressed by the id the trigger
|
|
212
|
+
* publishes as `aria-controls`.
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```ts
|
|
216
|
+
* const period = await loader.getHarness(WrDateRangePickerHarness);
|
|
217
|
+
*
|
|
218
|
+
* await period.open();
|
|
219
|
+
* await period.selectDay(14);
|
|
220
|
+
* await period.selectDay(20);
|
|
221
|
+
*
|
|
222
|
+
* expect([await period.getStartText(), await period.getEndText()]).toEqual(['14.01.2025', '20.01.2025']);
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* @see https://ngwr.dev/guides/testing
|
|
226
|
+
*/
|
|
227
|
+
declare class WrDateRangePickerHarness extends WrDatePickerHarnessBase {
|
|
228
|
+
static hostSelector: string;
|
|
229
|
+
/** Build a predicate that narrows the query. */
|
|
230
|
+
static with(options?: WrDateRangePickerHarnessFilters): HarnessPredicate<WrDateRangePickerHarness>;
|
|
231
|
+
protected readonly harnessName = "WrDateRangePickerHarness";
|
|
232
|
+
/** Which mode the picker is in, read from the `wr-date-range-picker--*` modifier. */
|
|
233
|
+
getMode(): Promise<'date' | 'datetime'>;
|
|
234
|
+
/** What the start field is showing — `''` while that end is unpicked. */
|
|
235
|
+
getStartText(): Promise<string>;
|
|
236
|
+
/** What the end field is showing — `''` while that end is unpicked. */
|
|
237
|
+
getEndText(): Promise<string>;
|
|
238
|
+
/** The glyph rendered between the two fields (`[separator]`, `'–'` by default). */
|
|
239
|
+
getSeparator(): Promise<string>;
|
|
240
|
+
/** The placeholder of one field. */
|
|
241
|
+
getPlaceholder(end: WrDateRangePickerEnd): Promise<string>;
|
|
242
|
+
/**
|
|
243
|
+
* Type a date into the start field, replacing whatever is there.
|
|
244
|
+
*
|
|
245
|
+
* Ends typed out of order are NOT swapped here — the component settles the
|
|
246
|
+
* ordering when the interaction is over, so call {@link blur} (or close the
|
|
247
|
+
* popup) to see a normalised range.
|
|
248
|
+
*/
|
|
249
|
+
setStartText(text: string): Promise<void>;
|
|
250
|
+
/** Type a date into the end field — see {@link setStartText} on ordering. */
|
|
251
|
+
setEndText(text: string): Promise<void>;
|
|
252
|
+
/** Empty both fields, which clears the range. Neither end has a clear button. */
|
|
253
|
+
clear(): Promise<void>;
|
|
254
|
+
/** Whether the picker refuses interaction. */
|
|
255
|
+
isDisabled(): Promise<boolean>;
|
|
256
|
+
/**
|
|
257
|
+
* Whether the fields refuse typing. Stricter than `<wr-date-picker>`: a
|
|
258
|
+
* read-only range picker also refuses to open, since two fields over one
|
|
259
|
+
* calendar leaves no reading of "untypeable" that still lets the grid rewrite
|
|
260
|
+
* both ends.
|
|
261
|
+
*/
|
|
262
|
+
isReadonly(): Promise<boolean>;
|
|
263
|
+
/** Move focus to one field. */
|
|
264
|
+
focus(end: WrDateRangePickerEnd): Promise<void>;
|
|
265
|
+
/**
|
|
266
|
+
* Blur one field. This is the moment an out-of-order range is put back in
|
|
267
|
+
* order, and — when focus leaves the control rather than hopping to the other
|
|
268
|
+
* end — the moment `touch` is emitted.
|
|
269
|
+
*/
|
|
270
|
+
blur(end: WrDateRangePickerEnd): Promise<void>;
|
|
271
|
+
/** Whether one field currently has focus. */
|
|
272
|
+
isFocused(end: WrDateRangePickerEnd): Promise<boolean>;
|
|
273
|
+
/**
|
|
274
|
+
* One end's time stepper as `HH:MM`, plus `:SS` when `showSeconds` is on and
|
|
275
|
+
* ` AM`/` PM` in 12-hour mode. `datetime` mode only.
|
|
276
|
+
*/
|
|
277
|
+
getTime(end: WrDateRangePickerEnd): Promise<string>;
|
|
278
|
+
/** Type into one end's time stepper. Omitted fields are left alone. */
|
|
279
|
+
setTime(end: WrDateRangePickerEnd, fields: WrDatePickerTimeFields): Promise<void>;
|
|
280
|
+
/** Click one of an end's ▲ / ▼ buttons. Minutes and seconds move by `step`. */
|
|
281
|
+
stepTime(end: WrDateRangePickerEnd, unit: 'hours' | 'minutes' | 'seconds', direction: 1 | -1): Promise<void>;
|
|
282
|
+
/** Flip one end between AM and PM. Throws in 24-hour mode, which has no such control. */
|
|
283
|
+
toggleMeridiem(end: WrDateRangePickerEnd): Promise<void>;
|
|
284
|
+
private type;
|
|
285
|
+
/** The two fields are addressed by position, which is the order they render in. */
|
|
286
|
+
private field;
|
|
287
|
+
/**
|
|
288
|
+
* One end's stepper. Both are mounted together in `datetime` mode, start first —
|
|
289
|
+
* the group labels are localized, so position is the addressable thing.
|
|
290
|
+
*/
|
|
291
|
+
private timePanel;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* @license
|
|
296
|
+
*
|
|
297
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
298
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
299
|
+
*/
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Either picker harness, for a consumer's own helper that does not care which —
|
|
303
|
+
* `async function pickToday(picker: WrAnyDatePickerHarness)`. Both classes extend
|
|
304
|
+
* one abstract base, but that base is not exported and is not going to be: it
|
|
305
|
+
* would publish its `protected` plumbing, and a `<wr-time-panel>` harness for a
|
|
306
|
+
* component this package keeps internal, as a subclassing contract. A union says
|
|
307
|
+
* the only part anyone asked for.
|
|
308
|
+
*/
|
|
309
|
+
type WrAnyDatePickerHarness = WrDatePickerHarness | WrDateRangePickerHarness;
|
|
310
|
+
/**
|
|
311
|
+
* Which end of a range a `WrDateRangePickerHarness` call applies to. Every call
|
|
312
|
+
* that could mean either field takes one, and it is exported so a consumer's own
|
|
313
|
+
* helper can forward it rather than re-declaring the union.
|
|
314
|
+
*/
|
|
315
|
+
type WrDateRangePickerEnd = 'start' | 'end';
|
|
316
|
+
/** Narrows which `<wr-date-picker>` a harness query matches. */
|
|
317
|
+
interface WrDatePickerHarnessFilters extends BaseHarnessFilters {
|
|
318
|
+
/**
|
|
319
|
+
* Match the text the field is showing — the formatted value, or `''` when the
|
|
320
|
+
* picker is empty and the placeholder is up. A string is an exact match, a
|
|
321
|
+
* RegExp is tested.
|
|
322
|
+
*/
|
|
323
|
+
readonly text?: string | RegExp;
|
|
324
|
+
/** Match the field's placeholder — a string is an exact match, a RegExp is tested. */
|
|
325
|
+
readonly placeholder?: string | RegExp;
|
|
326
|
+
/** Match one mode only. */
|
|
327
|
+
readonly mode?: 'date' | 'time' | 'datetime';
|
|
328
|
+
/** Match only enabled (`false`) or only disabled (`true`) pickers. */
|
|
329
|
+
readonly disabled?: boolean;
|
|
330
|
+
/** Match only pickers whose popup is up (`true`) or down (`false`). */
|
|
331
|
+
readonly open?: boolean;
|
|
332
|
+
}
|
|
333
|
+
/** Narrows which `<wr-date-range-picker>` a harness query matches. */
|
|
334
|
+
interface WrDateRangePickerHarnessFilters extends BaseHarnessFilters {
|
|
335
|
+
/** Match the text in the START field. A string is an exact match, a RegExp is tested. */
|
|
336
|
+
readonly startText?: string | RegExp;
|
|
337
|
+
/** Match the text in the END field. A string is an exact match, a RegExp is tested. */
|
|
338
|
+
readonly endText?: string | RegExp;
|
|
339
|
+
/** Match one mode only. The range picker has no `time` mode. */
|
|
340
|
+
readonly mode?: 'date' | 'datetime';
|
|
341
|
+
/** Match only enabled (`false`) or only disabled (`true`) pickers. */
|
|
342
|
+
readonly disabled?: boolean;
|
|
343
|
+
/** Match only pickers whose popup is up (`true`) or down (`false`). */
|
|
344
|
+
readonly open?: boolean;
|
|
345
|
+
}
|
|
346
|
+
/** Narrows which day cell inside a picker's calendar a harness query matches. */
|
|
347
|
+
interface WrDatePickerDayHarnessFilters extends BaseHarnessFilters {
|
|
348
|
+
/**
|
|
349
|
+
* Match the cell's day number as rendered (`'1'` … `'31'`). A string is an
|
|
350
|
+
* exact match, a RegExp is tested — note the grid spills into the neighbouring
|
|
351
|
+
* months, so a number appears twice on most months.
|
|
352
|
+
*/
|
|
353
|
+
readonly text?: string | RegExp;
|
|
354
|
+
/** Match only selected (`true`) or only unselected (`false`) cells. */
|
|
355
|
+
readonly selected?: boolean;
|
|
356
|
+
/** Match only enabled (`false`) or only disabled (`true`) cells. */
|
|
357
|
+
readonly disabled?: boolean;
|
|
358
|
+
/**
|
|
359
|
+
* Match cells strictly BETWEEN the two ends of a picked range — the ends
|
|
360
|
+
* themselves are `selected`, not `inRange`. Always `false` for
|
|
361
|
+
* `<wr-date-picker>`, whose calendar has a single value.
|
|
362
|
+
*/
|
|
363
|
+
readonly inRange?: boolean;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* @license
|
|
368
|
+
*
|
|
369
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
370
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
371
|
+
*/
|
|
372
|
+
/**
|
|
373
|
+
* Which boxes of a time stepper to type into. Omitted fields are left alone, so
|
|
374
|
+
* `{ minutes: 45 }` changes the minutes and nothing else.
|
|
375
|
+
*
|
|
376
|
+
* Hours are given the way the stepper SHOWS them: 0-23 for a 24-hour panel,
|
|
377
|
+
* 1-12 for a 12-hour one (where AM/PM stays where it was — flip it with
|
|
378
|
+
* `toggleMeridiem()`).
|
|
379
|
+
*/
|
|
380
|
+
interface WrDatePickerTimeFields {
|
|
381
|
+
readonly hours?: number;
|
|
382
|
+
readonly minutes?: number;
|
|
383
|
+
readonly seconds?: number;
|
|
384
|
+
}
|
|
385
|
+
|
|
261
386
|
/**
|
|
262
387
|
* @license
|
|
263
388
|
*
|
|
@@ -355,109 +480,5 @@ declare class WrDatePickerHarness extends WrDatePickerHarnessBase {
|
|
|
355
480
|
private timePanel;
|
|
356
481
|
}
|
|
357
482
|
|
|
358
|
-
/**
|
|
359
|
-
* @license
|
|
360
|
-
*
|
|
361
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
362
|
-
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
363
|
-
*/
|
|
364
|
-
|
|
365
|
-
/** Which end of the range a call applies to. */
|
|
366
|
-
type End = 'start' | 'end';
|
|
367
|
-
/**
|
|
368
|
-
* Test harness for `<wr-date-range-picker>` — two text fields over one range
|
|
369
|
-
* calendar.
|
|
370
|
-
*
|
|
371
|
-
* A separate harness rather than a mode of {@link WrDatePickerHarness}, because
|
|
372
|
-
* the DOM a spec has to reach is genuinely different: two fields with a separator
|
|
373
|
-
* between them, and in `datetime` mode two time steppers instead of one. Every
|
|
374
|
-
* call that could mean either field takes an explicit `'start'` / `'end'` — the
|
|
375
|
-
* component's own bugs were nearly all "which end did that belong to", and a
|
|
376
|
-
* harness that guessed would reproduce them.
|
|
377
|
-
*
|
|
378
|
-
* The popup, the calendar and the scoping work exactly as they do for the single
|
|
379
|
-
* picker: a pane in the overlay container, addressed by the id the trigger
|
|
380
|
-
* publishes as `aria-controls`.
|
|
381
|
-
*
|
|
382
|
-
* @example
|
|
383
|
-
* ```ts
|
|
384
|
-
* const period = await loader.getHarness(WrDateRangePickerHarness);
|
|
385
|
-
*
|
|
386
|
-
* await period.open();
|
|
387
|
-
* await period.selectDay(14);
|
|
388
|
-
* await period.selectDay(20);
|
|
389
|
-
*
|
|
390
|
-
* expect([await period.getStartText(), await period.getEndText()]).toEqual(['14.01.2025', '20.01.2025']);
|
|
391
|
-
* ```
|
|
392
|
-
*
|
|
393
|
-
* @see https://ngwr.dev/guides/testing
|
|
394
|
-
*/
|
|
395
|
-
declare class WrDateRangePickerHarness extends WrDatePickerHarnessBase {
|
|
396
|
-
static hostSelector: string;
|
|
397
|
-
/** Build a predicate that narrows the query. */
|
|
398
|
-
static with(options?: WrDateRangePickerHarnessFilters): HarnessPredicate<WrDateRangePickerHarness>;
|
|
399
|
-
protected readonly harnessName = "WrDateRangePickerHarness";
|
|
400
|
-
/** Which mode the picker is in, read from the `wr-date-range-picker--*` modifier. */
|
|
401
|
-
getMode(): Promise<'date' | 'datetime'>;
|
|
402
|
-
/** What the start field is showing — `''` while that end is unpicked. */
|
|
403
|
-
getStartText(): Promise<string>;
|
|
404
|
-
/** What the end field is showing — `''` while that end is unpicked. */
|
|
405
|
-
getEndText(): Promise<string>;
|
|
406
|
-
/** The glyph rendered between the two fields (`[separator]`, `'–'` by default). */
|
|
407
|
-
getSeparator(): Promise<string>;
|
|
408
|
-
/** The placeholder of one field. */
|
|
409
|
-
getPlaceholder(end: End): Promise<string>;
|
|
410
|
-
/**
|
|
411
|
-
* Type a date into the start field, replacing whatever is there.
|
|
412
|
-
*
|
|
413
|
-
* Ends typed out of order are NOT swapped here — the component settles the
|
|
414
|
-
* ordering when the interaction is over, so call {@link blur} (or close the
|
|
415
|
-
* popup) to see a normalised range.
|
|
416
|
-
*/
|
|
417
|
-
setStartText(text: string): Promise<void>;
|
|
418
|
-
/** Type a date into the end field — see {@link setStartText} on ordering. */
|
|
419
|
-
setEndText(text: string): Promise<void>;
|
|
420
|
-
/** Empty both fields, which clears the range. Neither end has a clear button. */
|
|
421
|
-
clear(): Promise<void>;
|
|
422
|
-
/** Whether the picker refuses interaction. */
|
|
423
|
-
isDisabled(): Promise<boolean>;
|
|
424
|
-
/**
|
|
425
|
-
* Whether the fields refuse typing. Stricter than `<wr-date-picker>`: a
|
|
426
|
-
* read-only range picker also refuses to open, since two fields over one
|
|
427
|
-
* calendar leaves no reading of "untypeable" that still lets the grid rewrite
|
|
428
|
-
* both ends.
|
|
429
|
-
*/
|
|
430
|
-
isReadonly(): Promise<boolean>;
|
|
431
|
-
/** Move focus to one field. */
|
|
432
|
-
focus(end: End): Promise<void>;
|
|
433
|
-
/**
|
|
434
|
-
* Blur one field. This is the moment an out-of-order range is put back in
|
|
435
|
-
* order, and — when focus leaves the control rather than hopping to the other
|
|
436
|
-
* end — the moment `touch` is emitted.
|
|
437
|
-
*/
|
|
438
|
-
blur(end: End): Promise<void>;
|
|
439
|
-
/** Whether one field currently has focus. */
|
|
440
|
-
isFocused(end: End): Promise<boolean>;
|
|
441
|
-
/**
|
|
442
|
-
* One end's time stepper as `HH:MM`, plus `:SS` when `showSeconds` is on and
|
|
443
|
-
* ` AM`/` PM` in 12-hour mode. `datetime` mode only.
|
|
444
|
-
*/
|
|
445
|
-
getTime(end: End): Promise<string>;
|
|
446
|
-
/** Type into one end's time stepper. Omitted fields are left alone. */
|
|
447
|
-
setTime(end: End, fields: WrDatePickerTimeFields): Promise<void>;
|
|
448
|
-
/** Click one of an end's ▲ / ▼ buttons. Minutes and seconds move by `step`. */
|
|
449
|
-
stepTime(end: End, unit: 'hours' | 'minutes' | 'seconds', direction: 1 | -1): Promise<void>;
|
|
450
|
-
/** Flip one end between AM and PM. Throws in 24-hour mode, which has no such control. */
|
|
451
|
-
toggleMeridiem(end: End): Promise<void>;
|
|
452
|
-
private type;
|
|
453
|
-
/** The two fields are addressed by position, which is the order they render in. */
|
|
454
|
-
private field;
|
|
455
|
-
/**
|
|
456
|
-
* One end's stepper. Both are mounted together in `datetime` mode, start first —
|
|
457
|
-
* the group labels are localized, so position is the addressable thing.
|
|
458
|
-
*/
|
|
459
|
-
private timePanel;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
483
|
export { WrDatePickerHarness, WrDateRangePickerHarness };
|
|
463
|
-
export type { WrDatePickerDayHarnessFilters, WrDatePickerHarnessFilters, WrDatePickerTimeFields, WrDateRangePickerHarnessFilters };
|
|
484
|
+
export type { WrAnyDatePickerHarness, WrDatePickerDayHarnessFilters, WrDatePickerHarnessFilters, WrDatePickerTimeFields, WrDateRangePickerEnd, WrDateRangePickerHarnessFilters };
|
|
@@ -149,6 +149,13 @@ declare class WrDatePicker implements FormValueControl<Date | null> {
|
|
|
149
149
|
private lastFormat;
|
|
150
150
|
constructor();
|
|
151
151
|
protected onInput(event: Event): void;
|
|
152
|
+
/**
|
|
153
|
+
* In `time` mode the typed string carries no date, so the adapter fills one in — and
|
|
154
|
+
* the date already in the model is the better answer than whatever default it picks.
|
|
155
|
+
* The time PANEL has always worked this way (it keeps a `basis` date across edits);
|
|
156
|
+
* the text field silently moved the value to another day.
|
|
157
|
+
*/
|
|
158
|
+
private withKeptDate;
|
|
152
159
|
protected onBlur(): void;
|
|
153
160
|
/** Called by the input's click — opens the overlay if it isn't open already. */
|
|
154
161
|
protected openOnInput(): void;
|
package/types/ngwr-date.d.ts
CHANGED
|
@@ -97,12 +97,24 @@ declare abstract class WrDateAdapter<TDate = Date> {
|
|
|
97
97
|
* adapter resolves locale-aware) or a raw format string (`'dd.MM.yyyy'`).
|
|
98
98
|
*
|
|
99
99
|
* Supported tokens for raw strings: `yyyy`, `yy`, `MMMM`, `MMM`, `MM`, `M`,
|
|
100
|
-
* `dd`, `d`, `HH`, `H`, `hh`, `h`, `mm`, `ss`, `a` (
|
|
100
|
+
* `dd`, `d`, `HH`, `H`, `hh`, `h`, `mm`, `ss`, `a` (the locale's day-period
|
|
101
|
+
* marker — `PM`, `م`, `午後`).
|
|
102
|
+
*
|
|
103
|
+
* `MMMM` / `MMM` take the form the language uses in the position the pattern
|
|
104
|
+
* puts them: beside a day token a case language declines the month (ru writes
|
|
105
|
+
* `15 марта`, not `15 март`), and on their own they stay nominative, which is
|
|
106
|
+
* what a calendar heading wants.
|
|
101
107
|
*/
|
|
102
108
|
abstract format(date: TDate, formatKeyOrString: WrDateFormat | (string & {})): string;
|
|
103
109
|
/**
|
|
104
110
|
* Parse a string into a date. Returns `null` when parsing fails. Accepts
|
|
105
111
|
* the same `formatKeyOrString` set as {@link format}.
|
|
112
|
+
*
|
|
113
|
+
* **The round trip is a contract, not an aspiration**: whatever {@link format}
|
|
114
|
+
* writes for a given key, `parse` reads back to the same date. A caller relies
|
|
115
|
+
* on it every keystroke — the picker re-parses what it printed — and returning
|
|
116
|
+
* `null` is how an adapter refuses, which leaves the caller's committed value
|
|
117
|
+
* exactly as it was.
|
|
106
118
|
*/
|
|
107
119
|
abstract parse(value: string, formatKeyOrString: WrDateFormat | (string & {})): TDate | null;
|
|
108
120
|
/** `0` Sunday, `1` Monday — locale-dependent. */
|
|
@@ -143,6 +155,22 @@ declare class WrNativeDateAdapter extends WrDateAdapter<Date> {
|
|
|
143
155
|
isSameMonth(a: Date, b: Date): boolean;
|
|
144
156
|
compareDate(a: Date, b: Date): number;
|
|
145
157
|
format(date: Date, formatKeyOrString: WrDateFormat | (string & {})): string;
|
|
158
|
+
/**
|
|
159
|
+
* Read back what {@link format} wrote.
|
|
160
|
+
*
|
|
161
|
+
* A named format used to delegate to `new Date(raw)`, which understands only
|
|
162
|
+
* Anglo-American forms — so the field could not read its own output anywhere else.
|
|
163
|
+
* `new Date('15.3.2026')` and `new Date('14:30')` are both `Invalid Date`, while
|
|
164
|
+
* `new Date('1')` is 1 January 2001: retyping a de-DE date committed the year 2001 on
|
|
165
|
+
* the first keystroke and then refused every one after it, and `mode="time"` collapsed
|
|
166
|
+
* to midnight in EVERY locale, en-US included. The named branch now builds its parser
|
|
167
|
+
* from the SAME `Intl.DateTimeFormat` that printed the string, so the round trip holds
|
|
168
|
+
* by construction rather than by luck.
|
|
169
|
+
*
|
|
170
|
+
* Returns `null` rather than a guess whenever the string does not match — the caller's
|
|
171
|
+
* committed value is then left exactly as it was, which is the contract
|
|
172
|
+
* `wr-input-number` follows for unparseable text.
|
|
173
|
+
*/
|
|
146
174
|
parse(value: string, formatKeyOrString: WrDateFormat | (string & {})): Date | null;
|
|
147
175
|
getFirstDayOfWeek(): number;
|
|
148
176
|
/**
|
|
@@ -156,11 +184,93 @@ declare class WrNativeDateAdapter extends WrDateAdapter<Date> {
|
|
|
156
184
|
* can be this simple.
|
|
157
185
|
*/
|
|
158
186
|
private readonly formatters;
|
|
187
|
+
/**
|
|
188
|
+
* Every `Intl` call this adapter makes pins `calendar: 'gregory'`, and that is a
|
|
189
|
+
* correctness fix rather than a preference.
|
|
190
|
+
*
|
|
191
|
+
* The value type is a JS `Date`, every accessor on this class (`getYear`,
|
|
192
|
+
* `getMonth`, `getDate`) is Gregorian, `createDate` builds a Gregorian date and the
|
|
193
|
+
* calendar grid draws Gregorian months. A locale whose DEFAULT calendar is something
|
|
194
|
+
* else — `fa-IR` resolves to `persian`, `th-TH` to `buddhist`, `ar-SA` to
|
|
195
|
+
* `islamic-umalqura` in several engines — printed a field the grid beside it could
|
|
196
|
+
* never agree with (`۱۴۰۴/۱۲/۲۴` over a grid headed 2026), and no parser can turn
|
|
197
|
+
* that back into the `Date` it came from. Pinning the calendar makes format and parse
|
|
198
|
+
* describe the same one.
|
|
199
|
+
*/
|
|
200
|
+
private intlOptions;
|
|
159
201
|
private intl;
|
|
160
202
|
getDayOfWeekNames(style: 'narrow' | 'short' | 'long'): readonly string[];
|
|
203
|
+
/**
|
|
204
|
+
* Month names in the STANDALONE (nominative) form — what a calendar heading wants.
|
|
205
|
+
* Inside a date the same name often declines; {@link monthNames} serves that form to
|
|
206
|
+
* the token formatter, and this method deliberately keeps the heading one.
|
|
207
|
+
*/
|
|
161
208
|
getMonthNames(style: 'narrow' | 'short' | 'long'): readonly string[];
|
|
209
|
+
private numeralsCache;
|
|
210
|
+
/** The locale's own ten digits, cached — empty when its system is algorithmic. */
|
|
211
|
+
private localeNumerals;
|
|
212
|
+
private dayPeriodCache;
|
|
213
|
+
/**
|
|
214
|
+
* `[am, pm]` as the LOCALE writes them — `PM`, `م`, `午後`.
|
|
215
|
+
*
|
|
216
|
+
* The `a` token used to return a hard-coded lowercase `pm`, byte for byte identical in
|
|
217
|
+
* every locale, which made it the one token in the pattern language that could not be
|
|
218
|
+
* localised at all. `Intl` is the source rather than the i18n catalog because
|
|
219
|
+
* `ngwr/date` deliberately depends on nothing: the panel next to it reads
|
|
220
|
+
* `datePicker.am` / `datePicker.pm`, so an app that wants its own wording overrides it
|
|
221
|
+
* there and passes a 24-hour pattern here.
|
|
222
|
+
*/
|
|
223
|
+
private dayPeriods;
|
|
224
|
+
private readonly monthNameCache;
|
|
225
|
+
/**
|
|
226
|
+
* `context: 'format'` asks `Intl` for the month name as it appears BESIDE A DAY, which
|
|
227
|
+
* is where a case language stops using the nominative: ru writes `15 марта`, not
|
|
228
|
+
* `15 март`, and fi writes `maaliskuuta`, not `maaliskuu`. The name comes out of a
|
|
229
|
+
* `{ day, month }` formatter's parts, because a `{ month }` formatter alone can only
|
|
230
|
+
* ever answer with the standalone form.
|
|
231
|
+
*
|
|
232
|
+
* Some locales write the month NUMERICALLY in that position — fi abbreviates `15.3.`,
|
|
233
|
+
* ja writes `3` with `月` as a separate literal — and there the standalone name is the
|
|
234
|
+
* only name there is, so a purely numeric answer falls back to it. Without that guard
|
|
235
|
+
* `dd MMMM yyyy` would render `15 3 2026` in Japanese.
|
|
236
|
+
*/
|
|
237
|
+
private monthNames;
|
|
238
|
+
/** Whether a token pattern also writes the day, which decides the month's form. */
|
|
239
|
+
private hasDayToken;
|
|
162
240
|
private formatWithTokens;
|
|
163
241
|
private parseWithTokens;
|
|
242
|
+
/**
|
|
243
|
+
* Build the parser for one named format out of the very formatter that prints it.
|
|
244
|
+
*
|
|
245
|
+
* `formatToParts` is the only honest source for a locale's field ORDER and its
|
|
246
|
+
* literals — ru writes `dd.MM.y` with a two-digit month while its own
|
|
247
|
+
* `{ month: 'numeric' }` request says one digit, ja puts the year first, and ar-SA
|
|
248
|
+
* separates fields with U+200F. Names (a month, AM/PM) become an alternation of the
|
|
249
|
+
* real strings; numbers accept the locale's digits AND ASCII, because a physical
|
|
250
|
+
* keyboard produces the latter whatever the display shows.
|
|
251
|
+
*
|
|
252
|
+
* Returns `null` — meaning "this format cannot be read back" — rather than guessing,
|
|
253
|
+
* for a field type nothing here asks for (an era, a weekday) or a numbering system
|
|
254
|
+
* with no digit-by-digit reading (roman numerals). `parse` then refuses, which leaves
|
|
255
|
+
* the caller's committed value untouched.
|
|
256
|
+
*/
|
|
257
|
+
private buildNamedParser;
|
|
258
|
+
/** The twelve month strings THIS formatter writes, in its own style and context. */
|
|
259
|
+
private namedMonthNames;
|
|
260
|
+
/** `[am, pm]` as THIS formatter writes them — `ص` / `م` in Arabic, not AM / PM. */
|
|
261
|
+
private dayPeriodNames;
|
|
262
|
+
private readonly namedParsers;
|
|
263
|
+
private parseNamed;
|
|
264
|
+
/**
|
|
265
|
+
* Assemble whatever was read into a `Date`, or refuse.
|
|
266
|
+
*
|
|
267
|
+
* `new Date(2025, 12, 45)` does not fail — it rolls forward into the next year — and
|
|
268
|
+
* `isValid` is happy with the result, so a text field used to turn nonsense into a
|
|
269
|
+
* confident wrong answer. The clock parts are range-checked directly; the month and the
|
|
270
|
+
* day are checked by comparing what came back, which catches every rollover including a
|
|
271
|
+
* month of 12 or -1.
|
|
272
|
+
*/
|
|
273
|
+
private compose;
|
|
164
274
|
static ɵfac: i0.ɵɵFactoryDeclaration<WrNativeDateAdapter, never>;
|
|
165
275
|
static ɵprov: i0.ɵɵInjectableDeclaration<WrNativeDateAdapter>;
|
|
166
276
|
}
|
|
@@ -176,12 +286,16 @@ declare class WrNativeDateAdapter extends WrDateAdapter<Date> {
|
|
|
176
286
|
* Register the date adapter and locale used by the calendar / date picker /
|
|
177
287
|
* time picker. Call once at bootstrap.
|
|
178
288
|
*
|
|
289
|
+
* Omit `locale` and dates follow Angular's `LOCALE_ID`, which is what the app
|
|
290
|
+
* already says it is. Pass one only to pin dates to something else — see
|
|
291
|
+
* {@link WR_DATE_LOCALE}, and `WrI18n` for how the three locale inputs rank.
|
|
292
|
+
*
|
|
179
293
|
* @example
|
|
180
294
|
* ```ts
|
|
181
295
|
* bootstrapApplication(AppComponent, {
|
|
182
296
|
* providers: [
|
|
183
|
-
* provideWrDateAdapter(), // native,
|
|
184
|
-
* // provideWrDateAdapter({ locale: 'ru-RU' }),
|
|
297
|
+
* provideWrDateAdapter(), // native adapter, LOCALE_ID
|
|
298
|
+
* // provideWrDateAdapter({ locale: 'ru-RU' }), // pin the dates
|
|
185
299
|
* // provideWrDateAdapter({ adapter: MyDateFnsAdapter, locale: 'fr' }),
|
|
186
300
|
* ],
|
|
187
301
|
* });
|
|
@@ -198,18 +312,34 @@ declare function provideWrDateAdapter(options?: WrDateAdapterOptions): Environme
|
|
|
198
312
|
|
|
199
313
|
/**
|
|
200
314
|
* BCP 47 locale tag the {@link WrDateAdapter} implementations read. Defaults to
|
|
201
|
-
* `
|
|
202
|
-
*
|
|
315
|
+
* Angular's `LOCALE_ID`; override via {@link provideWrDateAdapter}'s `locale`
|
|
316
|
+
* option.
|
|
317
|
+
*
|
|
318
|
+
* **It used to default to `navigator.language`, and that was wrong in the
|
|
319
|
+
* documented case.** The provider's own first example is the no-argument call,
|
|
320
|
+
* so the path a reader copies was the broken one: an app that set
|
|
321
|
+
* `LOCALE_ID: 'ru-RU'` and translated every string still rendered `March 2026`,
|
|
322
|
+
* `SUN MON TUE …` and a week starting on Sunday, because the calendar was
|
|
323
|
+
* asking the browser rather than the application. `navigator.language` is the
|
|
324
|
+
* user's browser preference; `LOCALE_ID` is what the app says it is, and only
|
|
325
|
+
* the app can be right about that. Reading the browser also made a prerendered
|
|
326
|
+
* page and its hydrated self disagree — the server has no `navigator.language`
|
|
327
|
+
* to match. An app that genuinely wants the browser's tag can still say so:
|
|
328
|
+
* `provideWrDateAdapter({ locale: navigator.language })`.
|
|
329
|
+
*
|
|
330
|
+
* The token is a plain string, resolved once. It is therefore the *pinned* date
|
|
331
|
+
* locale, not a live one — `WrI18n.use()` moves catalog text and cannot move
|
|
332
|
+
* this. `WrI18n`'s class docs carry the full precedence and `use()` warns about
|
|
333
|
+
* the gap in dev mode.
|
|
203
334
|
*
|
|
204
335
|
* **How far it reaches depends on the adapter, and the difference matters.**
|
|
205
|
-
* The luxon
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* lever (`setDefaultOptions`).
|
|
336
|
+
* The native and luxon adapters thread it through everything. The date-fns
|
|
337
|
+
* adapter cannot: date-fns resolves its patterns against a `Locale` OBJECT, not
|
|
338
|
+
* a tag, so this token drives only the parts that go through `Intl` (the month
|
|
339
|
+
* and weekday names) and the OBJECT drives `format` / `parse`. Pass it as
|
|
340
|
+
* `provideWrDateFnsAdapter({ dateFnsLocale: ru })` — with only a tag the calendar
|
|
341
|
+
* headings localize and the field does not, which the adapter warns about once
|
|
342
|
+
* in dev mode.
|
|
213
343
|
*/
|
|
214
344
|
declare const WR_DATE_LOCALE: InjectionToken<string>;
|
|
215
345
|
|
|
@@ -30,6 +30,10 @@ interface WrSortableReorderEvent<T> {
|
|
|
30
30
|
* handling of its own, so without this the component's only function was
|
|
31
31
|
* unreachable from a keyboard.
|
|
32
32
|
*
|
|
33
|
+
* Reading direction: a `horizontal` list follows the VISUAL order, so under
|
|
34
|
+
* `dir="rtl"` ArrowLeft moves the held row toward the higher index — the same
|
|
35
|
+
* rule `wr-slider` applies to its track. A vertical list never mirrors.
|
|
36
|
+
*
|
|
33
37
|
* What that does NOT answer is WCAG 2.5.7, which asks for a POINTER alternative
|
|
34
38
|
* to the drag. Click-to-pick-up is the obvious candidate and is not safe here:
|
|
35
39
|
* the CDK's drag-drop bundle installs no click suppressor of any kind, so the
|
|
@@ -78,6 +82,21 @@ declare class WrSortableList<T = unknown> {
|
|
|
78
82
|
readonly reorder: _angular_core.OutputEmitterRef<WrSortableReorderEvent<T>>;
|
|
79
83
|
protected readonly rowTemplate: _angular_core.Signal<TemplateRef<any>>;
|
|
80
84
|
private readonly injector;
|
|
85
|
+
/**
|
|
86
|
+
* Ambient reading direction, for the horizontal keyboard path only.
|
|
87
|
+
*
|
|
88
|
+
* Optional so a bare `TestBed` — or any consumer that never set a direction —
|
|
89
|
+
* needs no provider; `Directionality` is root-provided, so `null` only ever
|
|
90
|
+
* means "nobody asked", which is LTR. Nothing caches a direction-derived
|
|
91
|
+
* value: `isRtl()` is read inside the key handler, so a runtime flip needs no
|
|
92
|
+
* subscription to `Directionality.change`.
|
|
93
|
+
*
|
|
94
|
+
* The POINTER path already mirrors without this — `cdkDropList` injects
|
|
95
|
+
* `Directionality` itself and feeds it to `DropListRef.withDirection`, so a
|
|
96
|
+
* horizontal drag has always followed the visual order. The keyboard path was
|
|
97
|
+
* the half that did not, which is why the two disagreed.
|
|
98
|
+
*/
|
|
99
|
+
private readonly dir;
|
|
81
100
|
private readonly rowEls;
|
|
82
101
|
/** Index of the row the keyboard is holding, or `null` when nothing is held. */
|
|
83
102
|
protected readonly grabbedIndex: _angular_core.WritableSignal<number | null>;
|