ngwr 13.0.1 → 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-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 +7 -1
- 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-drag-drop.mjs +30 -2
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +2 -1
- 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-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-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-mention.mjs +104 -14
- package/fesm2022/ngwr-mention.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-select.mjs +93 -34
- package/fesm2022/ngwr-select.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 +98 -10
- 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 +37 -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 +9 -1
- 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-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-i18n.d.ts +89 -7
- 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-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 +33 -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
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
*
|
|
5
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
/**
|
|
10
|
+
* v13 to v14 migration. Two halves, and the split is deliberate.
|
|
11
|
+
*
|
|
12
|
+
* **It REWRITES the five renames**: on `<wr-alert>` from `closeable` to
|
|
13
|
+
* `closable`, on `<wr-table>` from `[totalItems]` to `[total]`, on
|
|
14
|
+
* `<wr-pagination>` from `[(currentPage)]` to `[(page)]`, from
|
|
15
|
+
* `isDisabledWhenLoading` to `disabledWhenLoading`, and the window
|
|
16
|
+
* `chromeSize` scale from `'compact' | 'normal'` to `'sm' | 'md'`. A rename is
|
|
17
|
+
* exactly what a codemod does well: the new name means what the old one meant,
|
|
18
|
+
* on the same element, and nothing about the app has to be understood to move it.
|
|
19
|
+
*
|
|
20
|
+
* **It REPORTS everything else.** Those need a decision a codemod cannot make
|
|
21
|
+
* correctly, and v10/v11 already establish the rule here — a migration that
|
|
22
|
+
* pretends to have handled something it has not is worse than none, because the
|
|
23
|
+
* silence reads as "nothing to do".
|
|
24
|
+
*
|
|
25
|
+
* **`wr-loading-bar`** no longer subscribes to the router on its own. Add
|
|
26
|
+
* `provideWrLoadingBarRouter()` from `ngwr/loading-bar/router` to your
|
|
27
|
+
* application providers. Without it the bar still works for manual
|
|
28
|
+
* `start()` / `complete()` and simply never moves for navigation — which is the
|
|
29
|
+
* dangerous shape, because nothing throws: this project's own site shipped a
|
|
30
|
+
* permanently-empty bar for the length of a release by missing exactly this.
|
|
31
|
+
* Not auto-fixed because the provider belongs in a bootstrap file this schematic
|
|
32
|
+
* cannot identify: `app.config.ts`, a `main.ts` calling `bootstrapApplication`,
|
|
33
|
+
* or a route-level `providers` array are all legitimate, and guessing wrong puts
|
|
34
|
+
* the subscription in the wrong injector.
|
|
35
|
+
*
|
|
36
|
+
* **`<wr-tab routerLink>`** needs `wrTabsRouting` on the strip and
|
|
37
|
+
* `WrTabsRouting` in the component's `imports`. This one at least fails loudly —
|
|
38
|
+
* the strip throws when a tab carries a `routerLink` and no adapter is present.
|
|
39
|
+
* Not auto-fixed because adding the attribute is only half of it: the class has
|
|
40
|
+
* to reach an `imports` array in a `.ts` file that this rule would have to match
|
|
41
|
+
* to the template by convention, and a template can be inline, external, or
|
|
42
|
+
* shared between components.
|
|
43
|
+
*
|
|
44
|
+
* **The locale sources were collapsed into one precedence**, and two defaults
|
|
45
|
+
* moved with it. `WR_DATE_LOCALE` used to default to `navigator.language`; it
|
|
46
|
+
* now defaults to Angular's `LOCALE_ID`, so `provideWrDateAdapter()` with no
|
|
47
|
+
* `locale` follows the application rather than the browser. `WrI18n`'s own
|
|
48
|
+
* default locale used to be the literal `'en'`; it is now `LOCALE_ID` as well,
|
|
49
|
+
* and `availableLocales` defaults to `[defaultLocale]` instead of `['en']`.
|
|
50
|
+
* Reported rather than rewritten for the usual reason: the fix, where one is
|
|
51
|
+
* wanted at all, is a value only the app knows — an app that really did want the
|
|
52
|
+
* browser's tag writes `provideWrDateAdapter({ locale: navigator.language })`,
|
|
53
|
+
* and one that really did want `'en'` writes it. A codemod cannot tell those
|
|
54
|
+
* from the majority for whom the new default is the answer they meant.
|
|
55
|
+
*
|
|
56
|
+
* **`<wr-pagination ofLabel>`** is gone. The "1–10 of 235" line is now ONE
|
|
57
|
+
* catalog template, `pagination.range`, with `{{from}}` / `{{to}}` /
|
|
58
|
+
* `{{total}}` placeholders — because an input for the word in the middle
|
|
59
|
+
* localised only the middle: the ASCII hyphen between the bounds and the
|
|
60
|
+
* operand order were both frozen in TypeScript, and several languages put the
|
|
61
|
+
* total first. Reported rather than rewritten for the reason the others are —
|
|
62
|
+
* the text moves out of a template into a catalog file this schematic cannot
|
|
63
|
+
* identify, and the sentence it becomes is a translation decision. A bound
|
|
64
|
+
* `[ofLabel]` fails the template type-check, so it cannot ship unnoticed; a
|
|
65
|
+
* static `ofLabel="…"` is the shape worth naming.
|
|
66
|
+
*
|
|
67
|
+
* Two more v14 changes are visible without being breaking API, and are called
|
|
68
|
+
* out here because a snapshot or a text assertion will catch them: the
|
|
69
|
+
* pagination range separates its bounds with an EN DASH and groups its three
|
|
70
|
+
* numbers per `LOCALE_ID` (`1–10 of 1,234`), and `<wr-statistic>` formats its
|
|
71
|
+
* delta through `Intl.NumberFormat` rather than interpolating the raw number,
|
|
72
|
+
* so a non-English locale sees its own digits, sign and decimal separator
|
|
73
|
+
* there — matching the value printed above it, which always did.
|
|
74
|
+
*
|
|
75
|
+
* **The five renames**, and why each one moved. `wr-alert` spelled its dismiss
|
|
76
|
+
* toggle `closeable` while `wr-drawer`, `WrDrawerOptions` and `WrDialogOptions`
|
|
77
|
+
* all spelled the same idea `closable` — and a bare attribute that matches no
|
|
78
|
+
* input raises no template error, so `<wr-alert closable>` and
|
|
79
|
+
* `<wr-drawer closeable>` both compiled to nothing at all. `wr-table` and
|
|
80
|
+
* `wr-pagination` disagreed about the two concepts they share: `totalItems` /
|
|
81
|
+
* `page` against `total` / `currentPage`, two components designed to sit on the
|
|
82
|
+
* same screen. `isDisabledWhenLoading` was the only `is`-prefixed input in the
|
|
83
|
+
* library, against thirty-nine plainly-named `disabled` inputs and no
|
|
84
|
+
* `isDisabled` anywhere; dropping the prefix leaves none at all. And
|
|
85
|
+
* `WrWindowChromeSize` was still `'compact' | 'normal'` — the exact vocabulary
|
|
86
|
+
* v8's density migration exists to retire, three majors after it landed.
|
|
87
|
+
*
|
|
88
|
+
* What the rename rules will NOT catch, because no regex can: a component class
|
|
89
|
+
* reading one of these off a `viewChild()` reference. Those are type errors on
|
|
90
|
+
* upgrade, which is the loud failure and needs no help. One quiet case is worth
|
|
91
|
+
* naming: `WrWindowHarness.getChromeSize()` now answers `'sm'` / `'md'`, so a
|
|
92
|
+
* test asserting `'compact'` fails as a wrong value rather than as a wrong type.
|
|
93
|
+
*
|
|
94
|
+
* Why the split happened at all: the subscription and the link directives are
|
|
95
|
+
* what pull `@angular/router` into the bundle. Measured on 13.0.0, in an app
|
|
96
|
+
* declaring no routes, `ngwr/loading-bar` cost 100.1 kB of which 67.9 kB was the
|
|
97
|
+
* router, against 2.4 kB of its own code; `ngwr/tabs` carried 75.6 kB of router.
|
|
98
|
+
* Both are now zero for an app that does not opt in.
|
|
99
|
+
*/
|
|
100
|
+
const IGNORE_DIRS = new Set(['node_modules', 'dist', '.git', '.cache', '.angular', 'coverage', '.next', '.nuxt']);
|
|
101
|
+
/**
|
|
102
|
+
* An open tag, up to and including the whitespace before some attribute.
|
|
103
|
+
* `[^>]*?` cannot cross a `>`, so a rename can never escape the element it is
|
|
104
|
+
* scoped to, however the tag wraps across lines.
|
|
105
|
+
*
|
|
106
|
+
* The anchor is `(?![-\w])` and NOT `\b`: a word boundary still matches at the
|
|
107
|
+
* front of a longer element name, which is how a v9-shaped rule would have
|
|
108
|
+
* renamed an attribute on `<wr-table-filter>` while claiming to touch only
|
|
109
|
+
* `<wr-table>`. Every one of these four has such a neighbour — `wr-table-filter`
|
|
110
|
+
* and `wr-table-sort`, `wr-window-container` and `wr-window-taskbar` — or would
|
|
111
|
+
* acquire one the moment the catalog grows.
|
|
112
|
+
*
|
|
113
|
+
* Quoted values are stepped over rather than excluded, and that is the half a
|
|
114
|
+
* plain `[^>]*?` gets wrong: a `>` inside a binding expression looks like the end
|
|
115
|
+
* of the tag, so `<wr-alert [type]="n > 0 ? 'a' : 'b'" closeable>` left
|
|
116
|
+
* `closeable` behind while the same attributes in the other order moved. The
|
|
117
|
+
* leftover is SILENT — a static `closeable` / `totalItems="42"` that matches no
|
|
118
|
+
* input is an ordinary DOM attribute and `strictTemplates` says nothing, so the
|
|
119
|
+
* alert quietly loses its dismiss button. (Bracketed forms are loud: NG8002.)
|
|
120
|
+
* `migration-v9` carries the same anchoring and the same hole.
|
|
121
|
+
*/
|
|
122
|
+
const openTag = (name) => String.raw `<${name}(?![-\w])(?:"[^"]*"|'[^']*'|[^>])*?\s`;
|
|
123
|
+
const ALERT = openTag('wr-alert');
|
|
124
|
+
const TABLE = openTag('wr-table');
|
|
125
|
+
const PAGER = openTag('wr-pagination');
|
|
126
|
+
const WINDOW = openTag('wr-window');
|
|
127
|
+
/**
|
|
128
|
+
* Template renames. Run over `.html` AND `.ts`, because an inline template is
|
|
129
|
+
* a string in a component file and is otherwise invisible to this.
|
|
130
|
+
*/
|
|
131
|
+
const HTML_TRANSFORMS = [
|
|
132
|
+
// <wr-alert closeable>, to closable. The bracketed form first: after it runs
|
|
133
|
+
// the bare rule cannot see what it rewrote, and the bare rule's lookahead
|
|
134
|
+
// (`[\s/>=]`) is what keeps it from matching the inside of a longer word.
|
|
135
|
+
{ pattern: new RegExp(`(${ALERT})\\[closeable\\]`, 'g'), replacement: '$1[closable]' },
|
|
136
|
+
{ pattern: new RegExp(`(${ALERT})closeable(?=[\\s/>=])`, 'g'), replacement: '$1closable' },
|
|
137
|
+
// `[wrInput]`'s size input drops its prefix. Anchored on the DIRECTIVE, not on
|
|
138
|
+
// an element, because it sits on a native `<input>` / `<textarea>` — and the
|
|
139
|
+
// anchor matters more here than anywhere else in this table: `size` is a legal
|
|
140
|
+
// native attribute, so rewriting one that was never ngwr's silently rebinds a
|
|
141
|
+
// character-width hint. The two orders are both real markup, hence two rules.
|
|
142
|
+
{
|
|
143
|
+
pattern: /(<(?:input|textarea)(?![-\w])(?:"[^"]*"|'[^']*'|[^>])*?\swrInput(?:"[^"]*"|'[^']*'|[^>])*?\s)\[wrSize\]/g,
|
|
144
|
+
replacement: '$1[size]',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
pattern: /(<(?:input|textarea)(?![-\w])(?:"[^"]*"|'[^']*'|[^>])*?\swrInput(?:"[^"]*"|'[^']*'|[^>])*?\s)wrSize=/g,
|
|
148
|
+
replacement: '$1size=',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
pattern: /(<(?:input|textarea)(?![-\w])(?:"[^"]*"|'[^']*'|[^>])*?\s)\[wrSize\]((?:"[^"]*"|'[^']*'|[^>])*?\swrInput)/g,
|
|
152
|
+
replacement: '$1[size]$2',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
pattern: /(<(?:input|textarea)(?![-\w])(?:"[^"]*"|'[^']*'|[^>])*?\s)wrSize=((?:"[^"]*"|'[^']*'|[^>])*?\swrInput)/g,
|
|
156
|
+
replacement: '$1size=$2',
|
|
157
|
+
},
|
|
158
|
+
// <wr-table>, from [totalItems] to [total]
|
|
159
|
+
{ pattern: new RegExp(`(${TABLE})\\[totalItems\\]`, 'g'), replacement: '$1[total]' },
|
|
160
|
+
{ pattern: new RegExp(`(${TABLE})totalItems=`, 'g'), replacement: '$1total=' },
|
|
161
|
+
// <wr-pagination>, from [(currentPage)] to [(page)], and the one-way pair with it.
|
|
162
|
+
{ pattern: new RegExp(`(${PAGER})\\[\\(currentPage\\)\\]`, 'g'), replacement: '$1[(page)]' },
|
|
163
|
+
{ pattern: new RegExp(`(${PAGER})\\(currentPageChange\\)`, 'g'), replacement: '$1(pageChange)' },
|
|
164
|
+
{ pattern: new RegExp(`(${PAGER})\\[currentPage\\]`, 'g'), replacement: '$1[page]' },
|
|
165
|
+
{ pattern: new RegExp(`(${PAGER})currentPage=`, 'g'), replacement: '$1page=' },
|
|
166
|
+
// <wr-window>, from chromeSize="compact" to "sm", bound literal included.
|
|
167
|
+
{ pattern: new RegExp(`(${WINDOW}chromeSize=")compact(")`, 'g'), replacement: '$1sm$2' },
|
|
168
|
+
{ pattern: new RegExp(`(${WINDOW}chromeSize=")normal(")`, 'g'), replacement: '$1md$2' },
|
|
169
|
+
{ pattern: new RegExp(`(${WINDOW}\\[chromeSize\\]=")'compact'(")`, 'g'), replacement: "$1'sm'$2" },
|
|
170
|
+
{ pattern: new RegExp(`(${WINDOW}\\[chromeSize\\]=")'normal'(")`, 'g'), replacement: "$1'md'$2" },
|
|
171
|
+
];
|
|
172
|
+
/** `.ts` only — object keys and a harness filter, neither of which is markup. */
|
|
173
|
+
const TS_TRANSFORMS = [
|
|
174
|
+
// WrWindowManager.open(Cmp, { chromeSize: 'compact' }) — the primary form,
|
|
175
|
+
// since a window is always a service call. Keyed on the property name rather
|
|
176
|
+
// than the element: there is no element in a `.ts` object literal to scope to,
|
|
177
|
+
// and `chromeSize` carrying one of exactly these two values is not a shape
|
|
178
|
+
// another library hands you by accident.
|
|
179
|
+
{ pattern: /(\bchromeSize\s*:\s*['"])compact(['"])/g, replacement: '$1sm$2' },
|
|
180
|
+
{ pattern: /(\bchromeSize\s*:\s*['"])normal(['"])/g, replacement: '$1md$2' },
|
|
181
|
+
// WrPaginationHarness.with({ currentPage: 3 }), to { page: 3 }. The filter is
|
|
182
|
+
// named after the input, so it moved with it. Scoped to the `with(` call —
|
|
183
|
+
// `currentPage` is far too ordinary a property name to rename on sight.
|
|
184
|
+
{ pattern: /(WrPaginationHarness\.with\(\s*\{[^}]*?\b)currentPage(\s*:)/g, replacement: '$1page$2' },
|
|
185
|
+
];
|
|
186
|
+
/**
|
|
187
|
+
* Renames safe ANYWHERE, in markup, TypeScript and stylesheets alike, because
|
|
188
|
+
* the string itself is unambiguous. `isDisabledWhenLoading` was the library's
|
|
189
|
+
* only `is`-prefixed input and appears nowhere else; `wr-window--chrome-compact`
|
|
190
|
+
* is a BEM class, which is public API here, so a consumer stylesheet overriding
|
|
191
|
+
* it has to move with the component.
|
|
192
|
+
*/
|
|
193
|
+
const GLOBAL_TRANSFORMS = [
|
|
194
|
+
{ pattern: /\bisDisabledWhenLoading\b/g, replacement: 'disabledWhenLoading' },
|
|
195
|
+
{ pattern: /\bwr-window--chrome-compact\b/g, replacement: 'wr-window--chrome-sm' },
|
|
196
|
+
// `--chrome-normal` too, even though the library never styled it: the class is
|
|
197
|
+
// emitted as `wr-window--chrome-${chromeSize()}`, so every default window in
|
|
198
|
+
// v13 carried it, BEM classes are public API here, and a consumer override
|
|
199
|
+
// keyed on it stops matching with no error — CSS does not have one.
|
|
200
|
+
{ pattern: /\bwr-window--chrome-normal\b/g, replacement: 'wr-window--chrome-md' },
|
|
201
|
+
];
|
|
202
|
+
/** `<wr-tab …>` carrying a `routerLink`, however the tag is wrapped across lines. */
|
|
203
|
+
const ROUTER_TAB = /<wr-tab\b[^>]*\brouterLink\b/;
|
|
204
|
+
const LOADING_BAR = /<wr-loading-bar\b/;
|
|
205
|
+
/** `provideWrDateAdapter(` with no `locale:` before the call closes. */
|
|
206
|
+
// `locale` as a key OR as shorthand, and the scan for it runs to the call's own
|
|
207
|
+
// closing brace rather than to the first `)`. The first version demanded a colon
|
|
208
|
+
// and could not cross a nested call, so it reported
|
|
209
|
+
// `provideWrDateAdapter({ locale })` — which the audit's own stand writes — and
|
|
210
|
+
// `provideWrDateAdapter({ adapter: mk(), locale: 'ru' })` as having no locale.
|
|
211
|
+
// Over-reporting is the gentler failure, but a warning that fires on the
|
|
212
|
+
// idiomatic form is a warning people learn to skip.
|
|
213
|
+
const DATE_ADAPTER_NO_LOCALE = /\bprovideWrDateAdapter\(\s*(?:\)|\{(?![\s\S]*?\blocale\s*[,:}]))/;
|
|
214
|
+
/** `provideWrI18n(` with no `defaultLocale:` before the call closes. */
|
|
215
|
+
const I18N_NO_DEFAULT_LOCALE = /\bprovideWrI18n\(\s*(?:\)|\{(?![^})]*\bdefaultLocale\s*:))/;
|
|
216
|
+
const DEFAULT_CONFIG = /\bDEFAULT_WR_I18N_CONFIG\b/;
|
|
217
|
+
/** `ofLabel` on a pagination tag, bound (`[ofLabel]`) or static. */
|
|
218
|
+
const OF_LABEL = /<wr-pagination\b[^>]*\[?ofLabel\]?\s*=/;
|
|
219
|
+
// The half `OF_LABEL` cannot see. Apps that never bound the input still
|
|
220
|
+
// translated the key, and `pagination.of` is gone: the range is one
|
|
221
|
+
// `pagination.range` template now, so a catalog that defines the old key loses
|
|
222
|
+
// its translation with nothing said. Markup detection misses every one of them,
|
|
223
|
+
// which is why this looks at the catalog instead.
|
|
224
|
+
const REMOVED_KEY = /['"`]?\bof['"`]?\s*:\s*['"`]/;
|
|
225
|
+
const PAGINATION_SCOPE = /\bpagination\s*:\s*\{/g;
|
|
226
|
+
/**
|
|
227
|
+
* Every `pagination: { … }` object literal in a file, brace-matched and
|
|
228
|
+
* QUOTE-AWARE — and it has to be both, because the first version was neither.
|
|
229
|
+
*
|
|
230
|
+
* It sliced to `content.indexOf('}')`, and the shipped catalog carries
|
|
231
|
+
* `perPage: '{{size}} / page'` two lines ABOVE `of`, so the slice ended inside
|
|
232
|
+
* `{{size` and the scan never reached the key it exists to find. The detector
|
|
233
|
+
* therefore answered "clean" for the one shape that actually occurs — a
|
|
234
|
+
* consumer catalog copied from ngwr's own — and green for the toy literal in
|
|
235
|
+
* its spec, `pagination: { of: 'von' }`, where `of` comes first and no
|
|
236
|
+
* placeholder precedes it. A warning that only fires on a shape nobody writes
|
|
237
|
+
* is the silent half of a silent change.
|
|
238
|
+
*
|
|
239
|
+
* All of them rather than the first, since one file commonly holds several
|
|
240
|
+
* locales.
|
|
241
|
+
*/
|
|
242
|
+
function paginationBlocks(content) {
|
|
243
|
+
const blocks = [];
|
|
244
|
+
PAGINATION_SCOPE.lastIndex = 0;
|
|
245
|
+
for (let scope = PAGINATION_SCOPE.exec(content); scope; scope = PAGINATION_SCOPE.exec(content)) {
|
|
246
|
+
// The `{` the match ends on.
|
|
247
|
+
const start = scope.index + scope[0].length - 1;
|
|
248
|
+
let depth = 0;
|
|
249
|
+
let quote = null;
|
|
250
|
+
for (let i = start; i < content.length; i += 1) {
|
|
251
|
+
const char = content[i];
|
|
252
|
+
if (quote !== null) {
|
|
253
|
+
if (char === '\\')
|
|
254
|
+
i += 1;
|
|
255
|
+
else if (char === quote)
|
|
256
|
+
quote = null;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (char === "'" || char === '"' || char === '`') {
|
|
260
|
+
quote = char;
|
|
261
|
+
}
|
|
262
|
+
else if (char === '{') {
|
|
263
|
+
depth += 1;
|
|
264
|
+
}
|
|
265
|
+
else if (char === '}') {
|
|
266
|
+
depth -= 1;
|
|
267
|
+
if (depth === 0) {
|
|
268
|
+
blocks.push(content.slice(start, i + 1));
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return blocks;
|
|
275
|
+
}
|
|
276
|
+
function ngUpdateV14() {
|
|
277
|
+
return (tree, context) => {
|
|
278
|
+
const routerTabs = [];
|
|
279
|
+
const loadingBars = [];
|
|
280
|
+
const dateAdapters = [];
|
|
281
|
+
const i18nProviders = [];
|
|
282
|
+
const defaultConfigs = [];
|
|
283
|
+
const ofLabels = [];
|
|
284
|
+
const staleCatalogs = [];
|
|
285
|
+
let rewritten = 0;
|
|
286
|
+
visit(tree, '/', filePath => {
|
|
287
|
+
const lower = filePath.toLowerCase();
|
|
288
|
+
const isTs = lower.endsWith('.ts');
|
|
289
|
+
const isHtml = lower.endsWith('.html');
|
|
290
|
+
const isStyle = lower.endsWith('.scss') || lower.endsWith('.css');
|
|
291
|
+
// Inline templates live in `.ts`, external ones in `.html`; the renames
|
|
292
|
+
// reach stylesheets too, because one of them is a BEM class.
|
|
293
|
+
if (!isTs && !isHtml && !isStyle && !lower.endsWith('.json'))
|
|
294
|
+
return;
|
|
295
|
+
// Read ONCE. Every detector below then answers about the file the user
|
|
296
|
+
// wrote, not about the file a transform left behind — none of the five
|
|
297
|
+
// renames touches a reported token today, and relying on that is exactly
|
|
298
|
+
// the coupling that breaks the next time one is added.
|
|
299
|
+
const content = tree.readText(filePath);
|
|
300
|
+
if (isTs || isHtml || isStyle) {
|
|
301
|
+
const next = apply(content, [
|
|
302
|
+
...(isTs || isHtml ? HTML_TRANSFORMS : []),
|
|
303
|
+
...(isTs ? TS_TRANSFORMS : []),
|
|
304
|
+
...GLOBAL_TRANSFORMS,
|
|
305
|
+
]);
|
|
306
|
+
if (next !== content) {
|
|
307
|
+
tree.overwrite(filePath, next);
|
|
308
|
+
rewritten += 1;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (ROUTER_TAB.test(content))
|
|
312
|
+
routerTabs.push(filePath);
|
|
313
|
+
if (LOADING_BAR.test(content))
|
|
314
|
+
loadingBars.push(filePath);
|
|
315
|
+
if (DATE_ADAPTER_NO_LOCALE.test(content))
|
|
316
|
+
dateAdapters.push(filePath);
|
|
317
|
+
if (I18N_NO_DEFAULT_LOCALE.test(content))
|
|
318
|
+
i18nProviders.push(filePath);
|
|
319
|
+
if (DEFAULT_CONFIG.test(content))
|
|
320
|
+
defaultConfigs.push(filePath);
|
|
321
|
+
if (OF_LABEL.test(content))
|
|
322
|
+
ofLabels.push(filePath);
|
|
323
|
+
// Scoped to the `pagination:` block so a `common: { of: '…' }` — a key that
|
|
324
|
+
// is still shipped and still unread — does not drag every catalog in.
|
|
325
|
+
if (paginationBlocks(content).some(block => REMOVED_KEY.test(block))) {
|
|
326
|
+
staleCatalogs.push(filePath);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
if (rewritten > 0) {
|
|
330
|
+
context.logger.info(`ngwr v14 migration: rewrote ${rewritten} file(s) for the renames: on <wr-alert> from ` +
|
|
331
|
+
'closeable to closable, on <wr-table> from totalItems to total, on <wr-pagination> from ' +
|
|
332
|
+
'currentPage to page (and from currentPageChange to pageChange), from isDisabledWhenLoading ' +
|
|
333
|
+
'to disabledWhenLoading, and the window chromeSize scale from compact/normal to sm/md ' +
|
|
334
|
+
'(class .wr-window--chrome-compact to --chrome-sm).');
|
|
335
|
+
context.logger.info('Verify the result with `git diff` — a few edge cases may need manual touch-up.');
|
|
336
|
+
}
|
|
337
|
+
if (staleCatalogs.length > 0) {
|
|
338
|
+
context.logger.warn(`ngwr v14: a translated \`pagination.of\` found in ${staleCatalogs.length} file(s). The range is ` +
|
|
339
|
+
'one template now — replace it with `pagination.range` ("{{from}}–{{to}} of {{total}}") and ' +
|
|
340
|
+
'`pagination.compact`. Nothing throws: the old key is simply never read again, so a catalog ' +
|
|
341
|
+
'that keeps it silently reverts that line to English.');
|
|
342
|
+
for (const file of staleCatalogs)
|
|
343
|
+
context.logger.warn(` ${file}`);
|
|
344
|
+
}
|
|
345
|
+
if (loadingBars.length > 0) {
|
|
346
|
+
context.logger.warn(`ngwr v14: <wr-loading-bar> found in ${loadingBars.length} file(s). Router navigations no ` +
|
|
347
|
+
'longer drive it by default — add `provideWrLoadingBarRouter()` from `ngwr/loading-bar/router` ' +
|
|
348
|
+
'to your application providers. Nothing throws without it; the bar simply stays at 0%.');
|
|
349
|
+
for (const file of loadingBars)
|
|
350
|
+
context.logger.warn(` ${file}`);
|
|
351
|
+
}
|
|
352
|
+
if (routerTabs.length > 0) {
|
|
353
|
+
context.logger.warn(`ngwr v14: <wr-tab routerLink> found in ${routerTabs.length} file(s). Add \`wrTabsRouting\` to the ` +
|
|
354
|
+
"`<wr-tabs>` element and `WrTabsRouting` (from `ngwr/tabs/router`) to the component's imports. " +
|
|
355
|
+
'The strip throws at runtime until you do, so this one cannot ship unnoticed.');
|
|
356
|
+
for (const file of routerTabs)
|
|
357
|
+
context.logger.warn(` ${file}`);
|
|
358
|
+
}
|
|
359
|
+
if (dateAdapters.length > 0) {
|
|
360
|
+
context.logger.warn(`ngwr v14: provideWrDateAdapter() with no \`locale\` found in ${dateAdapters.length} file(s). It now ` +
|
|
361
|
+
"takes Angular's LOCALE_ID instead of navigator.language, so a prerendered page and its hydrated " +
|
|
362
|
+
'self finally agree and an app that set LOCALE_ID stops rendering an English calendar inside ' +
|
|
363
|
+
"itself. If you genuinely wanted the browser's tag, say so: " +
|
|
364
|
+
'provideWrDateAdapter({ locale: navigator.language }).');
|
|
365
|
+
for (const file of dateAdapters)
|
|
366
|
+
context.logger.warn(` ${file}`);
|
|
367
|
+
}
|
|
368
|
+
if (i18nProviders.length > 0) {
|
|
369
|
+
context.logger.warn(`ngwr v14: provideWrI18n() with no \`defaultLocale\` found in ${i18nProviders.length} file(s). The ` +
|
|
370
|
+
"default is now LOCALE_ID rather than the literal 'en', and `availableLocales` defaults to " +
|
|
371
|
+
"[defaultLocale] rather than ['en']. Catalog lookups also fall back from a region to its language, " +
|
|
372
|
+
'so a `ru` catalog answers an app running `ru-RU`. Pass `defaultLocale` explicitly to pin the old ' +
|
|
373
|
+
'behaviour.');
|
|
374
|
+
for (const file of i18nProviders)
|
|
375
|
+
context.logger.warn(` ${file}`);
|
|
376
|
+
}
|
|
377
|
+
if (defaultConfigs.length > 0) {
|
|
378
|
+
context.logger.warn(`ngwr v14: DEFAULT_WR_I18N_CONFIG referenced in ${defaultConfigs.length} file(s). It no longer ` +
|
|
379
|
+
'carries `defaultLocale` or `availableLocales` — those cannot be constants now that they resolve ' +
|
|
380
|
+
'from LOCALE_ID — so spreading it no longer produces a complete WrI18nConfigResolved.');
|
|
381
|
+
for (const file of defaultConfigs)
|
|
382
|
+
context.logger.warn(` ${file}`);
|
|
383
|
+
}
|
|
384
|
+
if (ofLabels.length > 0) {
|
|
385
|
+
context.logger.warn(`ngwr v14: <wr-pagination ofLabel> found in ${ofLabels.length} file(s). The input is gone — the ` +
|
|
386
|
+
'whole "1–10 of 235" line is now the `pagination.range` catalog entry, with `{{from}}`, ' +
|
|
387
|
+
'`{{to}}` and `{{total}}` placeholders, so a translation owns the operand order and the ' +
|
|
388
|
+
'punctuation as well as the word between them. Move your text there and drop the binding.');
|
|
389
|
+
for (const file of ofLabels)
|
|
390
|
+
context.logger.warn(` ${file}`);
|
|
391
|
+
}
|
|
392
|
+
if (rewritten === 0 &&
|
|
393
|
+
loadingBars.length === 0 &&
|
|
394
|
+
routerTabs.length === 0 &&
|
|
395
|
+
dateAdapters.length === 0 &&
|
|
396
|
+
i18nProviders.length === 0 &&
|
|
397
|
+
defaultConfigs.length === 0 &&
|
|
398
|
+
ofLabels.length === 0 &&
|
|
399
|
+
staleCatalogs.length === 0) {
|
|
400
|
+
context.logger.info('ngwr v14 migration: nothing to do — no affected usage found.');
|
|
401
|
+
}
|
|
402
|
+
return tree;
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function apply(content, transforms) {
|
|
406
|
+
let next = content;
|
|
407
|
+
for (const { pattern, replacement } of transforms) {
|
|
408
|
+
next = next.replace(pattern, replacement);
|
|
409
|
+
}
|
|
410
|
+
return next;
|
|
411
|
+
}
|
|
412
|
+
function visit(tree, path, visitor) {
|
|
413
|
+
const dir = tree.getDir(path);
|
|
414
|
+
for (const file of dir.subfiles)
|
|
415
|
+
visitor(`${path === '/' ? '' : path}/${file}`);
|
|
416
|
+
for (const sub of dir.subdirs) {
|
|
417
|
+
if (IGNORE_DIRS.has(sub))
|
|
418
|
+
continue;
|
|
419
|
+
visit(tree, `${path === '/' ? '' : path}/${sub}`, visitor);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
exports.default = ngUpdateV14;
|
|
@@ -20,6 +20,16 @@
|
|
|
20
20
|
"version": "12.0.0",
|
|
21
21
|
"description": "Move the date entry points under one namespace: ngwr/date-adapter \u2192 ngwr/date, ngwr/date-adapter-fns \u2192 ngwr/date/adapters/fns, ngwr/date-adapter-luxon \u2192 ngwr/date/adapters/luxon. Import paths only \u2014 every exported symbol keeps its name. Touches .ts, .html and .json files.",
|
|
22
22
|
"factory": "./migrations/v12/index#default"
|
|
23
|
+
},
|
|
24
|
+
"migration-v13": {
|
|
25
|
+
"version": "13.0.0",
|
|
26
|
+
"description": "Reports every host-id selector on <wr-checkbox>, <wr-radio> and <wr-switch>: `[id]` no longer lands on the host element, it goes to the inner <input> where the input was always documented to put it. Rewrites nothing — whether `wr-checkbox#agree` should become `#agree` (the tick), `wr-checkbox:has(#agree)` (the row) or a class is a decision only the author can make, and a selector that stops matching is silent in CSS, in querySelector and in a test locator alike. Reads .ts, .html, .scss and .css files.",
|
|
27
|
+
"factory": "./migrations/v13/index#default"
|
|
28
|
+
},
|
|
29
|
+
"migration-v14": {
|
|
30
|
+
"version": "14.0.0",
|
|
31
|
+
"description": "Rewrites five renames: on <wr-alert> from closeable to closable; on <wr-table> from totalItems to total; on <wr-pagination> from currentPage to page (and from currentPageChange to pageChange); from isDisabledWhenLoading to disabledWhenLoading; and the window chromeSize scale from compact/normal to sm/md, including the .wr-window--chrome-compact class. Reports what a codemod cannot decide: router integration is now opt-in (<wr-loading-bar> needs provideWrLoadingBarRouter() from ngwr/loading-bar/router, <wr-tab routerLink> needs wrTabsRouting on the strip plus WrTabsRouting in imports), the locale defaults now follow LOCALE_ID, and <wr-pagination ofLabel> is gone. Touches .ts, .html, .scss and .css files.",
|
|
32
|
+
"factory": "./migrations/v14/index#default"
|
|
23
33
|
}
|
|
24
34
|
}
|
|
25
35
|
}
|
package/skills/ngwr/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: Build Angular UIs with the ngwr component library (standalone, sign
|
|
|
5
5
|
|
|
6
6
|
# ngwr
|
|
7
7
|
|
|
8
|
-
An Angular 22 UI library:
|
|
8
|
+
An Angular 22 UI library: 204 tree-shakable entry points, 111 of them shipping a selector.
|
|
9
9
|
Standalone, signals-first, zoneless, `ViewEncapsulation.None`. One runtime
|
|
10
10
|
dependency (`tslib`).
|
|
11
11
|
|
|
@@ -92,6 +92,9 @@ cause.
|
|
|
92
92
|
- `provideWrDateFnsAdapter() // from 'ngwr/date/adapters/fns'`
|
|
93
93
|
— every date mode goes through an adapter; there is no built-in default
|
|
94
94
|
— needed by: `WrDatePicker`, `WrCalendar`, `WrEventCalendar`
|
|
95
|
+
- `provideWrLoadingBarRouter() // from 'ngwr/loading-bar/router'`
|
|
96
|
+
— without it the bar never responds to navigation; it only moves for manual start() / complete()
|
|
97
|
+
— needed by: `WrLoadingBar`
|
|
95
98
|
- `provideWrI18n() + provideWrI18nStaticLoader({ en: wrEn }) // from 'ngwr/i18n' + 'ngwr/i18n/en'`
|
|
96
99
|
— the pipe and directive read from a catalog you provide
|
|
97
100
|
— needed by: `WrTPipe`, `WrTDirective`, `WrI18n`
|
|
@@ -114,6 +114,7 @@ root barrel for components.
|
|
|
114
114
|
| `ngwr/line-chart/testing` | `import { WrLineChartHarness } from 'ngwr/line-chart/testing'` | — |
|
|
115
115
|
| `ngwr/list` | `import { WrList } from 'ngwr/list'` | `wr-list-item` `wr-list` |
|
|
116
116
|
| `ngwr/loading-bar` | `import { WrLoadingBar } from 'ngwr/loading-bar'` | `wr-loading-bar` |
|
|
117
|
+
| `ngwr/loading-bar/router` | `import { provideWrLoadingBarRouter } from 'ngwr/loading-bar/router'` | — |
|
|
117
118
|
| `ngwr/markdown` | `import { WrMarkdown } from 'ngwr/markdown'` | `wr-markdown` |
|
|
118
119
|
| `ngwr/markdown/testing` | `import { WrMarkdownCodeBlockHarness } from 'ngwr/markdown/testing'` | — |
|
|
119
120
|
| `ngwr/marquee` | `import { WrMarquee } from 'ngwr/marquee'` | `wr-marquee` |
|
|
@@ -180,6 +181,7 @@ root barrel for components.
|
|
|
180
181
|
| `ngwr/table` | `import { WrTable } from 'ngwr/table'` | `[wrTableCell]` `ng-template[wrTableExpand]` `wr-table-filter` `ng-template[wrTableGroupHeader]` `wr-table-sort` `wr-table` |
|
|
181
182
|
| `ngwr/table/testing` | `import { WrTableCellHarness } from 'ngwr/table/testing'` | — |
|
|
182
183
|
| `ngwr/tabs` | `import { WrTabs } from 'ngwr/tabs'` | `wr-tab` `wr-tabs` |
|
|
184
|
+
| `ngwr/tabs/router` | `import { WrTabsRouting } from 'ngwr/tabs/router'` | `[wrTabsRouting]` |
|
|
183
185
|
| `ngwr/tabs/testing` | `import { WrTabHarness } from 'ngwr/tabs/testing'` | — |
|
|
184
186
|
| `ngwr/textarea` | `import { WrTextarea } from 'ngwr/textarea'` | `wr-textarea` |
|
|
185
187
|
| `ngwr/textarea/testing` | `import { WrTextareaHarness } from 'ngwr/textarea/testing'` | — |
|
|
@@ -56,6 +56,10 @@ Icons resolve by name from a registry you populate. Needed by `WrIcon`.
|
|
|
56
56
|
|
|
57
57
|
Every date mode goes through an adapter; there is no built-in default. Needed by `WrDatePicker`, `WrCalendar`, `WrEventCalendar`.
|
|
58
58
|
|
|
59
|
+
### `provideWrLoadingBarRouter() // from 'ngwr/loading-bar/router'`
|
|
60
|
+
|
|
61
|
+
Without it the bar never responds to navigation; it only moves for manual start() / complete(). Needed by `WrLoadingBar`.
|
|
62
|
+
|
|
59
63
|
### `provideWrI18n() + provideWrI18nStaticLoader({ en: wrEn }) // from 'ngwr/i18n' + 'ngwr/i18n/en'`
|
|
60
64
|
|
|
61
65
|
The pipe and directive read from a catalog you provide. Needed by `WrTPipe`, `WrTDirective`, `WrI18n`.
|
|
@@ -95,7 +95,17 @@ $header-padding-block: 0.25rem;
|
|
|
95
95
|
color: var(--wr-color-on-surface);
|
|
96
96
|
cursor: pointer;
|
|
97
97
|
text-align: start;
|
|
98
|
-
flex: 0 0 auto
|
|
98
|
+
// Shrinkable, with a floor of nothing. `flex: 0 0 auto` froze the button at
|
|
99
|
+
// its max-content width, so the `<li>`'s own `min-width: 0` bought nothing:
|
|
100
|
+
// the row shrank and the button overflowed it. English hid this — the defect
|
|
101
|
+
// needs a label the row cannot fit, which is what a translation is. Measured
|
|
102
|
+
// in Chromium at a 375px viewport, three steps: `Übersichtsdarstellung /
|
|
103
|
+
// Grundeinstellungen / Rechnungsstellung` pushed the DOCUMENT to 423px, so
|
|
104
|
+
// the whole page scrolled sideways and the last label ran off the screen; the
|
|
105
|
+
// Finnish and Japanese sets did the same by 16px. A horizontal stepper is a
|
|
106
|
+
// full-width row of unbounded strings — it has to be able to give.
|
|
107
|
+
flex: 0 1 auto;
|
|
108
|
+
min-width: 0;
|
|
99
109
|
|
|
100
110
|
&:disabled {
|
|
101
111
|
cursor: not-allowed;
|
|
@@ -145,6 +155,14 @@ $header-padding-block: 0.25rem;
|
|
|
145
155
|
font-size: var(--wr-text-sm);
|
|
146
156
|
font-weight: 500;
|
|
147
157
|
line-height: $label-line-height;
|
|
158
|
+
// The other half of the shrink above: a flex item's automatic minimum size
|
|
159
|
+
// is its min-content width, and for a German compound noun that IS the whole
|
|
160
|
+
// word, so the button would shrink and the label would not. `break-word`
|
|
161
|
+
// only splits a word that cannot fit a line of its own, so nothing changes
|
|
162
|
+
// until the row is genuinely too narrow — and nothing changes at all in
|
|
163
|
+
// English or above 768px, measured.
|
|
164
|
+
min-width: 0;
|
|
165
|
+
overflow-wrap: break-word;
|
|
148
166
|
// Centre the label's FIRST LINE on the indicator, now that both are anchored
|
|
149
167
|
// to the button's block start. Half the difference between the circle and one
|
|
150
168
|
// line box — derived, not typed, because `--wr-stepper-indicator-size` is a
|
|
@@ -94,12 +94,13 @@
|
|
|
94
94
|
// cursor follow the `resize` direction.
|
|
95
95
|
&__resize {
|
|
96
96
|
position: absolute;
|
|
97
|
-
//
|
|
98
|
-
// `
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
|
|
97
|
+
// Logical now, and the drag maths moved with it: `onResize` reads
|
|
98
|
+
// `Directionality` and negates the `clientX` delta under `dir="rtl"`, because
|
|
99
|
+
// a block-level box is anchored at its inline START and grows toward its
|
|
100
|
+
// inline END — physically right in LTR, physically left in RTL. The grip has
|
|
101
|
+
// to sit on the corner the box actually extends toward, so the two halves
|
|
102
|
+
// must be changed together or not at all.
|
|
103
|
+
inset-inline-end: 0.25rem;
|
|
103
104
|
bottom: 0.25rem;
|
|
104
105
|
display: inline-flex;
|
|
105
106
|
color: var(--wr-color-text-faint);
|
|
@@ -113,7 +114,14 @@
|
|
|
113
114
|
cursor: ew-resize;
|
|
114
115
|
}
|
|
115
116
|
&--both {
|
|
117
|
+
// The diagonal cursor names two physical corners, so it is the one cue here
|
|
118
|
+
// that has no logical spelling: at the bottom-LEFT corner an RTL field grows
|
|
119
|
+
// along the north-east / south-west diagonal instead.
|
|
116
120
|
cursor: nwse-resize;
|
|
121
|
+
|
|
122
|
+
[dir='rtl'] & {
|
|
123
|
+
cursor: nesw-resize;
|
|
124
|
+
}
|
|
117
125
|
}
|
|
118
126
|
|
|
119
127
|
.wr-icon__svg {
|
package/toast/styles/_index.scss
CHANGED
|
@@ -209,14 +209,22 @@ $toast-colors: (
|
|
|
209
209
|
inset-inline-start: 0;
|
|
210
210
|
height: 2px;
|
|
211
211
|
width: 100%;
|
|
212
|
-
// `transform-origin` has no logical keyword
|
|
213
|
-
// `scaleX
|
|
214
|
-
// direction-aware rule
|
|
215
|
-
//
|
|
212
|
+
// `transform-origin` has no logical keyword and the drain is a physical
|
|
213
|
+
// `scaleX`, so the anchor cannot be renamed into a logical property — it has
|
|
214
|
+
// to be swapped by a direction-aware rule. The bar drains toward the reader's
|
|
215
|
+
// end, which means it stays anchored at the reader's START: physically left
|
|
216
|
+
// in LTR, physically right in RTL. Leaving it at `left` in both pinned the
|
|
217
|
+
// remaining time to the side an RTL reader's eye leaves from.
|
|
218
|
+
// rtl-ok: origin is one half of a physical scaleX pair, mirrored below
|
|
216
219
|
transform-origin: left;
|
|
217
220
|
background: var(--wr-toast-accent);
|
|
218
221
|
animation: wr-toast-progress linear forwards;
|
|
219
222
|
animation-duration: var(--wr-toast-duration, 4000ms);
|
|
223
|
+
|
|
224
|
+
[dir='rtl'] & {
|
|
225
|
+
// rtl-ok: the mirrored half of the pair above
|
|
226
|
+
transform-origin: right;
|
|
227
|
+
}
|
|
220
228
|
}
|
|
221
229
|
|
|
222
230
|
&:hover &__progress {
|
package/types/ngwr-alert.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ type WrAlertType = 'info' | 'success' | 'warning' | 'danger' | 'neutral' | 'offl
|
|
|
17
17
|
* @example
|
|
18
18
|
* ```html
|
|
19
19
|
* <wr-alert title="Saved" message="Your changes are live." type="success" />
|
|
20
|
-
* <wr-alert title="Failed" type="danger"
|
|
20
|
+
* <wr-alert title="Failed" type="danger" closable (closed)="onClose()" />
|
|
21
21
|
* ```
|
|
22
22
|
*
|
|
23
23
|
* @see https://ngwr.dev/reference/components/alert
|
|
@@ -62,7 +62,7 @@ declare class WrAlert {
|
|
|
62
62
|
*
|
|
63
63
|
* @default false
|
|
64
64
|
*/
|
|
65
|
-
readonly
|
|
65
|
+
readonly closable: _angular_core.InputSignalWithTransform<boolean, any>;
|
|
66
66
|
/**
|
|
67
67
|
* Emitted when the user dismisses the alert via the close button.
|
|
68
68
|
*/
|
|
@@ -74,7 +74,7 @@ declare class WrAlert {
|
|
|
74
74
|
protected readonly liveLevel: _angular_core.Signal<"assertive" | "polite" | null>;
|
|
75
75
|
protected onClose(): void;
|
|
76
76
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrAlert, never>;
|
|
77
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrAlert, "wr-alert", never, { "closeLabel": { "alias": "closeLabel"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "iconName": { "alias": "iconName"; "required": false; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "
|
|
77
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrAlert, "wr-alert", never, { "closeLabel": { "alias": "closeLabel"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "iconName": { "alias": "iconName"; "required": false; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "closable": { "alias": "closable"; "required": false; "isSignal": true; }; }, { "closed": "closed"; }, never, never, true, never>;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
export { WrAlert };
|