ngwr 15.2.0 → 15.3.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/alert/styles/_index.scss +13 -5
- package/fesm2022/ngwr-alert.mjs +2 -2
- package/fesm2022/ngwr-alert.mjs.map +1 -1
- package/fesm2022/ngwr-breadcrumbs.mjs +18 -2
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ngwr-hotkey.mjs +23 -1
- package/fesm2022/ngwr-hotkey.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ar.mjs +2 -0
- package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-cs.mjs +2 -0
- package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-de.mjs +2 -0
- package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +2 -0
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-es.mjs +2 -0
- package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-fr.mjs +2 -0
- package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-he.mjs +2 -0
- package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-hi.mjs +2 -0
- package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-id.mjs +2 -0
- package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-it.mjs +2 -0
- package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ja.mjs +2 -0
- package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ko.mjs +2 -0
- package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-nl.mjs +2 -0
- package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pl.mjs +2 -0
- package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pt.mjs +2 -0
- package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +2 -0
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-sv.mjs +2 -0
- package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-tr.mjs +2 -0
- package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-uk.mjs +2 -0
- package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-vi.mjs +2 -0
- package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh-tw.mjs +2 -0
- package/fesm2022/ngwr-i18n-zh-tw.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh.mjs +2 -0
- package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
- package/fesm2022/ngwr-pagination.mjs +3 -0
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-pipes.mjs +5 -2
- package/fesm2022/ngwr-pipes.mjs.map +1 -1
- package/fesm2022/ngwr-schema-form.mjs +3 -0
- package/fesm2022/ngwr-schema-form.mjs.map +1 -1
- package/fesm2022/ngwr-select-testing.mjs +16 -0
- package/fesm2022/ngwr-select-testing.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +218 -38
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-statistic.mjs +9 -5
- package/fesm2022/ngwr-statistic.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/i18n/ar.json +2 -0
- package/i18n/cs.json +2 -0
- package/i18n/de.json +2 -0
- package/i18n/en.json +2 -0
- package/i18n/es.json +2 -0
- package/i18n/fr.json +2 -0
- package/i18n/he.json +2 -0
- package/i18n/hi.json +2 -0
- package/i18n/id.json +2 -0
- package/i18n/it.json +2 -0
- package/i18n/ja.json +2 -0
- package/i18n/ko.json +2 -0
- package/i18n/nl.json +2 -0
- package/i18n/pl.json +2 -0
- package/i18n/pt.json +2 -0
- package/i18n/ru.json +2 -0
- package/i18n/sv.json +2 -0
- package/i18n/tr.json +2 -0
- package/i18n/uk.json +2 -0
- package/i18n/vi.json +2 -0
- package/i18n/zh-TW.json +2 -0
- package/i18n/zh.json +2 -0
- package/llms-full.txt +3 -3
- package/package.json +1 -1
- package/schematics/use/symbol-map.json +1 -0
- package/select/styles/_index.scss +23 -1
- package/skills/ngwr/references/catalog.md +1 -1
- package/types/ngwr-alert.d.ts +3 -1
- package/types/ngwr-breadcrumbs.d.ts +15 -0
- package/types/ngwr-hotkey.d.ts +14 -2
- package/types/ngwr-select-testing.d.ts +9 -0
- package/types/ngwr-select.d.ts +133 -2
- package/types/ngwr-sidebar.d.ts +1 -1
- package/types/ngwr-version.d.ts +1 -1
package/alert/styles/_index.scss
CHANGED
|
@@ -108,7 +108,10 @@ $alert-colors: (
|
|
|
108
108
|
line-height: var(--wr-alert-title-line-height);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
// Projected content reads as the message does. Hidden while empty, so an alert
|
|
112
|
+
// with nothing inside keeps the body's gap to what it had.
|
|
113
|
+
&__message,
|
|
114
|
+
&__content {
|
|
112
115
|
margin: 0;
|
|
113
116
|
color: var(--wr-alert-message);
|
|
114
117
|
font-family: var(--wr-alert-font-family);
|
|
@@ -116,6 +119,10 @@ $alert-colors: (
|
|
|
116
119
|
line-height: var(--wr-alert-message-line-height);
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
&__content:empty {
|
|
123
|
+
display: none;
|
|
124
|
+
}
|
|
125
|
+
|
|
119
126
|
&__close {
|
|
120
127
|
flex: 0 0 auto;
|
|
121
128
|
appearance: none;
|
|
@@ -136,11 +143,12 @@ $alert-colors: (
|
|
|
136
143
|
// `font: inherit`. Inheriting the size makes `1em` the alert's own text in
|
|
137
144
|
// every app. `--wr-icon-size` cannot do this job — only a `<wr-icon>` host
|
|
138
145
|
// reads it, and the rule here used to set it for nothing. The SIZE only,
|
|
139
|
-
// never the `font` shorthand, which would bring the line-height with it
|
|
140
|
-
// no `line-height` of its own either, the way `wr-dialog` needs one — the
|
|
141
|
-
// alert stretches its row, so this box is the alert's height whatever the
|
|
142
|
-
// strut says.
|
|
146
|
+
// never the `font` shorthand, which would bring the line-height with it.
|
|
143
147
|
font-size: inherit;
|
|
148
|
+
// Top of the row, by the title, rather than stretched to the alert's height:
|
|
149
|
+
// with projected content under the message, a stretched button put the ✕
|
|
150
|
+
// halfway down the alert and painted its hover tint as a full-height strip.
|
|
151
|
+
align-self: flex-start;
|
|
144
152
|
|
|
145
153
|
@include theme.touch-target; // glyph -> 44px tap area on touch
|
|
146
154
|
|
package/fesm2022/ngwr-alert.mjs
CHANGED
|
@@ -125,7 +125,7 @@ var WrAlert = class WrAlert {
|
|
|
125
125
|
"attr.aria-live": "liveLevel()"
|
|
126
126
|
} },
|
|
127
127
|
ngImport: i0,
|
|
128
|
-
template: "@if (!dismissed()) {\n @if (iconName(); as n) {\n <wr-icon class=\"wr-alert__icon\" [name]=\"n\" />\n } @else if (icon()) {\n <svg\n class=\"wr-alert__icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (type()) {\n @case ('success') {\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n }\n @case ('warning') {\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n }\n <!-- An OCTAGON, and the shape is the point. `danger` used to be a\n circle holding a bar over a dot, which is the vertical mirror of\n the `i` the @default branch draws — at the rendered 18px the two\n differ only by where a 1.5px gap sits. The stop-sign silhouette\n reads at that size and survives greyscale, which a mirrored gap\n does not. -->\n @case ('danger') {\n <path\n d=\"M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z\"\n />\n <path d=\"M12 8v4\" />\n <path d=\"M12 16h.01\" />\n }\n <!-- A bar, not the exclamation mark `danger` used to carry: `neutral`\n emitted that glyph byte for byte. The icon is the whole difference\n between these two, because what the component actually paints —\n `danger-ink` #a32a33 (L 0.0968) against `on-surface-muted` #5f6c7d\n (L 0.1464) on tints 1.036:1 apart — is a hue difference and little\n else. -->\n @case ('neutral') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 12h8\" />\n }\n @case ('offline') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m4.9 4.9 14.2 14.2\" />\n }\n @default {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n }\n }\n </svg>\n }\n\n <div class=\"wr-alert__body\">\n @if (title(); as t) {\n <p class=\"wr-alert__title\">{{ t }}</p>\n @if (message(); as m) {\n <p class=\"wr-alert__message\">{{ m }}</p>\n }\n } @else if (message(); as m) {\n <p class=\"wr-alert__title\">{{ m }}</p>\n }\n </div>\n\n @if (closable()) {\n <button type=\"button\" class=\"wr-alert__close\" [attr.aria-label]=\"resolvedCloseLabel()\" (click)=\"onClose()\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n }\n}\n",
|
|
128
|
+
template: "@if (!dismissed()) {\n @if (iconName(); as n) {\n <wr-icon class=\"wr-alert__icon\" [name]=\"n\" />\n } @else if (icon()) {\n <svg\n class=\"wr-alert__icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (type()) {\n @case ('success') {\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n }\n @case ('warning') {\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n }\n <!-- An OCTAGON, and the shape is the point. `danger` used to be a\n circle holding a bar over a dot, which is the vertical mirror of\n the `i` the @default branch draws — at the rendered 18px the two\n differ only by where a 1.5px gap sits. The stop-sign silhouette\n reads at that size and survives greyscale, which a mirrored gap\n does not. -->\n @case ('danger') {\n <path\n d=\"M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z\"\n />\n <path d=\"M12 8v4\" />\n <path d=\"M12 16h.01\" />\n }\n <!-- A bar, not the exclamation mark `danger` used to carry: `neutral`\n emitted that glyph byte for byte. The icon is the whole difference\n between these two, because what the component actually paints —\n `danger-ink` #a32a33 (L 0.0968) against `on-surface-muted` #5f6c7d\n (L 0.1464) on tints 1.036:1 apart — is a hue difference and little\n else. -->\n @case ('neutral') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 12h8\" />\n }\n @case ('offline') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m4.9 4.9 14.2 14.2\" />\n }\n @default {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n }\n }\n </svg>\n }\n\n <div class=\"wr-alert__body\">\n @if (title(); as t) {\n <p class=\"wr-alert__title\">{{ t }}</p>\n @if (message(); as m) {\n <p class=\"wr-alert__message\">{{ m }}</p>\n }\n } @else if (message(); as m) {\n <p class=\"wr-alert__title\">{{ m }}</p>\n }\n <div class=\"wr-alert__content\"><ng-content /></div>\n </div>\n\n @if (closable()) {\n <button type=\"button\" class=\"wr-alert__close\" [attr.aria-label]=\"resolvedCloseLabel()\" (click)=\"onClose()\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n }\n}\n",
|
|
129
129
|
dependencies: [{
|
|
130
130
|
kind: "component",
|
|
131
131
|
type: WrIcon,
|
|
@@ -152,7 +152,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
152
152
|
"[attr.role]": "liveRole()",
|
|
153
153
|
"[attr.aria-live]": "liveLevel()"
|
|
154
154
|
},
|
|
155
|
-
template: "@if (!dismissed()) {\n @if (iconName(); as n) {\n <wr-icon class=\"wr-alert__icon\" [name]=\"n\" />\n } @else if (icon()) {\n <svg\n class=\"wr-alert__icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (type()) {\n @case ('success') {\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n }\n @case ('warning') {\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n }\n <!-- An OCTAGON, and the shape is the point. `danger` used to be a\n circle holding a bar over a dot, which is the vertical mirror of\n the `i` the @default branch draws — at the rendered 18px the two\n differ only by where a 1.5px gap sits. The stop-sign silhouette\n reads at that size and survives greyscale, which a mirrored gap\n does not. -->\n @case ('danger') {\n <path\n d=\"M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z\"\n />\n <path d=\"M12 8v4\" />\n <path d=\"M12 16h.01\" />\n }\n <!-- A bar, not the exclamation mark `danger` used to carry: `neutral`\n emitted that glyph byte for byte. The icon is the whole difference\n between these two, because what the component actually paints —\n `danger-ink` #a32a33 (L 0.0968) against `on-surface-muted` #5f6c7d\n (L 0.1464) on tints 1.036:1 apart — is a hue difference and little\n else. -->\n @case ('neutral') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 12h8\" />\n }\n @case ('offline') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m4.9 4.9 14.2 14.2\" />\n }\n @default {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n }\n }\n </svg>\n }\n\n <div class=\"wr-alert__body\">\n @if (title(); as t) {\n <p class=\"wr-alert__title\">{{ t }}</p>\n @if (message(); as m) {\n <p class=\"wr-alert__message\">{{ m }}</p>\n }\n } @else if (message(); as m) {\n <p class=\"wr-alert__title\">{{ m }}</p>\n }\n </div>\n\n @if (closable()) {\n <button type=\"button\" class=\"wr-alert__close\" [attr.aria-label]=\"resolvedCloseLabel()\" (click)=\"onClose()\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n }\n}\n"
|
|
155
|
+
template: "@if (!dismissed()) {\n @if (iconName(); as n) {\n <wr-icon class=\"wr-alert__icon\" [name]=\"n\" />\n } @else if (icon()) {\n <svg\n class=\"wr-alert__icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (type()) {\n @case ('success') {\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n }\n @case ('warning') {\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n }\n <!-- An OCTAGON, and the shape is the point. `danger` used to be a\n circle holding a bar over a dot, which is the vertical mirror of\n the `i` the @default branch draws — at the rendered 18px the two\n differ only by where a 1.5px gap sits. The stop-sign silhouette\n reads at that size and survives greyscale, which a mirrored gap\n does not. -->\n @case ('danger') {\n <path\n d=\"M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z\"\n />\n <path d=\"M12 8v4\" />\n <path d=\"M12 16h.01\" />\n }\n <!-- A bar, not the exclamation mark `danger` used to carry: `neutral`\n emitted that glyph byte for byte. The icon is the whole difference\n between these two, because what the component actually paints —\n `danger-ink` #a32a33 (L 0.0968) against `on-surface-muted` #5f6c7d\n (L 0.1464) on tints 1.036:1 apart — is a hue difference and little\n else. -->\n @case ('neutral') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 12h8\" />\n }\n @case ('offline') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m4.9 4.9 14.2 14.2\" />\n }\n @default {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n }\n }\n </svg>\n }\n\n <div class=\"wr-alert__body\">\n @if (title(); as t) {\n <p class=\"wr-alert__title\">{{ t }}</p>\n @if (message(); as m) {\n <p class=\"wr-alert__message\">{{ m }}</p>\n }\n } @else if (message(); as m) {\n <p class=\"wr-alert__title\">{{ m }}</p>\n }\n <div class=\"wr-alert__content\"><ng-content /></div>\n </div>\n\n @if (closable()) {\n <button type=\"button\" class=\"wr-alert__close\" [attr.aria-label]=\"resolvedCloseLabel()\" (click)=\"onClose()\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n }\n}\n"
|
|
156
156
|
}]
|
|
157
157
|
}],
|
|
158
158
|
propDecorators: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-alert.mjs","names":[],"sources":["../../../projects/lib/alert/alert.ts","../../../projects/lib/alert/alert.html"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n Injector,\n ViewEncapsulation,\n afterNextRender,\n computed,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\nimport { getFocusableElements } from 'ngwr/utils';\n\nimport type { WrAlertType } from './types';\n\n/**\n * Inline status banner. Use for feedback messages — saved/failed/notice etc.\n *\n * @example\n * ```html\n * <wr-alert title=\"Saved\" message=\"Your changes are live.\" type=\"success\" />\n * <wr-alert title=\"Failed\" type=\"danger\" closable (closed)=\"onClose()\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/alert\n */\n@Component({\n selector: 'wr-alert',\n templateUrl: './alert.html',\n imports: [WrIcon],\n encapsulation: ViewEncapsulation.None,\n host: {\n // `title` is an input, and a static attribute that feeds an input is ALSO\n // written onto the host — where the browser shows it as a native tooltip\n // over the whole component, and where it feeds the accessible name of any\n // element that has a role. `<wr-alert title=\"Heads up\">` is the documented\n // spelling, so every page writing it shipped both. A bound `[title]` never\n // did this, which is why the two forms behaved differently for no reason a\n // reader could see.\n '[attr.title]': 'null',\n '[class]': 'classes()',\n '[attr.role]': 'liveRole()',\n '[attr.aria-live]': 'liveLevel()',\n },\n})\nexport class WrAlert {\n /** Accessible name. Falls back to `alert.close`, then `'Close alert'`. */\n readonly closeLabel = input<string | null>(null);\n\n protected readonly resolvedCloseLabel = useI18nText(this.closeLabel, 'alert.close', 'Close alert');\n\n /**\n * Optional headline shown at the top of the alert.\n *\n * @default null\n */\n readonly title = input<string | null>(null);\n\n /**\n * Visual variant.\n *\n * @default 'info'\n */\n readonly type = input<WrAlertType>('info');\n\n /**\n * Override the default per-type icon with any ngwr icon name.\n *\n * @default null\n */\n readonly iconName = input<WrIconName | null>(null);\n\n /**\n * Optional secondary message rendered below the title.\n *\n * @default null\n */\n readonly message = input<string | null>(null);\n\n /**\n * When `true`, renders a leading status icon matching the `type`.\n * Pass `false` to hide. Ignored when `iconName` is set.\n *\n * @default true\n */\n readonly icon = input(true, { transform: coerceBooleanProperty });\n\n /**\n * When `true`, renders a close button.\n *\n * @default false\n */\n readonly closable = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Emitted when the user dismisses the alert via the close button. If the close\n * button had focus, focus moves on to the next focusable element after the alert\n * (or the one before it, when nothing follows) — unless a `(closed)` handler has\n * placed it somewhere itself.\n */\n readonly closed = output<void>();\n\n protected readonly dismissed = signal(false);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-alert', `wr-alert--${this.type()}`];\n if (this.dismissed()) parts.push('wr-alert--dismissed');\n return parts.join(' ');\n });\n\n /** Escalate role/aria-live for danger/warning alerts. */\n protected readonly liveRole = computed(() =>\n this.dismissed() ? null : this.type() === 'danger' ? 'alert' : 'status'\n );\n protected readonly liveLevel = computed(() =>\n this.dismissed() ? null : this.type() === 'danger' || this.type() === 'warning' ? 'assertive' : 'polite'\n );\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n\n protected onClose(): void {\n const host = this.host.nativeElement;\n const hadFocus = host.contains(host.ownerDocument.activeElement);\n this.dismissed.set(true);\n this.closed.emit();\n if (hadFocus) afterNextRender(() => this.handOnFocus(), { injector: this.injector });\n }\n\n /**\n * The close button is removed with the rest of the content, and a focused element\n * that leaves the DOM drops the caret on `<body>`: a keyboard user's next Tab, and\n * a screen reader's reading position, started over from the top of the page. Run\n * after the render that removed it, so a `(closed)` handler that moved focus on\n * purpose is seen and left alone.\n */\n private handOnFocus(): void {\n const host = this.host.nativeElement;\n const doc = host.ownerDocument;\n const active = doc.activeElement;\n if (active && active !== doc.body) return;\n // Tab stops only: a roving composite parks its other items at -1. The host has\n // nothing focusable left inside it, so every stop is either before or after it.\n const stops = getFocusableElements(doc.body).filter(el => el.tabIndex >= 0);\n // eslint-disable-next-line no-bitwise -- compareDocumentPosition answers with a bitmask\n const after = stops.findIndex(el => (host.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0);\n (after >= 0 ? stops[after] : stops.at(-1))?.focus();\n }\n}\n","@if (!dismissed()) {\n @if (iconName(); as n) {\n <wr-icon class=\"wr-alert__icon\" [name]=\"n\" />\n } @else if (icon()) {\n <svg\n class=\"wr-alert__icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (type()) {\n @case ('success') {\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n }\n @case ('warning') {\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n }\n <!-- An OCTAGON, and the shape is the point. `danger` used to be a\n circle holding a bar over a dot, which is the vertical mirror of\n the `i` the @default branch draws — at the rendered 18px the two\n differ only by where a 1.5px gap sits. The stop-sign silhouette\n reads at that size and survives greyscale, which a mirrored gap\n does not. -->\n @case ('danger') {\n <path\n d=\"M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z\"\n />\n <path d=\"M12 8v4\" />\n <path d=\"M12 16h.01\" />\n }\n <!-- A bar, not the exclamation mark `danger` used to carry: `neutral`\n emitted that glyph byte for byte. The icon is the whole difference\n between these two, because what the component actually paints —\n `danger-ink` #a32a33 (L 0.0968) against `on-surface-muted` #5f6c7d\n (L 0.1464) on tints 1.036:1 apart — is a hue difference and little\n else. -->\n @case ('neutral') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 12h8\" />\n }\n @case ('offline') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m4.9 4.9 14.2 14.2\" />\n }\n @default {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n }\n }\n </svg>\n }\n\n <div class=\"wr-alert__body\">\n @if (title(); as t) {\n <p class=\"wr-alert__title\">{{ t }}</p>\n @if (message(); as m) {\n <p class=\"wr-alert__message\">{{ m }}</p>\n }\n } @else if (message(); as m) {\n <p class=\"wr-alert__title\">{{ m }}</p>\n }\n </div>\n\n @if (closable()) {\n <button type=\"button\" class=\"wr-alert__close\" [attr.aria-label]=\"resolvedCloseLabel()\" (click)=\"onClose()\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngwr-alert.mjs","names":[],"sources":["../../../projects/lib/alert/alert.ts","../../../projects/lib/alert/alert.html"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n Injector,\n ViewEncapsulation,\n afterNextRender,\n computed,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\nimport { getFocusableElements } from 'ngwr/utils';\n\nimport type { WrAlertType } from './types';\n\n/**\n * Inline status banner. Use for feedback messages — saved/failed/notice etc.\n * Content placed inside renders below the message, in `.wr-alert__content`.\n *\n * @example\n * ```html\n * <wr-alert title=\"Saved\" message=\"Your changes are live.\" type=\"success\" />\n * <wr-alert title=\"Failed\" type=\"danger\" closable (closed)=\"onClose()\" />\n * <wr-alert title=\"Sync failed\" type=\"danger\">Request <code>8f2c41</code> timed out.</wr-alert>\n * ```\n *\n * @see https://ngwr.dev/reference/components/alert\n */\n@Component({\n selector: 'wr-alert',\n templateUrl: './alert.html',\n imports: [WrIcon],\n encapsulation: ViewEncapsulation.None,\n host: {\n // `title` is an input, and a static attribute that feeds an input is ALSO\n // written onto the host — where the browser shows it as a native tooltip\n // over the whole component, and where it feeds the accessible name of any\n // element that has a role. `<wr-alert title=\"Heads up\">` is the documented\n // spelling, so every page writing it shipped both. A bound `[title]` never\n // did this, which is why the two forms behaved differently for no reason a\n // reader could see.\n '[attr.title]': 'null',\n '[class]': 'classes()',\n '[attr.role]': 'liveRole()',\n '[attr.aria-live]': 'liveLevel()',\n },\n})\nexport class WrAlert {\n /** Accessible name. Falls back to `alert.close`, then `'Close alert'`. */\n readonly closeLabel = input<string | null>(null);\n\n protected readonly resolvedCloseLabel = useI18nText(this.closeLabel, 'alert.close', 'Close alert');\n\n /**\n * Optional headline shown at the top of the alert.\n *\n * @default null\n */\n readonly title = input<string | null>(null);\n\n /**\n * Visual variant.\n *\n * @default 'info'\n */\n readonly type = input<WrAlertType>('info');\n\n /**\n * Override the default per-type icon with any ngwr icon name.\n *\n * @default null\n */\n readonly iconName = input<WrIconName | null>(null);\n\n /**\n * Optional secondary message rendered below the title.\n *\n * @default null\n */\n readonly message = input<string | null>(null);\n\n /**\n * When `true`, renders a leading status icon matching the `type`.\n * Pass `false` to hide. Ignored when `iconName` is set.\n *\n * @default true\n */\n readonly icon = input(true, { transform: coerceBooleanProperty });\n\n /**\n * When `true`, renders a close button.\n *\n * @default false\n */\n readonly closable = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Emitted when the user dismisses the alert via the close button. If the close\n * button had focus, focus moves on to the next focusable element after the alert\n * (or the one before it, when nothing follows) — unless a `(closed)` handler has\n * placed it somewhere itself.\n */\n readonly closed = output<void>();\n\n protected readonly dismissed = signal(false);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-alert', `wr-alert--${this.type()}`];\n if (this.dismissed()) parts.push('wr-alert--dismissed');\n return parts.join(' ');\n });\n\n /** Escalate role/aria-live for danger/warning alerts. */\n protected readonly liveRole = computed(() =>\n this.dismissed() ? null : this.type() === 'danger' ? 'alert' : 'status'\n );\n protected readonly liveLevel = computed(() =>\n this.dismissed() ? null : this.type() === 'danger' || this.type() === 'warning' ? 'assertive' : 'polite'\n );\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n\n protected onClose(): void {\n const host = this.host.nativeElement;\n const hadFocus = host.contains(host.ownerDocument.activeElement);\n this.dismissed.set(true);\n this.closed.emit();\n if (hadFocus) afterNextRender(() => this.handOnFocus(), { injector: this.injector });\n }\n\n /**\n * The close button is removed with the rest of the content, and a focused element\n * that leaves the DOM drops the caret on `<body>`: a keyboard user's next Tab, and\n * a screen reader's reading position, started over from the top of the page. Run\n * after the render that removed it, so a `(closed)` handler that moved focus on\n * purpose is seen and left alone.\n */\n private handOnFocus(): void {\n const host = this.host.nativeElement;\n const doc = host.ownerDocument;\n const active = doc.activeElement;\n if (active && active !== doc.body) return;\n // Tab stops only: a roving composite parks its other items at -1. The host has\n // nothing focusable left inside it, so every stop is either before or after it.\n const stops = getFocusableElements(doc.body).filter(el => el.tabIndex >= 0);\n // eslint-disable-next-line no-bitwise -- compareDocumentPosition answers with a bitmask\n const after = stops.findIndex(el => (host.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0);\n (after >= 0 ? stops[after] : stops.at(-1))?.focus();\n }\n}\n","@if (!dismissed()) {\n @if (iconName(); as n) {\n <wr-icon class=\"wr-alert__icon\" [name]=\"n\" />\n } @else if (icon()) {\n <svg\n class=\"wr-alert__icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (type()) {\n @case ('success') {\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n }\n @case ('warning') {\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n }\n <!-- An OCTAGON, and the shape is the point. `danger` used to be a\n circle holding a bar over a dot, which is the vertical mirror of\n the `i` the @default branch draws — at the rendered 18px the two\n differ only by where a 1.5px gap sits. The stop-sign silhouette\n reads at that size and survives greyscale, which a mirrored gap\n does not. -->\n @case ('danger') {\n <path\n d=\"M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z\"\n />\n <path d=\"M12 8v4\" />\n <path d=\"M12 16h.01\" />\n }\n <!-- A bar, not the exclamation mark `danger` used to carry: `neutral`\n emitted that glyph byte for byte. The icon is the whole difference\n between these two, because what the component actually paints —\n `danger-ink` #a32a33 (L 0.0968) against `on-surface-muted` #5f6c7d\n (L 0.1464) on tints 1.036:1 apart — is a hue difference and little\n else. -->\n @case ('neutral') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M8 12h8\" />\n }\n @case ('offline') {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m4.9 4.9 14.2 14.2\" />\n }\n @default {\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n }\n }\n </svg>\n }\n\n <div class=\"wr-alert__body\">\n @if (title(); as t) {\n <p class=\"wr-alert__title\">{{ t }}</p>\n @if (message(); as m) {\n <p class=\"wr-alert__message\">{{ m }}</p>\n }\n } @else if (message(); as m) {\n <p class=\"wr-alert__title\">{{ m }}</p>\n }\n <div class=\"wr-alert__content\"><ng-content /></div>\n </div>\n\n @if (closable()) {\n <button type=\"button\" class=\"wr-alert__close\" [attr.aria-label]=\"resolvedCloseLabel()\" (click)=\"onClose()\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n }\n}\n"],"mappings":"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"}
|
|
@@ -104,6 +104,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
104
104
|
var WrBreadcrumbsItem = class WrBreadcrumbsItem {
|
|
105
105
|
href = input(null, ...ngDevMode ? [{ debugName: "href" }] : /* istanbul ignore next */ []);
|
|
106
106
|
routerLink = input(null, ...ngDevMode ? [{ debugName: "routerLink" }] : /* istanbul ignore next */ []);
|
|
107
|
+
queryParams = input(null, ...ngDevMode ? [{ debugName: "queryParams" }] : /* istanbul ignore next */ []);
|
|
107
108
|
external = input(false, ...ngDevMode ? [{ debugName: "external" }] : /* istanbul ignore next */ []);
|
|
108
109
|
icon = input(null, ...ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []);
|
|
109
110
|
isLink = computed(() => this.href() != null || this.routerLink() != null, ...ngDevMode ? [{ debugName: "isLink" }] : /* istanbul ignore next */ []);
|
|
@@ -138,6 +139,13 @@ var WrBreadcrumbsItem = class WrBreadcrumbsItem {
|
|
|
138
139
|
isRequired: false,
|
|
139
140
|
transformFunction: null
|
|
140
141
|
},
|
|
142
|
+
queryParams: {
|
|
143
|
+
classPropertyName: "queryParams",
|
|
144
|
+
publicName: "queryParams",
|
|
145
|
+
isSignal: true,
|
|
146
|
+
isRequired: false,
|
|
147
|
+
transformFunction: null
|
|
148
|
+
},
|
|
141
149
|
external: {
|
|
142
150
|
classPropertyName: "external",
|
|
143
151
|
publicName: "external",
|
|
@@ -158,7 +166,7 @@ var WrBreadcrumbsItem = class WrBreadcrumbsItem {
|
|
|
158
166
|
classAttribute: "wr-breadcrumbs__item"
|
|
159
167
|
},
|
|
160
168
|
ngImport: i0,
|
|
161
|
-
template: "<!--\n The label lives in a template rather than inside each branch below. A default\n `<ng-content />` written into two `@if` branches fills only ONE of them — the\n last in static order — and the other renders empty, with no template error and\n nothing in the console. This component has been broken exactly that way\n before; stamping one template from either branch keeps two anchors and one\n projection.\n-->\n<ng-template #label>\n @if (icon(); as i) {\n <wr-icon class=\"wr-breadcrumbs__icon\" [name]=\"i\" />\n }\n <ng-content />\n</ng-template>\n\n@if (isRouter()) {\n <!--\n Only ROUTER crumbs get `RouterLink`. Applied unconditionally it owns the\n anchor's `href` and writes null into it whenever `routerLink` is null —\n which silently turned every `href`-based crumb, a documented input, into\n text that navigates nowhere.\n -->\n <a [class]=\"rootClass()\" [routerLink]=\"routerLink()\">\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n} @else {\n <a\n [class]=\"rootClass()\"\n [attr.href]=\"href()\"\n [attr.aria-current]=\"isLink() ? null : 'page'\"\n [attr.role]=\"isLink() ? null : 'text'\"\n [attr.tabindex]=\"isLink() ? null : -1\"\n [attr.target]=\"external() ? '_blank' : null\"\n [attr.rel]=\"external() ? 'noreferrer noopener' : null\"\n >\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n}\n",
|
|
169
|
+
template: "<!--\n The label lives in a template rather than inside each branch below. A default\n `<ng-content />` written into two `@if` branches fills only ONE of them — the\n last in static order — and the other renders empty, with no template error and\n nothing in the console. This component has been broken exactly that way\n before; stamping one template from either branch keeps two anchors and one\n projection.\n-->\n<ng-template #label>\n @if (icon(); as i) {\n <wr-icon class=\"wr-breadcrumbs__icon\" [name]=\"i\" />\n }\n <ng-content />\n</ng-template>\n\n@if (isRouter()) {\n <!--\n Only ROUTER crumbs get `RouterLink`. Applied unconditionally it owns the\n anchor's `href` and writes null into it whenever `routerLink` is null —\n which silently turned every `href`-based crumb, a documented input, into\n text that navigates nowhere.\n -->\n <a [class]=\"rootClass()\" [routerLink]=\"routerLink()\" [queryParams]=\"queryParams()\">\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n} @else {\n <a\n [class]=\"rootClass()\"\n [attr.href]=\"href()\"\n [attr.aria-current]=\"isLink() ? null : 'page'\"\n [attr.role]=\"isLink() ? null : 'text'\"\n [attr.tabindex]=\"isLink() ? null : -1\"\n [attr.target]=\"external() ? '_blank' : null\"\n [attr.rel]=\"external() ? 'noreferrer noopener' : null\"\n >\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n}\n",
|
|
162
170
|
dependencies: [
|
|
163
171
|
{
|
|
164
172
|
kind: "directive",
|
|
@@ -218,7 +226,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
218
226
|
class: "wr-breadcrumbs__item",
|
|
219
227
|
role: "listitem"
|
|
220
228
|
},
|
|
221
|
-
template: "<!--\n The label lives in a template rather than inside each branch below. A default\n `<ng-content />` written into two `@if` branches fills only ONE of them — the\n last in static order — and the other renders empty, with no template error and\n nothing in the console. This component has been broken exactly that way\n before; stamping one template from either branch keeps two anchors and one\n projection.\n-->\n<ng-template #label>\n @if (icon(); as i) {\n <wr-icon class=\"wr-breadcrumbs__icon\" [name]=\"i\" />\n }\n <ng-content />\n</ng-template>\n\n@if (isRouter()) {\n <!--\n Only ROUTER crumbs get `RouterLink`. Applied unconditionally it owns the\n anchor's `href` and writes null into it whenever `routerLink` is null —\n which silently turned every `href`-based crumb, a documented input, into\n text that navigates nowhere.\n -->\n <a [class]=\"rootClass()\" [routerLink]=\"routerLink()\">\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n} @else {\n <a\n [class]=\"rootClass()\"\n [attr.href]=\"href()\"\n [attr.aria-current]=\"isLink() ? null : 'page'\"\n [attr.role]=\"isLink() ? null : 'text'\"\n [attr.tabindex]=\"isLink() ? null : -1\"\n [attr.target]=\"external() ? '_blank' : null\"\n [attr.rel]=\"external() ? 'noreferrer noopener' : null\"\n >\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n}\n"
|
|
229
|
+
template: "<!--\n The label lives in a template rather than inside each branch below. A default\n `<ng-content />` written into two `@if` branches fills only ONE of them — the\n last in static order — and the other renders empty, with no template error and\n nothing in the console. This component has been broken exactly that way\n before; stamping one template from either branch keeps two anchors and one\n projection.\n-->\n<ng-template #label>\n @if (icon(); as i) {\n <wr-icon class=\"wr-breadcrumbs__icon\" [name]=\"i\" />\n }\n <ng-content />\n</ng-template>\n\n@if (isRouter()) {\n <!--\n Only ROUTER crumbs get `RouterLink`. Applied unconditionally it owns the\n anchor's `href` and writes null into it whenever `routerLink` is null —\n which silently turned every `href`-based crumb, a documented input, into\n text that navigates nowhere.\n -->\n <a [class]=\"rootClass()\" [routerLink]=\"routerLink()\" [queryParams]=\"queryParams()\">\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n} @else {\n <a\n [class]=\"rootClass()\"\n [attr.href]=\"href()\"\n [attr.aria-current]=\"isLink() ? null : 'page'\"\n [attr.role]=\"isLink() ? null : 'text'\"\n [attr.tabindex]=\"isLink() ? null : -1\"\n [attr.target]=\"external() ? '_blank' : null\"\n [attr.rel]=\"external() ? 'noreferrer noopener' : null\"\n >\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n}\n"
|
|
222
230
|
}]
|
|
223
231
|
}],
|
|
224
232
|
propDecorators: {
|
|
@@ -238,6 +246,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
238
246
|
required: false
|
|
239
247
|
}]
|
|
240
248
|
}],
|
|
249
|
+
queryParams: [{
|
|
250
|
+
type: i0.Input,
|
|
251
|
+
args: [{
|
|
252
|
+
isSignal: true,
|
|
253
|
+
alias: "queryParams",
|
|
254
|
+
required: false
|
|
255
|
+
}]
|
|
256
|
+
}],
|
|
241
257
|
external: [{
|
|
242
258
|
type: i0.Input,
|
|
243
259
|
args: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-breadcrumbs.mjs","names":[],"sources":["../../../projects/lib/breadcrumbs/breadcrumbs.ts","../../../projects/lib/breadcrumbs/breadcrumbs.html","../../../projects/lib/breadcrumbs/breadcrumbs-item.ts","../../../projects/lib/breadcrumbs/breadcrumbs-item.html"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\n\n/** Escape a string for use inside a double-quoted CSS `<string>`. */\nfunction cssString(value: string): string {\n return value.replace(/[\\\\\"]/g, '\\\\$&').replace(/[\\n\\r\\f]/g, char => `\\\\${char.codePointAt(0)!.toString(16)} `);\n}\n\n/**\n * Breadcrumb navigation. Project `<wr-breadcrumbs-item>` children — each keeps\n * its own element and takes `role=\"listitem\"` inside the `<ol>` rather than\n * rendering an `<li>`, separated by the configured glyph (default `/`). The\n * container exposes the `nav[aria-label]` landmark required by WCAG.\n *\n * @example\n * ```html\n * <wr-breadcrumbs>\n * <wr-breadcrumbs-item routerLink=\"/\">Home</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item routerLink=\"/docs\">Docs</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item>Current</wr-breadcrumbs-item>\n * </wr-breadcrumbs>\n *\n * <!-- Custom separator -->\n * <wr-breadcrumbs separator=\"›\">…</wr-breadcrumbs>\n * ```\n *\n * @see https://ngwr.dev/reference/components/breadcrumbs\n */\n@Component({\n selector: 'wr-breadcrumbs',\n templateUrl: './breadcrumbs.html',\n styleUrl: './breadcrumbs.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-breadcrumbs',\n '[style.--wr-breadcrumbs-separator]': 'separatorValue()',\n },\n})\nexport class WrBreadcrumbs {\n /** Separator glyph between items. Any short string. @default '/' */\n readonly separator = input('/');\n\n /**\n * Accessible label for the `nav` landmark. Falls back to `breadcrumbs.label`,\n * then `'Breadcrumbs'`.\n */\n readonly ariaLabel = input<string | null>(null);\n\n // The English default used to live on the input itself, which made this the one\n // landmark in the library a catalog could not reach: `wr-anchor` and `wr-sidebar`\n // announced in Russian on the same page while this one stayed \"Breadcrumbs\", and\n // the only escape was restating `[ariaLabel]` on every trail.\n protected readonly resolvedAriaLabel = useI18nText(this.ariaLabel, 'breadcrumbs.label', 'Breadcrumbs');\n\n // The glyph is WRAPPED in quotes here and unwrapped by `content:` in the\n // stylesheet, so an unescaped `\"` inside it closes the library's own string\n // and the rest of the value is parsed as CSS — `/\" url(\"…\") \"` computes to\n // `content: \"/\" url(\"…\") \"\"`, an image the browser fetches. Escaping is the\n // whole fix, and it is lossless: a separator that IS a quote still renders.\n protected readonly separatorValue = computed(() => `\"${cssString(this.separator())}\"`);\n}\n","<nav class=\"wr-breadcrumbs__nav\" [attr.aria-label]=\"resolvedAriaLabel()\">\n <ol class=\"wr-breadcrumbs__list\">\n <ng-content />\n </ol>\n</nav>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\n\n/**\n * One row inside `<wr-breadcrumbs>`. The host itself is the row — a\n * `<wr-breadcrumbs-item role=\"listitem\" class=\"wr-breadcrumbs__item\">`\n * inside the parent's `<ol>` — and it contains either a real\n * `<a class=\"wr-breadcrumbs__link\">` (when `[href]` or `[routerLink]` is\n * set) or, for the current crumb, a non-interactive\n * `<a class=\"wr-breadcrumbs__current\" role=\"text\" tabindex=\"-1\"\n * aria-current=\"page\">` (when neither is set — typically the last crumb).\n *\n * @example\n * ```html\n * <wr-breadcrumbs-item icon=\"home\" routerLink=\"/\">Home</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item href=\"https://ngwr.dev\">External</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item>Current page</wr-breadcrumbs-item>\n * ```\n */\n@Component({\n selector: 'wr-breadcrumbs-item',\n templateUrl: './breadcrumbs-item.html',\n encapsulation: ViewEncapsulation.None,\n imports: [NgTemplateOutlet, RouterLink, WrIcon],\n host: { class: 'wr-breadcrumbs__item', role: 'listitem' },\n})\nexport class WrBreadcrumbsItem {\n /** Plain anchor href. Overridden by `routerLink` when both are set. */\n readonly href = input<string | null>(null);\n\n /** Angular router target. Anything `RouterLink` accepts (string or `any[]`). */\n readonly routerLink = input<string | readonly unknown[] | null>(null);\n\n /** Open external `href` in a new tab. Ignored when `routerLink` is set. @default false */\n readonly external = input(false);\n\n /** Optional leading icon rendered inline before the label. @default null */\n readonly icon = input<WrIconName | null>(null);\n\n protected readonly isLink = computed(() => this.href() != null || this.routerLink() != null);\n protected readonly isRouter = computed(() => this.routerLink() != null);\n\n protected readonly rootClass = computed(() => (this.isLink() ? 'wr-breadcrumbs__link' : 'wr-breadcrumbs__current'));\n}\n","<!--\n The label lives in a template rather than inside each branch below. A default\n `<ng-content />` written into two `@if` branches fills only ONE of them — the\n last in static order — and the other renders empty, with no template error and\n nothing in the console. This component has been broken exactly that way\n before; stamping one template from either branch keeps two anchors and one\n projection.\n-->\n<ng-template #label>\n @if (icon(); as i) {\n <wr-icon class=\"wr-breadcrumbs__icon\" [name]=\"i\" />\n }\n <ng-content />\n</ng-template>\n\n@if (isRouter()) {\n <!--\n Only ROUTER crumbs get `RouterLink`. Applied unconditionally it owns the\n anchor's `href` and writes null into it whenever `routerLink` is null —\n which silently turned every `href`-based crumb, a documented input, into\n text that navigates nowhere.\n -->\n <a [class]=\"rootClass()\" [routerLink]=\"routerLink()\">\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n} @else {\n <a\n [class]=\"rootClass()\"\n [attr.href]=\"href()\"\n [attr.aria-current]=\"isLink() ? null : 'page'\"\n [attr.role]=\"isLink() ? null : 'text'\"\n [attr.tabindex]=\"isLink() ? null : -1\"\n [attr.target]=\"external() ? '_blank' : null\"\n [attr.rel]=\"external() ? 'noreferrer noopener' : null\"\n >\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngwr-breadcrumbs.mjs","names":[],"sources":["../../../projects/lib/breadcrumbs/breadcrumbs.ts","../../../projects/lib/breadcrumbs/breadcrumbs.html","../../../projects/lib/breadcrumbs/breadcrumbs-item.ts","../../../projects/lib/breadcrumbs/breadcrumbs-item.html"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\n\n/** Escape a string for use inside a double-quoted CSS `<string>`. */\nfunction cssString(value: string): string {\n return value.replace(/[\\\\\"]/g, '\\\\$&').replace(/[\\n\\r\\f]/g, char => `\\\\${char.codePointAt(0)!.toString(16)} `);\n}\n\n/**\n * Breadcrumb navigation. Project `<wr-breadcrumbs-item>` children — each keeps\n * its own element and takes `role=\"listitem\"` inside the `<ol>` rather than\n * rendering an `<li>`, separated by the configured glyph (default `/`). The\n * container exposes the `nav[aria-label]` landmark required by WCAG.\n *\n * @example\n * ```html\n * <wr-breadcrumbs>\n * <wr-breadcrumbs-item routerLink=\"/\">Home</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item routerLink=\"/docs\">Docs</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item>Current</wr-breadcrumbs-item>\n * </wr-breadcrumbs>\n *\n * <!-- Custom separator -->\n * <wr-breadcrumbs separator=\"›\">…</wr-breadcrumbs>\n * ```\n *\n * @see https://ngwr.dev/reference/components/breadcrumbs\n */\n@Component({\n selector: 'wr-breadcrumbs',\n templateUrl: './breadcrumbs.html',\n styleUrl: './breadcrumbs.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-breadcrumbs',\n '[style.--wr-breadcrumbs-separator]': 'separatorValue()',\n },\n})\nexport class WrBreadcrumbs {\n /** Separator glyph between items. Any short string. @default '/' */\n readonly separator = input('/');\n\n /**\n * Accessible label for the `nav` landmark. Falls back to `breadcrumbs.label`,\n * then `'Breadcrumbs'`.\n */\n readonly ariaLabel = input<string | null>(null);\n\n // The English default used to live on the input itself, which made this the one\n // landmark in the library a catalog could not reach: `wr-anchor` and `wr-sidebar`\n // announced in Russian on the same page while this one stayed \"Breadcrumbs\", and\n // the only escape was restating `[ariaLabel]` on every trail.\n protected readonly resolvedAriaLabel = useI18nText(this.ariaLabel, 'breadcrumbs.label', 'Breadcrumbs');\n\n // The glyph is WRAPPED in quotes here and unwrapped by `content:` in the\n // stylesheet, so an unescaped `\"` inside it closes the library's own string\n // and the rest of the value is parsed as CSS — `/\" url(\"…\") \"` computes to\n // `content: \"/\" url(\"…\") \"\"`, an image the browser fetches. Escaping is the\n // whole fix, and it is lossless: a separator that IS a quote still renders.\n protected readonly separatorValue = computed(() => `\"${cssString(this.separator())}\"`);\n}\n","<nav class=\"wr-breadcrumbs__nav\" [attr.aria-label]=\"resolvedAriaLabel()\">\n <ol class=\"wr-breadcrumbs__list\">\n <ng-content />\n </ol>\n</nav>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\nimport { type Params, RouterLink } from '@angular/router';\n\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\n\n/**\n * One row inside `<wr-breadcrumbs>`. The host itself is the row — a\n * `<wr-breadcrumbs-item role=\"listitem\" class=\"wr-breadcrumbs__item\">`\n * inside the parent's `<ol>` — and it contains either a real\n * `<a class=\"wr-breadcrumbs__link\">` (when `[href]` or `[routerLink]` is\n * set) or, for the current crumb, a non-interactive\n * `<a class=\"wr-breadcrumbs__current\" role=\"text\" tabindex=\"-1\"\n * aria-current=\"page\">` (when neither is set — typically the last crumb).\n *\n * @example\n * ```html\n * <wr-breadcrumbs-item icon=\"home\" routerLink=\"/\">Home</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item routerLink=\"/debts\" [queryParams]=\"{ date: day }\">Debts</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item href=\"https://ngwr.dev\">External</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item>Current page</wr-breadcrumbs-item>\n * ```\n */\n@Component({\n selector: 'wr-breadcrumbs-item',\n templateUrl: './breadcrumbs-item.html',\n encapsulation: ViewEncapsulation.None,\n imports: [NgTemplateOutlet, RouterLink, WrIcon],\n host: { class: 'wr-breadcrumbs__item', role: 'listitem' },\n})\nexport class WrBreadcrumbsItem {\n /** Plain anchor href. Overridden by `routerLink` when both are set. */\n readonly href = input<string | null>(null);\n\n /** Angular router target. Anything `RouterLink` accepts (string or `any[]`). */\n readonly routerLink = input<string | readonly unknown[] | null>(null);\n\n /**\n * Query parameters for a `routerLink` crumb, the way `RouterLink` takes them.\n * A `?` written into `routerLink` is part of the path, and the router escapes\n * it: `/debts?date=1` became `/debts%3Fdate%3D1`. Ignored without `routerLink`.\n *\n * @default null\n */\n readonly queryParams = input<Params | null>(null);\n\n /** Open external `href` in a new tab. Ignored when `routerLink` is set. @default false */\n readonly external = input(false);\n\n /** Optional leading icon rendered inline before the label. @default null */\n readonly icon = input<WrIconName | null>(null);\n\n protected readonly isLink = computed(() => this.href() != null || this.routerLink() != null);\n protected readonly isRouter = computed(() => this.routerLink() != null);\n\n protected readonly rootClass = computed(() => (this.isLink() ? 'wr-breadcrumbs__link' : 'wr-breadcrumbs__current'));\n}\n","<!--\n The label lives in a template rather than inside each branch below. A default\n `<ng-content />` written into two `@if` branches fills only ONE of them — the\n last in static order — and the other renders empty, with no template error and\n nothing in the console. This component has been broken exactly that way\n before; stamping one template from either branch keeps two anchors and one\n projection.\n-->\n<ng-template #label>\n @if (icon(); as i) {\n <wr-icon class=\"wr-breadcrumbs__icon\" [name]=\"i\" />\n }\n <ng-content />\n</ng-template>\n\n@if (isRouter()) {\n <!--\n Only ROUTER crumbs get `RouterLink`. Applied unconditionally it owns the\n anchor's `href` and writes null into it whenever `routerLink` is null —\n which silently turned every `href`-based crumb, a documented input, into\n text that navigates nowhere.\n -->\n <a [class]=\"rootClass()\" [routerLink]=\"routerLink()\" [queryParams]=\"queryParams()\">\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n} @else {\n <a\n [class]=\"rootClass()\"\n [attr.href]=\"href()\"\n [attr.aria-current]=\"isLink() ? null : 'page'\"\n [attr.role]=\"isLink() ? null : 'text'\"\n [attr.tabindex]=\"isLink() ? null : -1\"\n [attr.target]=\"external() ? '_blank' : null\"\n [attr.rel]=\"external() ? 'noreferrer noopener' : null\"\n >\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAS,UAAU,OAAa;CAC9B,OAAO,MAAM,QAAQ,UAAU,MAAM,CAAC,CAAC,QAAQ,cAAa,SAAQ,KAAK,KAAK,YAAY,CAAC,CAAE,CAAC,SAAS,EAAE,EAAC,EAAG;AAC/G;AAgCA,IAAa,gBAAb,MAAa,cAAa;CAEf,YAAY,MAAM,KAAI,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAMtB,YAAY,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAM5B,oBAAoB,YAAY,KAAK,WAAW,qBAAqB,aAAa;CAOlF,iBAAiB,eAAe,IAAI,UAAU,KAAK,UAAS,CAAE,EAAC,IAAI,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CArB3E,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAa,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAb,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAa,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,MAAA;GAAA,YAAA,EAAA,oCAAA,mBAAA;GAAA,gBAAA;EAAA;EAAA,UAAA;EAAA,UC9C1B;EAKA,QAAA,CAAA,osRAAA;EAAA,eAAA,GAAA,kBAAA;CAAA,CAAA;;ADyCa,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAa,YAAA,CAAA;EAVzB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAgB,eAGX,kBAAkB;GAAI,MAC/B;IACJ,OAAO;IACP,sCAAsC;GACvC;GAAA,UAAA;GAAA,QAAA,CAAA,osRAAA;EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;AEPH,IAAa,oBAAb,MAAa,kBAAiB;CAEnB,OAAO,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAGjC,aAAa,MAA0C,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAS5D,cAAc,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAGxC,WAAW,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAGvB,OAAO,MAAyB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAE3B,SAAS,eAAe,KAAK,KAAI,KAAM,QAAQ,KAAK,WAAU,KAAM,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACzE,WAAW,eAAe,KAAK,WAAU,KAAM,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEpD,YAAY,eAAgB,KAAK,OAAM,IAAK,yBAAyB,2BAA2B,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAzBxG,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAiB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAjB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAiB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,YAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,MAAA;GAAA,YAAA,EAAA,QAAA,WAAA;GAAA,gBAAA;EAAA;EAAA,UAAA;EAAA,UCrC9B;EAsCA,cAAA;GAAA;IAAA,MAAA;IAAA,MDJY;IAAgB,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAU,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAM,UAAA;IAAA,QAAA,CAAA,MAAA;GAAA;EAAA;EAAA,eAAA,GAAA,kBAAA;CAAA,CAAA;;AAGnC,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAiB,YAAA,CAAA;EAP7B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAqB,eAEhB,kBAAkB;GAAI,SAC5B;IAAC;IAAkB;IAAY;GAAM;GAAC,MACzC;IAAE,OAAO;IAAwB,MAAM;GAAU;GAAE,UAAA;EAAA,CAAA"}
|
package/fesm2022/ngwr-hotkey.mjs
CHANGED
|
@@ -21,6 +21,27 @@ const KEY_ALIASES = {
|
|
|
21
21
|
right: "arrowright",
|
|
22
22
|
del: "delete"
|
|
23
23
|
};
|
|
24
|
+
const PUNCTUATION_CODES = {
|
|
25
|
+
Backquote: "`",
|
|
26
|
+
Minus: "-",
|
|
27
|
+
Equal: "=",
|
|
28
|
+
BracketLeft: "[",
|
|
29
|
+
BracketRight: "]",
|
|
30
|
+
Backslash: "\\",
|
|
31
|
+
Semicolon: ";",
|
|
32
|
+
Quote: "'",
|
|
33
|
+
Comma: ",",
|
|
34
|
+
Period: ".",
|
|
35
|
+
Slash: "/"
|
|
36
|
+
};
|
|
37
|
+
function physicalKey(code) {
|
|
38
|
+
if (/^Key[A-Z]$/.test(code)) return code.slice(3).toLowerCase();
|
|
39
|
+
if (/^Digit\d$/.test(code)) return code.slice(5);
|
|
40
|
+
return PUNCTUATION_CODES[code] ?? null;
|
|
41
|
+
}
|
|
42
|
+
function isNonLatinLetter(key) {
|
|
43
|
+
return /^\p{L}$/u.test(key) && !/^\p{Script=Latin}$/u.test(key);
|
|
44
|
+
}
|
|
24
45
|
function parseHotkeySpec(spec, isMac = false) {
|
|
25
46
|
const tokens = spec.split("+").map((t) => t.trim().toLowerCase()).filter(Boolean);
|
|
26
47
|
let ctrl = false;
|
|
@@ -66,7 +87,8 @@ function matchesHotkey(event, parsed) {
|
|
|
66
87
|
if (event.altKey !== parsed.alt) return false;
|
|
67
88
|
if (event.shiftKey !== parsed.shift) return false;
|
|
68
89
|
if (event.metaKey !== parsed.meta) return false;
|
|
69
|
-
|
|
90
|
+
if (event.key.toLowerCase() === parsed.key) return true;
|
|
91
|
+
return !event.altKey && isNonLatinLetter(event.key) && physicalKey(event.code) === parsed.key;
|
|
70
92
|
}
|
|
71
93
|
/**
|
|
72
94
|
* @license
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-hotkey.mjs","names":["DOCUMENT"],"sources":["../../../projects/lib/hotkey/parse-spec.ts","../../../projects/lib/hotkey/wr-hotkey.ts","../../../projects/lib/hotkey/wr-hotkey-binding.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrHotkeySpec } from './types';\n\n/** Map of user-friendly aliases to canonical `KeyboardEvent.key` strings. */\nconst KEY_ALIASES: Readonly<Record<string, string>> = {\n esc: 'escape',\n space: ' ',\n spacebar: ' ',\n enter: 'enter',\n return: 'enter',\n up: 'arrowup',\n down: 'arrowdown',\n left: 'arrowleft',\n right: 'arrowright',\n del: 'delete',\n};\n\n/** Normalised representation of a hotkey spec — easy to match against an event. */\ninterface WrParsedHotkey {\n readonly ctrl: boolean;\n readonly alt: boolean;\n readonly shift: boolean;\n readonly meta: boolean;\n /** Lowercased `KeyboardEvent.key` value the spec matches. */\n readonly key: string;\n}\n\n/**\n * Parse a hotkey spec like `'mod+shift+k'` into a normalised structure.\n *\n * @param spec - the spec to parse\n * @param isMac - when true, `mod` resolves to `meta` (Cmd); otherwise `ctrl`\n */\nfunction parseHotkeySpec(spec: WrHotkeySpec, isMac = false): WrParsedHotkey {\n const tokens = spec\n .split('+')\n .map(t => t.trim().toLowerCase())\n .filter(Boolean);\n\n let ctrl = false;\n let alt = false;\n let shift = false;\n let meta = false;\n let key = '';\n\n for (const token of tokens) {\n switch (token) {\n case 'ctrl':\n case 'control':\n ctrl = true;\n break;\n case 'alt':\n case 'option':\n alt = true;\n break;\n case 'shift':\n shift = true;\n break;\n case 'cmd':\n case 'command':\n case 'meta':\n case 'super':\n case 'win':\n meta = true;\n break;\n case 'mod':\n if (isMac) meta = true;\n else ctrl = true;\n break;\n default:\n key = KEY_ALIASES[token] ?? token;\n break;\n }\n }\n\n return { ctrl, alt, shift, meta, key };\n}\n\n/** Does `event` satisfy the parsed hotkey? */\nfunction matchesHotkey(event: KeyboardEvent, parsed: WrParsedHotkey): boolean {\n if (event.ctrlKey !== parsed.ctrl) return false;\n if (event.altKey !== parsed.alt) return false;\n if (event.shiftKey !== parsed.shift) return false;\n if (event.metaKey !== parsed.meta) return false;\n return event.key.toLowerCase() === parsed.key;\n}\n\nexport { parseHotkeySpec, matchesHotkey };\nexport type { WrParsedHotkey };\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { DOCUMENT } from '@angular/common';\nimport { DestroyRef, Service, NgZone, inject } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\n\nimport { matchesHotkey, parseHotkeySpec, type WrParsedHotkey } from './parse-spec';\nimport type { WrHotkeyHandle, WrHotkeyOptions, WrHotkeySpec } from './types';\n\ninterface Binding {\n readonly parsed: WrParsedHotkey;\n readonly handler: (event: KeyboardEvent) => void;\n readonly options: Required<WrHotkeyOptions>;\n}\n\nconst FALLBACK_OPTIONS: Required<WrHotkeyOptions> = {\n element: undefined as unknown as HTMLElement,\n preventDefault: true,\n allowInInput: false,\n priority: 0,\n};\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n const tag = target.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;\n return target.isContentEditable;\n}\n\n/**\n * Global keybinding registry.\n *\n * Bindings are keyed off `KeyboardEvent.key` + modifier state. Multiple\n * handlers per chord fire in priority order; a handler that calls\n * `event.preventDefault()` stops lower-priority bindings on that key.\n *\n * The listener runs outside Angular — only matched bindings re-enter\n * the zone, so an idle page doesn't trigger CD on every keystroke.\n *\n * Use `[wrHotkey]` for declarative element-scoped bindings.\n *\n * @example\n * ```ts\n * const hotkeys = inject(WrHotkey);\n * const handle = hotkeys.bind('mod+k', () => openCommandPalette());\n * // ...later\n * handle.unbind();\n * ```\n *\n * @see https://ngwr.dev/reference/services/hotkey\n */\n@Service()\nexport class WrHotkey {\n private readonly doc = inject(DOCUMENT);\n private readonly zone = inject(NgZone);\n private readonly platform = inject(WrPlatform);\n private readonly destroyRef = inject(DestroyRef);\n\n private readonly isMac = (this.platform.userAgent ?? '').toLowerCase().includes('mac');\n\n /** Bindings grouped by listener target. */\n private readonly registries = new Map<EventTarget, Set<Binding>>();\n\n constructor() {\n // Every listener belongs to this injector. Provided at the root that is the\n // whole application, but a route or component that provides its own\n // `WrHotkey` used to leave its `keydown` listeners on the document after it\n // was destroyed — still dispatching into handlers whose component was gone.\n this.destroyRef.onDestroy(() => {\n for (const target of [...this.listeners.keys()]) this.detach(target);\n this.registries.clear();\n });\n }\n\n /** Register a binding. */\n bind(spec: WrHotkeySpec, handler: (event: KeyboardEvent) => void, options: WrHotkeyOptions = {}): WrHotkeyHandle {\n const parsed = parseHotkeySpec(spec, this.isMac);\n const resolved: Required<WrHotkeyOptions> = { ...FALLBACK_OPTIONS, ...options };\n const target: EventTarget = resolved.element ?? this.doc;\n const binding: Binding = { parsed, handler, options: resolved };\n\n let bucket = this.registries.get(target);\n if (!bucket) {\n bucket = new Set();\n this.registries.set(target, bucket);\n this.attach(target);\n }\n bucket.add(binding);\n\n return {\n unbind: () => {\n // Look the bucket up again rather than closing over it, and let\n // `Set.delete` report whether this binding was still in it. The captured\n // bucket could be a REPLACED one: unbind the last binding, register a\n // new one for the same target, then call the old handle a second time —\n // which is ordinary, a directive releasing on destroy and on an input\n // change — and the stale empty set read as \"nothing left here\", taking\n // the live binding's listener down with it.\n const current = this.registries.get(target);\n if (!current?.delete(binding)) return;\n if (current.size === 0) {\n this.registries.delete(target);\n this.detach(target);\n }\n },\n };\n }\n\n // Internals\n\n private readonly listeners = new Map<EventTarget, EventListener>();\n\n private attach(target: EventTarget): void {\n const listener: EventListener = event => this.dispatch(target, event as KeyboardEvent);\n this.zone.runOutsideAngular(() => target.addEventListener('keydown', listener));\n this.listeners.set(target, listener);\n }\n\n private detach(target: EventTarget): void {\n const listener = this.listeners.get(target);\n if (!listener) return;\n target.removeEventListener('keydown', listener);\n this.listeners.delete(target);\n }\n\n private dispatch(target: EventTarget, event: KeyboardEvent): void {\n const bucket = this.registries.get(target);\n if (!bucket || bucket.size === 0) return;\n\n const matches: Binding[] = [];\n for (const binding of bucket) {\n if (!matchesHotkey(event, binding.parsed)) continue;\n if (!binding.options.allowInInput && isEditableTarget(event.target)) continue;\n matches.push(binding);\n }\n if (matches.length === 0) return;\n\n matches.sort((a, b) => b.options.priority - a.options.priority);\n\n this.zone.run(() => {\n // Two different questions, one flag. `preventDefault` is browser\n // suppression; `defaultPrevented` after a handler ran is how this service\n // reads \"that handler claimed the chord\". Applying the option first and\n // then reading the flag back meant the service saw its OWN mark as a\n // claim, so under the shipped default (`preventDefault: true`) only the\n // top-priority binding on a chord ever ran. Deferring the option's call to\n // the end keeps the flag inside the loop reporting only what a HANDLER\n // did — the rule this class already documents — and leaves a binding free\n // to suppress the browser AND claim the chord. The entry snapshot matters\n // too: another listener earlier in the propagation path may have\n // prevented the event already, and that is nobody's claim here.\n const preventedOnEntry = event.defaultPrevented;\n let suppress = false;\n\n for (const binding of matches) {\n binding.handler(event);\n if (binding.options.preventDefault) suppress = true;\n if (!preventedOnEntry && event.defaultPrevented) break;\n }\n\n if (suppress) event.preventDefault();\n });\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { DestroyRef, Directive, ElementRef, effect, inject, input, output } from '@angular/core';\n\nimport type { WrHotkeyHandle, WrHotkeySpec } from './types';\nimport { WrHotkey } from './wr-hotkey';\n\n/**\n * Declarative wrapper around {@link WrHotkey}.\n *\n * Binds on init (and re-binds when the spec changes), unbinds on destroy.\n * Defaults to global scope so the binding works regardless of focus —\n * pass `[scoped]=\"true\"` to limit it to the host element.\n *\n * @example\n * ```html\n * <button (wrHotkeyMatch)=\"open()\" [wrHotkey]=\"'mod+k'\">Open palette</button>\n * <div tabindex=\"0\" [wrHotkey]=\"'escape'\" [scoped]=\"true\" (wrHotkeyMatch)=\"close()\">…</div>\n * ```\n */\n@Directive({ selector: '[wrHotkey]' })\nexport class WrHotkeyBinding {\n /**\n * The chord to listen for — `'mod+k'`, `'shift+?'`, or the full spec object.\n * `mod` resolves to ⌘ on macOS and Ctrl everywhere else.\n */\n readonly wrHotkey = input.required<WrHotkeySpec>();\n\n /** Scope the binding to the host element instead of `document`. @default false */\n readonly scoped = input(false, { transform: coerceBooleanProperty });\n\n /** Fire even when an input / textarea has focus. @default false */\n readonly allowInInput = input(false, { transform: coerceBooleanProperty });\n\n /** Suppress the default action when the binding fires. @default true */\n readonly preventDefault = input(true, { transform: coerceBooleanProperty });\n\n /** Emits the original KeyboardEvent on match. */\n readonly wrHotkeyMatch = output<KeyboardEvent>();\n\n private readonly hotkeys = inject(WrHotkey);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private handle: WrHotkeyHandle | null = null;\n\n constructor() {\n effect(() => {\n this.handle?.unbind();\n this.handle = this.hotkeys.bind(this.wrHotkey(), event => this.wrHotkeyMatch.emit(event), {\n element: this.scoped() ? this.host.nativeElement : undefined,\n allowInInput: this.allowInInput(),\n preventDefault: this.preventDefault(),\n });\n });\n inject(DestroyRef).onDestroy(() => this.handle?.unbind());\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngwr-hotkey.mjs","names":["DOCUMENT"],"sources":["../../../projects/lib/hotkey/parse-spec.ts","../../../projects/lib/hotkey/wr-hotkey.ts","../../../projects/lib/hotkey/wr-hotkey-binding.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrHotkeySpec } from './types';\n\n/** Map of user-friendly aliases to canonical `KeyboardEvent.key` strings. */\nconst KEY_ALIASES: Readonly<Record<string, string>> = {\n esc: 'escape',\n space: ' ',\n spacebar: ' ',\n enter: 'enter',\n return: 'enter',\n up: 'arrowup',\n down: 'arrowdown',\n left: 'arrowleft',\n right: 'arrowright',\n del: 'delete',\n};\n\n/** What the US layout prints on each punctuation key, by `KeyboardEvent.code`. */\nconst PUNCTUATION_CODES: Readonly<Record<string, string>> = {\n Backquote: '`',\n Minus: '-',\n Equal: '=',\n BracketLeft: '[',\n BracketRight: ']',\n Backslash: '\\\\',\n Semicolon: ';',\n Quote: \"'\",\n Comma: ',',\n Period: '.',\n Slash: '/',\n};\n\n/** The key a spec names for a physical key, read off the US layout, or `null`. */\nfunction physicalKey(code: string): string | null {\n if (/^Key[A-Z]$/.test(code)) return code.slice(3).toLowerCase();\n if (/^Digit\\d$/.test(code)) return code.slice(5);\n return PUNCTUATION_CODES[code] ?? null;\n}\n\n/** One letter of a script other than Latin: what a Russian, Greek or Hebrew layout types. */\nfunction isNonLatinLetter(key: string): boolean {\n return /^\\p{L}$/u.test(key) && !/^\\p{Script=Latin}$/u.test(key);\n}\n\n/** Normalised representation of a hotkey spec — easy to match against an event. */\ninterface WrParsedHotkey {\n readonly ctrl: boolean;\n readonly alt: boolean;\n readonly shift: boolean;\n readonly meta: boolean;\n /** Lowercased `KeyboardEvent.key` value the spec matches. */\n readonly key: string;\n}\n\n/**\n * Parse a hotkey spec like `'mod+shift+k'` into a normalised structure.\n *\n * @param spec - the spec to parse\n * @param isMac - when true, `mod` resolves to `meta` (Cmd); otherwise `ctrl`\n */\nfunction parseHotkeySpec(spec: WrHotkeySpec, isMac = false): WrParsedHotkey {\n const tokens = spec\n .split('+')\n .map(t => t.trim().toLowerCase())\n .filter(Boolean);\n\n let ctrl = false;\n let alt = false;\n let shift = false;\n let meta = false;\n let key = '';\n\n for (const token of tokens) {\n switch (token) {\n case 'ctrl':\n case 'control':\n ctrl = true;\n break;\n case 'alt':\n case 'option':\n alt = true;\n break;\n case 'shift':\n shift = true;\n break;\n case 'cmd':\n case 'command':\n case 'meta':\n case 'super':\n case 'win':\n meta = true;\n break;\n case 'mod':\n if (isMac) meta = true;\n else ctrl = true;\n break;\n default:\n key = KEY_ALIASES[token] ?? token;\n break;\n }\n }\n\n return { ctrl, alt, shift, meta, key };\n}\n\n/**\n * Does `event` satisfy the parsed hotkey?\n *\n * The typed character decides, and the physical key only stands in when that\n * character is a letter of a non-Latin script. On a Russian layout the key\n * labelled K types `л`, so `mod+k` used to be dead for anyone who had not\n * switched to English; the same goes for Greek, Hebrew or Arabic. A Latin\n * layout never falls back, not even on a letter outside ASCII: on Dvorak the key\n * labelled K types `t`, and Turkish `ı` or German `ß` are keys of their own.\n * Nor does a chord holding Alt, since macOS Option and Windows AltGr type a\n * symbol on purpose, `€` on AltGr+E among them.\n */\nfunction matchesHotkey(event: KeyboardEvent, parsed: WrParsedHotkey): boolean {\n if (event.ctrlKey !== parsed.ctrl) return false;\n if (event.altKey !== parsed.alt) return false;\n if (event.shiftKey !== parsed.shift) return false;\n if (event.metaKey !== parsed.meta) return false;\n if (event.key.toLowerCase() === parsed.key) return true;\n return !event.altKey && isNonLatinLetter(event.key) && physicalKey(event.code) === parsed.key;\n}\n\nexport { parseHotkeySpec, matchesHotkey };\nexport type { WrParsedHotkey };\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { DOCUMENT } from '@angular/common';\nimport { DestroyRef, Service, NgZone, inject } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\n\nimport { matchesHotkey, parseHotkeySpec, type WrParsedHotkey } from './parse-spec';\nimport type { WrHotkeyHandle, WrHotkeyOptions, WrHotkeySpec } from './types';\n\ninterface Binding {\n readonly parsed: WrParsedHotkey;\n readonly handler: (event: KeyboardEvent) => void;\n readonly options: Required<WrHotkeyOptions>;\n}\n\nconst FALLBACK_OPTIONS: Required<WrHotkeyOptions> = {\n element: undefined as unknown as HTMLElement,\n preventDefault: true,\n allowInInput: false,\n priority: 0,\n};\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n const tag = target.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;\n return target.isContentEditable;\n}\n\n/**\n * Global keybinding registry.\n *\n * Bindings are keyed off `KeyboardEvent.key` + modifier state, and a letter\n * shortcut also fires on a non-Latin layout, by the physical key. Multiple\n * handlers per chord fire in priority order; a handler that calls\n * `event.preventDefault()` stops lower-priority bindings on that key.\n *\n * The listener runs outside Angular — only matched bindings re-enter\n * the zone, so an idle page doesn't trigger CD on every keystroke.\n *\n * Use `[wrHotkey]` for declarative element-scoped bindings.\n *\n * @example\n * ```ts\n * const hotkeys = inject(WrHotkey);\n * const handle = hotkeys.bind('mod+k', () => openCommandPalette());\n * // ...later\n * handle.unbind();\n * ```\n *\n * @see https://ngwr.dev/reference/services/hotkey\n */\n@Service()\nexport class WrHotkey {\n private readonly doc = inject(DOCUMENT);\n private readonly zone = inject(NgZone);\n private readonly platform = inject(WrPlatform);\n private readonly destroyRef = inject(DestroyRef);\n\n private readonly isMac = (this.platform.userAgent ?? '').toLowerCase().includes('mac');\n\n /** Bindings grouped by listener target. */\n private readonly registries = new Map<EventTarget, Set<Binding>>();\n\n constructor() {\n // Every listener belongs to this injector. Provided at the root that is the\n // whole application, but a route or component that provides its own\n // `WrHotkey` used to leave its `keydown` listeners on the document after it\n // was destroyed — still dispatching into handlers whose component was gone.\n this.destroyRef.onDestroy(() => {\n for (const target of [...this.listeners.keys()]) this.detach(target);\n this.registries.clear();\n });\n }\n\n /** Register a binding. */\n bind(spec: WrHotkeySpec, handler: (event: KeyboardEvent) => void, options: WrHotkeyOptions = {}): WrHotkeyHandle {\n const parsed = parseHotkeySpec(spec, this.isMac);\n const resolved: Required<WrHotkeyOptions> = { ...FALLBACK_OPTIONS, ...options };\n const target: EventTarget = resolved.element ?? this.doc;\n const binding: Binding = { parsed, handler, options: resolved };\n\n let bucket = this.registries.get(target);\n if (!bucket) {\n bucket = new Set();\n this.registries.set(target, bucket);\n this.attach(target);\n }\n bucket.add(binding);\n\n return {\n unbind: () => {\n // Look the bucket up again rather than closing over it, and let\n // `Set.delete` report whether this binding was still in it. The captured\n // bucket could be a REPLACED one: unbind the last binding, register a\n // new one for the same target, then call the old handle a second time —\n // which is ordinary, a directive releasing on destroy and on an input\n // change — and the stale empty set read as \"nothing left here\", taking\n // the live binding's listener down with it.\n const current = this.registries.get(target);\n if (!current?.delete(binding)) return;\n if (current.size === 0) {\n this.registries.delete(target);\n this.detach(target);\n }\n },\n };\n }\n\n // Internals\n\n private readonly listeners = new Map<EventTarget, EventListener>();\n\n private attach(target: EventTarget): void {\n const listener: EventListener = event => this.dispatch(target, event as KeyboardEvent);\n this.zone.runOutsideAngular(() => target.addEventListener('keydown', listener));\n this.listeners.set(target, listener);\n }\n\n private detach(target: EventTarget): void {\n const listener = this.listeners.get(target);\n if (!listener) return;\n target.removeEventListener('keydown', listener);\n this.listeners.delete(target);\n }\n\n private dispatch(target: EventTarget, event: KeyboardEvent): void {\n const bucket = this.registries.get(target);\n if (!bucket || bucket.size === 0) return;\n\n const matches: Binding[] = [];\n for (const binding of bucket) {\n if (!matchesHotkey(event, binding.parsed)) continue;\n if (!binding.options.allowInInput && isEditableTarget(event.target)) continue;\n matches.push(binding);\n }\n if (matches.length === 0) return;\n\n matches.sort((a, b) => b.options.priority - a.options.priority);\n\n this.zone.run(() => {\n // Two different questions, one flag. `preventDefault` is browser\n // suppression; `defaultPrevented` after a handler ran is how this service\n // reads \"that handler claimed the chord\". Applying the option first and\n // then reading the flag back meant the service saw its OWN mark as a\n // claim, so under the shipped default (`preventDefault: true`) only the\n // top-priority binding on a chord ever ran. Deferring the option's call to\n // the end keeps the flag inside the loop reporting only what a HANDLER\n // did — the rule this class already documents — and leaves a binding free\n // to suppress the browser AND claim the chord. The entry snapshot matters\n // too: another listener earlier in the propagation path may have\n // prevented the event already, and that is nobody's claim here.\n const preventedOnEntry = event.defaultPrevented;\n let suppress = false;\n\n for (const binding of matches) {\n binding.handler(event);\n if (binding.options.preventDefault) suppress = true;\n if (!preventedOnEntry && event.defaultPrevented) break;\n }\n\n if (suppress) event.preventDefault();\n });\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { DestroyRef, Directive, ElementRef, effect, inject, input, output } from '@angular/core';\n\nimport type { WrHotkeyHandle, WrHotkeySpec } from './types';\nimport { WrHotkey } from './wr-hotkey';\n\n/**\n * Declarative wrapper around {@link WrHotkey}.\n *\n * Binds on init (and re-binds when the spec changes), unbinds on destroy.\n * Defaults to global scope so the binding works regardless of focus —\n * pass `[scoped]=\"true\"` to limit it to the host element.\n *\n * @example\n * ```html\n * <button (wrHotkeyMatch)=\"open()\" [wrHotkey]=\"'mod+k'\">Open palette</button>\n * <div tabindex=\"0\" [wrHotkey]=\"'escape'\" [scoped]=\"true\" (wrHotkeyMatch)=\"close()\">…</div>\n * ```\n */\n@Directive({ selector: '[wrHotkey]' })\nexport class WrHotkeyBinding {\n /**\n * The chord to listen for — `'mod+k'`, `'shift+?'`, or the full spec object.\n * `mod` resolves to ⌘ on macOS and Ctrl everywhere else.\n */\n readonly wrHotkey = input.required<WrHotkeySpec>();\n\n /** Scope the binding to the host element instead of `document`. @default false */\n readonly scoped = input(false, { transform: coerceBooleanProperty });\n\n /** Fire even when an input / textarea has focus. @default false */\n readonly allowInInput = input(false, { transform: coerceBooleanProperty });\n\n /** Suppress the default action when the binding fires. @default true */\n readonly preventDefault = input(true, { transform: coerceBooleanProperty });\n\n /** Emits the original KeyboardEvent on match. */\n readonly wrHotkeyMatch = output<KeyboardEvent>();\n\n private readonly hotkeys = inject(WrHotkey);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private handle: WrHotkeyHandle | null = null;\n\n constructor() {\n effect(() => {\n this.handle?.unbind();\n this.handle = this.hotkeys.bind(this.wrHotkey(), event => this.wrHotkeyMatch.emit(event), {\n element: this.scoped() ? this.host.nativeElement : undefined,\n allowInInput: this.allowInInput(),\n preventDefault: this.preventDefault(),\n });\n });\n inject(DestroyRef).onDestroy(() => this.handle?.unbind());\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-i18n-ar.mjs","names":[],"sources":["../../../projects/lib/i18n/ar/public-api.ts"],"sourcesContent":["import { type WrI18nCatalog } from 'ngwr/i18n';\n\n/** Base Arabic catalog for ngwr built-in component strings. */\nexport const wrAr: WrI18nCatalog = {\n common: {\n ok: 'موافق',\n cancel: 'إلغاء',\n close: 'إغلاق',\n confirm: 'تأكيد',\n delete: 'حذف',\n save: 'حفظ',\n edit: 'تعديل',\n add: 'إضافة',\n remove: 'إزالة',\n clear: 'مسح',\n search: 'بحث',\n loading: 'جارٍ التحميل…',\n select: 'تحديد',\n next: 'التالي',\n previous: 'السابق',\n back: 'رجوع',\n today: 'اليوم',\n yesterday: 'أمس',\n tomorrow: 'غدًا',\n of: 'من',\n },\n pagination: {\n prev: 'الصفحة السابقة',\n next: 'الصفحة التالية',\n itemsPerPage: 'عدد العناصر في الصفحة',\n perPage: '{{size}} / صفحة',\n goToPage: 'الانتقال إلى الصفحة {{page}}',\n label: 'ترقيم الصفحات',\n pageOf: 'الصفحة {{current}} من {{total}}',\n range: '{{from}}–{{to}} من {{total}}',\n compact: '{{current}} / {{total}}',\n },\n table: {\n empty: 'لا توجد بيانات',\n loading: 'جارٍ التحميل…',\n sort: 'فرز عمود {{column}}',\n filter: 'تصفية عمود {{column}}',\n selectAll: 'تحديد كل الصفوف',\n selectRow: 'تحديد الصف',\n expandRow: 'تبديل تفاصيل الصف',\n toggleRow: 'تبديل الصفوف الفرعية',\n selectGroup: 'تحديد المجموعة',\n toggleGroup: 'تبديل المجموعة',\n noMatches: 'لا توجد نتائج مطابقة',\n search: 'بحث',\n reset: 'إعادة تعيين',\n },\n eventCalendar: {\n today: 'اليوم',\n previous: 'السابق',\n next: 'التالي',\n month: 'شهر',\n week: 'أسبوع',\n day: 'يوم',\n time: 'الوقت',\n allDay: 'طوال اليوم',\n label: 'التقويم',\n more: '+{{count}} أخرى',\n header: '{{month}} {{year}}',\n range: '{{from}} – {{to}}',\n chipLabel: '{{title}}، {{time}}',\n slotLabel: '{{time}} — {{date}}',\n allDayCellLabel: '{{label}} — {{date}}',\n },\n tour: {\n next: 'التالي',\n back: 'السابق',\n done: 'تم',\n skip: 'تخطي الجولة',\n progress: 'الخطوة {{current}} من {{total}}',\n },\n splitter: {\n divider: 'تغيير حجم الأجزاء',\n },\n stepper: {\n optional: 'اختياري',\n completed: 'مكتملة',\n },\n transfer: {\n source: 'المتاح',\n target: 'المحدد',\n search: 'بحث',\n empty: 'لا شيء هنا',\n selectAll: 'تحديد الكل',\n toTarget: 'النقل إلى المحدد',\n toSource: 'النقل إلى المتاح',\n count: '{{checked}} / {{total}}',\n selectAllAria: '{{pane}} — {{action}}',\n },\n form: {\n optional: 'اختياري',\n },\n select: {\n // The combobox's own accessible name, also read by `wr-tree` and\n // `wr-cascader`. «تحديد» is the word this catalog uses for marking rows and\n // groups that already exist; picking one value out of a list is «اختيار»,\n // which is also the verb the placeholder «اختر…» below opens with.\n label: 'اختيار',\n placeholder: 'اختر…',\n empty: 'لا توجد خيارات',\n clearSelection: 'مسح التحديد',\n removeItem: 'إزالة {{label}}',\n noResults: 'لا توجد نتائج',\n loading: 'جارٍ التحميل…',\n more: '+{{count}} أخرى',\n },\n // `tree` covers both inline display and combobox-mode pickers\n // (replaces the dropped `treeSelect` namespace).\n tree: {\n expand: 'توسيع',\n collapse: 'طي',\n placeholder: 'اختر…',\n clearSelection: 'مسح التحديد',\n removeItem: 'إزالة {{label}}',\n more: '+{{count}} أخرى',\n },\n commandPalette: {\n label: 'لوحة الأوامر',\n placeholder: 'اكتب أمرًا أو ابحث…',\n noResults: 'لا توجد نتائج',\n loading: 'جارٍ البحث…',\n escHint: 'esc',\n },\n empty: {\n noData: 'لا توجد بيانات',\n },\n fileUpload: {\n browse: 'انقر للاستعراض',\n dropZone: 'أو أفلت الملفات هنا',\n removeFile: 'إزالة الملف',\n invalid: 'نوع ملف غير مدعوم',\n tooBig: 'حجم الملف كبير جدًا',\n size: '{{value}} {{unit}}',\n unitByte: 'بايت',\n unitKb: 'كيلوبايت',\n unitMb: 'ميجابايت',\n unitGb: 'جيجابايت',\n unitTb: 'تيرابايت',\n },\n popconfirm: {\n label: 'تأكيد الإجراء',\n confirm: 'تأكيد',\n cancel: 'إلغاء',\n },\n toast: {\n region: 'الإشعارات',\n close: 'إغلاق',\n copy: 'نسخ',\n copied: 'تم النسخ',\n closeAll: 'إغلاق الكل',\n },\n input: {\n showPassword: 'إظهار كلمة المرور',\n hidePassword: 'إخفاء كلمة المرور',\n },\n inputNumber: {\n increment: 'زيادة',\n decrement: 'إنقاص',\n },\n inputOtp: {\n label: 'رمز التحقق',\n digit: 'الرقم {{index}}',\n character: 'الحرف {{index}}',\n },\n anchor: {\n label: 'جدول المحتويات',\n },\n avatar: {\n alt: 'الصورة الرمزية',\n },\n backTop: {\n label: 'العودة إلى الأعلى',\n },\n breadcrumbs: {\n label: 'مسار التنقل',\n },\n burger: {\n label: 'تبديل القائمة',\n },\n calendar: {\n prevMonth: 'الشهر السابق',\n nextMonth: 'الشهر التالي',\n prevYear: 'السنة السابقة',\n nextYear: 'السنة التالية',\n // The month / year pickers are `role=\"listbox\"`, and a listbox owes a\n // name — without one a screen reader announces the control as nothing at\n // all. Caught by `check:state-a11y` once a state finally opened the view.\n monthList: 'الأشهر',\n yearList: 'السنوات',\n prevYears: '12 سنة سابقة',\n nextYears: '12 سنة تالية',\n header: '{{month}} {{year}}',\n yearRange: '{{from}} – {{to}}',\n dayLabel: '{{weekday}}، {{date}}',\n },\n imageCropper: {\n empty: 'لا توجد صورة',\n window: 'منطقة الاقتصاص',\n keyHelp:\n 'مفاتيح الأسهم تحرّك منطقة الاقتصاص. اضغط باستمرار على Alt مع أحد مفاتيح الأسهم لتغيير حجمها، وعلى Shift لخطوات أكبر. ' +\n 'يُعلن عن المنطقة بقيم اليسار والأعلى والعرض والارتفاع بالبكسل داخل الصورة.',\n },\n sortableList: {\n keyHelp:\n 'اضغط مفتاح المسافة لالتقاط هذا العنصر، ثم استخدم مفاتيح الأسهم لتحريكه. ' +\n 'اضغط مفتاح المسافة مرة أخرى لإفلاته، أو Escape لإعادته إلى مكانه.',\n grabbed: 'تم الالتقاط. {{index}} من {{total}}.',\n moved: '{{index}} من {{total}}.',\n dropped: 'تم الإفلات. {{index}} من {{total}}.',\n cancelled: 'تم إلغاء النقل.',\n },\n colorPicker: {\n area: 'التشبع والسطوع، {{saturation}}% و{{brightness}}%',\n hue: 'درجة اللون',\n alpha: 'العتامة',\n formatHex: 'HEX',\n formatRgb: 'RGB',\n formatHsl: 'HSL',\n channelHex: 'HEX',\n channelRed: 'R',\n channelGreen: 'G',\n channelBlue: 'B',\n channelHue: 'H',\n channelSaturation: 'S%',\n channelLightness: 'L%',\n channelAlpha: 'A%',\n },\n barChart: {\n label: 'مخطط شريطي',\n total: 'الإجمالي',\n value: 'القيمة',\n datum: '{{label}}: {{value}}',\n },\n calendarHeatmap: {\n label: 'خريطة حرارية للتقويم',\n cell: '{{date}}: {{count}}',\n },\n lineChart: {\n label: 'مخطط خطي',\n areaLabel: 'مخطط مساحي',\n },\n donutChart: {\n label: 'مخطط دائري مجوف',\n pieLabel: 'مخطط دائري',\n },\n chartLegend: {\n toggleLabel: 'إظهار السلاسل أو إخفاؤها',\n hidden: 'مخفية',\n },\n scatterChart: {\n label: 'مخطط التشتت',\n x: 'X',\n y: 'Y',\n size: 'الحجم',\n },\n radarChart: {\n label: 'مخطط راداري',\n polarAreaLabel: 'مخطط مساحي قطبي',\n },\n heatmapChart: {\n label: 'خريطة حرارية',\n noData: 'لا توجد بيانات',\n },\n funnelChart: {\n label: 'مخطط قمعي',\n stage: 'المرحلة',\n value: 'القيمة',\n fromPrevious: 'من السابقة',\n fromFirst: 'من الأولى',\n ofPrevious: '{{percent}} من السابقة',\n ofFirst: '{{percent}} من الأولى',\n stageName: '{{label}}: {{value}}',\n stageNameOne: '{{label}}: {{value}}، {{conversion}}',\n stageNameBoth: '{{label}}: {{value}}، {{previous}}، {{first}}',\n },\n waterfallChart: {\n label: 'مخطط شلالي',\n step: 'الخطوة',\n change: 'التغيير',\n runningTotal: 'الإجمالي التراكمي',\n changeStep: '{{label}}: {{change}}، الإجمالي التراكمي {{total}}',\n totalStep: '{{label}}: الإجمالي {{total}}',\n },\n treemapChart: {\n label: 'مخطط شجري',\n value: 'القيمة',\n share: 'الحصة',\n },\n bulletChart: {\n label: 'مخطط رصاصي',\n target: 'الهدف',\n summary: '{{label}}: {{value}} من هدف {{target}}',\n summaryNoTarget: '{{label}}: {{value}}',\n summaryNoValue: '{{label}}: لا قيمة، الهدف {{target}}',\n noValue: '{{label}}: لا قيمة',\n },\n boxplotChart: {\n label: 'مخطط الصندوق',\n group: 'المجموعة',\n upperWhisker: 'الشارب العلوي',\n q3: 'Q3',\n median: 'الوسيط',\n q1: 'Q1',\n lowerWhisker: 'الشارب السفلي',\n outliers: 'القيم الشاذة',\n moreOutliers: '+{{count}} أخرى',\n },\n candlestickChart: {\n label: 'مخطط الشموع',\n open: 'الافتتاح',\n high: 'الأعلى',\n low: 'الأدنى',\n close: 'الإغلاق',\n },\n compare: {\n label: 'فاصل المقارنة',\n },\n // The two `roledescription` values are spoken INSTEAD of the role name, so they\n // are bare nouns. Arabic has no letter case, so English's lowercase rule has no\n // counterpart here — what carries it is dropping the definite article.\n carousel: {\n label: 'العرض الدوّار',\n goToSlide: 'الانتقال إلى الشريحة {{index}}',\n prev: 'الشريحة السابقة',\n next: 'الشريحة التالية',\n pagination: 'ترقيم شرائح العرض الدوّار',\n roledescription: 'عرض دوّار',\n slideRoledescription: 'شريحة',\n },\n alert: {\n close: 'إغلاق التنبيه',\n },\n qr: {\n label: 'رمز QR',\n },\n image: {\n viewer: 'معاينة الصورة',\n open: 'فتح المعاينة',\n close: 'إغلاق المعاينة',\n },\n window: {\n close: 'إغلاق',\n minimize: 'تصغير',\n maximize: 'تكبير',\n restore: 'استعادة',\n restoreDown: 'استعادة لأسفل',\n restoreWindow: 'استعادة {{title}}',\n closeWindow: 'إغلاق النافذة',\n untitled: 'بلا عنوان',\n taskbar: 'النوافذ المصغّرة',\n taskbarAll: 'النوافذ المفتوحة',\n taskbarMore: 'نوافذ أخرى: {{count}}',\n moveMode: 'جارٍ نقل النافذة. استخدم مفاتيح الأسهم، وEnter للإنهاء، وEscape للإلغاء.',\n resizeMode: 'جارٍ تغيير حجم النافذة. استخدم مفاتيح الأسهم، وEnter للإنهاء، وEscape للإلغاء.',\n moved: 'نُقلت النافذة إلى {{x}}، {{y}}',\n resized: 'تغيّر حجم النافذة إلى {{width}} في {{height}}',\n },\n dialog: {\n close: 'إغلاق مربع الحوار',\n },\n // Deliberately generic: a popover panel has no universal name, and an unnamed\n // `role=\"dialog\"` announces as nothing at all. Override per instance with\n // `[ariaLabel]`.\n popover: {\n label: 'لوحة منبثقة',\n },\n editor: {\n label: 'نص منسق',\n toolbar: 'التنسيق',\n bold: 'غامق',\n italic: 'مائل',\n underline: 'تسطير',\n strike: 'يتوسطه خط',\n code: 'رمز مضمّن',\n paragraph: 'فقرة',\n heading: 'عنوان {{level}}',\n bulletList: 'قائمة نقطية',\n orderedList: 'قائمة مرقمة',\n blockquote: 'اقتباس',\n codeBlock: 'كتلة رمز',\n link: 'إدراج رابط',\n horizontalRule: 'خط أفقي',\n undo: 'تراجع',\n redo: 'إعادة',\n linkUrl: 'عنوان الرابط',\n linkApply: 'تطبيق',\n linkRemove: 'إزالة الرابط',\n linkInvalid: 'لا يمكن استخدام هذا العنوان رابطًا.',\n shortcut: '{{label}} ({{keys}})',\n keyCtrl: 'Ctrl',\n keyShift: 'Shift',\n keyAlt: 'Alt',\n taskDone: 'تم:',\n taskTodo: 'لم يتم:',\n },\n // Arabic inflects a counted noun differently at one, at two, at three-to-ten\n // and at eleven-and-up, and the interpolator has no plural machinery — so a\n // string that counts ITEMS here does one of two things rather than write\n // \"{{count}} <noun>\" and be wrong at most counts. Either the number goes LAST,\n // after a colon, so no noun has to agree with it (`mention.available`), or\n // the noun is dropped: the overflow chips in `select`, `tree` and\n // `eventCalendar` read «+{{count}} أخرى», the invariable feminine-singular\n // form a non-human plural takes, leaving nothing for the count to inflect.\n marquee: {\n label: 'شريط متحرك',\n link: 'رابط',\n },\n mention: {\n listbox: 'الإشارات',\n available: 'المطابقات المتاحة: {{count}}',\n inserted: 'تم الإدراج: {{label}}',\n },\n drawer: {\n close: 'إغلاق اللوحة',\n },\n datePicker: {\n open: 'فتح التقويم',\n openTime: 'فتح منتقي الوقت',\n openDateTime: 'فتح منتقي التاريخ والوقت',\n openRange: 'فتح تقويم الفترة',\n panel: 'اختيار التاريخ',\n panelTime: 'اختيار الوقت',\n panelDateTime: 'اختيار التاريخ والوقت',\n panelRange: 'اختيار الفترة',\n panelRangeDateTime: 'اختيار الفترة بالتاريخ والوقت',\n rangeStart: 'بداية الفترة',\n rangeEnd: 'نهاية الفترة',\n startTime: 'وقت البدء',\n endTime: 'وقت الانتهاء',\n hours: 'الساعات',\n minutes: 'الدقائق',\n seconds: 'الثواني',\n incrementHours: 'زيادة الساعات',\n decrementHours: 'إنقاص الساعات',\n incrementMinutes: 'زيادة الدقائق',\n decrementMinutes: 'إنقاص الدقائق',\n incrementSeconds: 'زيادة الثواني',\n decrementSeconds: 'إنقاص الثواني',\n toggleAmPm: 'تبديل ص / م',\n am: 'ص',\n pm: 'م',\n },\n sidebar: {\n label: 'الشريط الجانبي',\n containsCurrent: 'تحتوي على الصفحة الحالية',\n subpages: 'الصفحات الفرعية لـ {{title}}',\n separator: '،',\n },\n spinner: {\n label: 'جارٍ التحميل',\n },\n rating: {\n label: 'التقييم',\n },\n gauge: {\n label: 'عداد',\n },\n graph: {\n label: 'مخطط',\n parents: 'الآباء: {{names}}.',\n children: 'الأبناء: {{names}}.',\n },\n progress: {\n label: 'التقدم',\n },\n meterGroup: {\n label: 'مقياس',\n },\n knob: {\n label: 'القيمة',\n },\n slider: {\n label: 'القيمة',\n lower: 'القيمة الدنيا',\n upper: 'القيمة العليا',\n },\n speedDial: {\n label: 'الإجراءات',\n },\n statistic: {\n delta: '{{value}}{{suffix}}',\n deltaSuffix: '%',\n },\n result: {\n notFound: 'عذرًا، الصفحة التي زرتها غير موجودة.',\n forbidden: 'عذرًا، ليس لديك إذن بالوصول إلى هذه الصفحة.',\n serverError: 'عذرًا، حدث خطأ ما.',\n },\n date: {\n months: {\n jan: 'يناير',\n feb: 'فبراير',\n mar: 'مارس',\n apr: 'أبريل',\n may: 'مايو',\n jun: 'يونيو',\n jul: 'يوليو',\n aug: 'أغسطس',\n sep: 'سبتمبر',\n oct: 'أكتوبر',\n nov: 'نوفمبر',\n dec: 'ديسمبر',\n },\n },\n};\n"],"mappings":"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OAAO;EACP,MAAM;CACP;CACD,SAAS;EACP,SAAS;EACT,WAAW;EACX,UAAU;CACX;CACD,QAAQ,EACN,OAAO,eACR;CACD,YAAY;EACV,MAAM;EACN,UAAU;EACV,cAAc;EACd,WAAW;EACX,OAAO;EACP,WAAW;EACX,eAAe;EACf,YAAY;EACZ,oBAAoB;EACpB,YAAY;EACZ,UAAU;EACV,WAAW;EACX,SAAS;EACT,OAAO;EACP,SAAS;EACT,SAAS;EACT,gBAAgB;EAChB,gBAAgB;EAChB,kBAAkB;EAClB,kBAAkB;EAClB,kBAAkB;EAClB,kBAAkB;EAClB,YAAY;EACZ,IAAI;EACJ,IAAI;CACL;CACD,SAAS;EACP,OAAO;EACP,iBAAiB;EACjB,UAAU;EACV,WAAW;CACZ;CACD,SAAS,EACP,OAAO,eACR;CACD,QAAQ,EACN,OAAO,UACR;CACD,OAAO,EACL,OAAO,OACR;CACD,OAAO;EACL,OAAO;EACP,SAAS;EACT,UAAU;CACX;CACD,UAAU,EACR,OAAO,SACR;CACD,YAAY,EACV,OAAO,QACR;CACD,MAAM,EACJ,OAAO,SACR;CACD,QAAQ;EACN,OAAO;EACP,OAAO;EACP,OAAO;CACR;CACD,WAAW,EACT,OAAO,YACR;CACD,WAAW;EACT,OAAO;EACP,aAAa;CACd;CACD,QAAQ;EACN,UAAU;EACV,WAAW;EACX,aAAa;CACd;CACD,MAAM,EACJ,QAAQ;EACN,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACN,EACF;AACF"}
|
|
1
|
+
{"version":3,"file":"ngwr-i18n-ar.mjs","names":[],"sources":["../../../projects/lib/i18n/ar/public-api.ts"],"sourcesContent":["import { type WrI18nCatalog } from 'ngwr/i18n';\n\n/** Base Arabic catalog for ngwr built-in component strings. */\nexport const wrAr: WrI18nCatalog = {\n common: {\n ok: 'موافق',\n cancel: 'إلغاء',\n close: 'إغلاق',\n confirm: 'تأكيد',\n delete: 'حذف',\n save: 'حفظ',\n edit: 'تعديل',\n add: 'إضافة',\n remove: 'إزالة',\n clear: 'مسح',\n search: 'بحث',\n loading: 'جارٍ التحميل…',\n select: 'تحديد',\n next: 'التالي',\n previous: 'السابق',\n back: 'رجوع',\n today: 'اليوم',\n yesterday: 'أمس',\n tomorrow: 'غدًا',\n of: 'من',\n },\n pagination: {\n prev: 'الصفحة السابقة',\n next: 'الصفحة التالية',\n itemsPerPage: 'عدد العناصر في الصفحة',\n perPage: '{{size}} / صفحة',\n goToPage: 'الانتقال إلى الصفحة {{page}}',\n label: 'ترقيم الصفحات',\n pageOf: 'الصفحة {{current}} من {{total}}',\n range: '{{from}}–{{to}} من {{total}}',\n compact: '{{current}} / {{total}}',\n },\n table: {\n empty: 'لا توجد بيانات',\n loading: 'جارٍ التحميل…',\n sort: 'فرز عمود {{column}}',\n filter: 'تصفية عمود {{column}}',\n selectAll: 'تحديد كل الصفوف',\n selectRow: 'تحديد الصف',\n expandRow: 'تبديل تفاصيل الصف',\n toggleRow: 'تبديل الصفوف الفرعية',\n selectGroup: 'تحديد المجموعة',\n toggleGroup: 'تبديل المجموعة',\n noMatches: 'لا توجد نتائج مطابقة',\n search: 'بحث',\n reset: 'إعادة تعيين',\n },\n eventCalendar: {\n today: 'اليوم',\n previous: 'السابق',\n next: 'التالي',\n month: 'شهر',\n week: 'أسبوع',\n day: 'يوم',\n time: 'الوقت',\n allDay: 'طوال اليوم',\n label: 'التقويم',\n more: '+{{count}} أخرى',\n header: '{{month}} {{year}}',\n range: '{{from}} – {{to}}',\n chipLabel: '{{title}}، {{time}}',\n slotLabel: '{{time}} — {{date}}',\n allDayCellLabel: '{{label}} — {{date}}',\n },\n tour: {\n next: 'التالي',\n back: 'السابق',\n done: 'تم',\n skip: 'تخطي الجولة',\n progress: 'الخطوة {{current}} من {{total}}',\n },\n splitter: {\n divider: 'تغيير حجم الأجزاء',\n },\n stepper: {\n optional: 'اختياري',\n completed: 'مكتملة',\n },\n transfer: {\n source: 'المتاح',\n target: 'المحدد',\n search: 'بحث',\n empty: 'لا شيء هنا',\n selectAll: 'تحديد الكل',\n toTarget: 'النقل إلى المحدد',\n toSource: 'النقل إلى المتاح',\n count: '{{checked}} / {{total}}',\n selectAllAria: '{{pane}} — {{action}}',\n },\n form: {\n optional: 'اختياري',\n },\n select: {\n // The combobox's own accessible name, also read by `wr-tree` and\n // `wr-cascader`. «تحديد» is the word this catalog uses for marking rows and\n // groups that already exist; picking one value out of a list is «اختيار»,\n // which is also the verb the placeholder «اختر…» below opens with.\n label: 'اختيار',\n placeholder: 'اختر…',\n empty: 'لا توجد خيارات',\n clearSelection: 'مسح التحديد',\n removeItem: 'إزالة {{label}}',\n noResults: 'لا توجد نتائج',\n loading: 'جارٍ التحميل…',\n loadError: 'تعذّر تحميل النتائج',\n retry: 'إعادة المحاولة',\n more: '+{{count}} أخرى',\n },\n // `tree` covers both inline display and combobox-mode pickers\n // (replaces the dropped `treeSelect` namespace).\n tree: {\n expand: 'توسيع',\n collapse: 'طي',\n placeholder: 'اختر…',\n clearSelection: 'مسح التحديد',\n removeItem: 'إزالة {{label}}',\n more: '+{{count}} أخرى',\n },\n commandPalette: {\n label: 'لوحة الأوامر',\n placeholder: 'اكتب أمرًا أو ابحث…',\n noResults: 'لا توجد نتائج',\n loading: 'جارٍ البحث…',\n escHint: 'esc',\n },\n empty: {\n noData: 'لا توجد بيانات',\n },\n fileUpload: {\n browse: 'انقر للاستعراض',\n dropZone: 'أو أفلت الملفات هنا',\n removeFile: 'إزالة الملف',\n invalid: 'نوع ملف غير مدعوم',\n tooBig: 'حجم الملف كبير جدًا',\n size: '{{value}} {{unit}}',\n unitByte: 'بايت',\n unitKb: 'كيلوبايت',\n unitMb: 'ميجابايت',\n unitGb: 'جيجابايت',\n unitTb: 'تيرابايت',\n },\n popconfirm: {\n label: 'تأكيد الإجراء',\n confirm: 'تأكيد',\n cancel: 'إلغاء',\n },\n toast: {\n region: 'الإشعارات',\n close: 'إغلاق',\n copy: 'نسخ',\n copied: 'تم النسخ',\n closeAll: 'إغلاق الكل',\n },\n input: {\n showPassword: 'إظهار كلمة المرور',\n hidePassword: 'إخفاء كلمة المرور',\n },\n inputNumber: {\n increment: 'زيادة',\n decrement: 'إنقاص',\n },\n inputOtp: {\n label: 'رمز التحقق',\n digit: 'الرقم {{index}}',\n character: 'الحرف {{index}}',\n },\n anchor: {\n label: 'جدول المحتويات',\n },\n avatar: {\n alt: 'الصورة الرمزية',\n },\n backTop: {\n label: 'العودة إلى الأعلى',\n },\n breadcrumbs: {\n label: 'مسار التنقل',\n },\n burger: {\n label: 'تبديل القائمة',\n },\n calendar: {\n prevMonth: 'الشهر السابق',\n nextMonth: 'الشهر التالي',\n prevYear: 'السنة السابقة',\n nextYear: 'السنة التالية',\n // The month / year pickers are `role=\"listbox\"`, and a listbox owes a\n // name — without one a screen reader announces the control as nothing at\n // all. Caught by `check:state-a11y` once a state finally opened the view.\n monthList: 'الأشهر',\n yearList: 'السنوات',\n prevYears: '12 سنة سابقة',\n nextYears: '12 سنة تالية',\n header: '{{month}} {{year}}',\n yearRange: '{{from}} – {{to}}',\n dayLabel: '{{weekday}}، {{date}}',\n },\n imageCropper: {\n empty: 'لا توجد صورة',\n window: 'منطقة الاقتصاص',\n keyHelp:\n 'مفاتيح الأسهم تحرّك منطقة الاقتصاص. اضغط باستمرار على Alt مع أحد مفاتيح الأسهم لتغيير حجمها، وعلى Shift لخطوات أكبر. ' +\n 'يُعلن عن المنطقة بقيم اليسار والأعلى والعرض والارتفاع بالبكسل داخل الصورة.',\n },\n sortableList: {\n keyHelp:\n 'اضغط مفتاح المسافة لالتقاط هذا العنصر، ثم استخدم مفاتيح الأسهم لتحريكه. ' +\n 'اضغط مفتاح المسافة مرة أخرى لإفلاته، أو Escape لإعادته إلى مكانه.',\n grabbed: 'تم الالتقاط. {{index}} من {{total}}.',\n moved: '{{index}} من {{total}}.',\n dropped: 'تم الإفلات. {{index}} من {{total}}.',\n cancelled: 'تم إلغاء النقل.',\n },\n colorPicker: {\n area: 'التشبع والسطوع، {{saturation}}% و{{brightness}}%',\n hue: 'درجة اللون',\n alpha: 'العتامة',\n formatHex: 'HEX',\n formatRgb: 'RGB',\n formatHsl: 'HSL',\n channelHex: 'HEX',\n channelRed: 'R',\n channelGreen: 'G',\n channelBlue: 'B',\n channelHue: 'H',\n channelSaturation: 'S%',\n channelLightness: 'L%',\n channelAlpha: 'A%',\n },\n barChart: {\n label: 'مخطط شريطي',\n total: 'الإجمالي',\n value: 'القيمة',\n datum: '{{label}}: {{value}}',\n },\n calendarHeatmap: {\n label: 'خريطة حرارية للتقويم',\n cell: '{{date}}: {{count}}',\n },\n lineChart: {\n label: 'مخطط خطي',\n areaLabel: 'مخطط مساحي',\n },\n donutChart: {\n label: 'مخطط دائري مجوف',\n pieLabel: 'مخطط دائري',\n },\n chartLegend: {\n toggleLabel: 'إظهار السلاسل أو إخفاؤها',\n hidden: 'مخفية',\n },\n scatterChart: {\n label: 'مخطط التشتت',\n x: 'X',\n y: 'Y',\n size: 'الحجم',\n },\n radarChart: {\n label: 'مخطط راداري',\n polarAreaLabel: 'مخطط مساحي قطبي',\n },\n heatmapChart: {\n label: 'خريطة حرارية',\n noData: 'لا توجد بيانات',\n },\n funnelChart: {\n label: 'مخطط قمعي',\n stage: 'المرحلة',\n value: 'القيمة',\n fromPrevious: 'من السابقة',\n fromFirst: 'من الأولى',\n ofPrevious: '{{percent}} من السابقة',\n ofFirst: '{{percent}} من الأولى',\n stageName: '{{label}}: {{value}}',\n stageNameOne: '{{label}}: {{value}}، {{conversion}}',\n stageNameBoth: '{{label}}: {{value}}، {{previous}}، {{first}}',\n },\n waterfallChart: {\n label: 'مخطط شلالي',\n step: 'الخطوة',\n change: 'التغيير',\n runningTotal: 'الإجمالي التراكمي',\n changeStep: '{{label}}: {{change}}، الإجمالي التراكمي {{total}}',\n totalStep: '{{label}}: الإجمالي {{total}}',\n },\n treemapChart: {\n label: 'مخطط شجري',\n value: 'القيمة',\n share: 'الحصة',\n },\n bulletChart: {\n label: 'مخطط رصاصي',\n target: 'الهدف',\n summary: '{{label}}: {{value}} من هدف {{target}}',\n summaryNoTarget: '{{label}}: {{value}}',\n summaryNoValue: '{{label}}: لا قيمة، الهدف {{target}}',\n noValue: '{{label}}: لا قيمة',\n },\n boxplotChart: {\n label: 'مخطط الصندوق',\n group: 'المجموعة',\n upperWhisker: 'الشارب العلوي',\n q3: 'Q3',\n median: 'الوسيط',\n q1: 'Q1',\n lowerWhisker: 'الشارب السفلي',\n outliers: 'القيم الشاذة',\n moreOutliers: '+{{count}} أخرى',\n },\n candlestickChart: {\n label: 'مخطط الشموع',\n open: 'الافتتاح',\n high: 'الأعلى',\n low: 'الأدنى',\n close: 'الإغلاق',\n },\n compare: {\n label: 'فاصل المقارنة',\n },\n // The two `roledescription` values are spoken INSTEAD of the role name, so they\n // are bare nouns. Arabic has no letter case, so English's lowercase rule has no\n // counterpart here — what carries it is dropping the definite article.\n carousel: {\n label: 'العرض الدوّار',\n goToSlide: 'الانتقال إلى الشريحة {{index}}',\n prev: 'الشريحة السابقة',\n next: 'الشريحة التالية',\n pagination: 'ترقيم شرائح العرض الدوّار',\n roledescription: 'عرض دوّار',\n slideRoledescription: 'شريحة',\n },\n alert: {\n close: 'إغلاق التنبيه',\n },\n qr: {\n label: 'رمز QR',\n },\n image: {\n viewer: 'معاينة الصورة',\n open: 'فتح المعاينة',\n close: 'إغلاق المعاينة',\n },\n window: {\n close: 'إغلاق',\n minimize: 'تصغير',\n maximize: 'تكبير',\n restore: 'استعادة',\n restoreDown: 'استعادة لأسفل',\n restoreWindow: 'استعادة {{title}}',\n closeWindow: 'إغلاق النافذة',\n untitled: 'بلا عنوان',\n taskbar: 'النوافذ المصغّرة',\n taskbarAll: 'النوافذ المفتوحة',\n taskbarMore: 'نوافذ أخرى: {{count}}',\n moveMode: 'جارٍ نقل النافذة. استخدم مفاتيح الأسهم، وEnter للإنهاء، وEscape للإلغاء.',\n resizeMode: 'جارٍ تغيير حجم النافذة. استخدم مفاتيح الأسهم، وEnter للإنهاء، وEscape للإلغاء.',\n moved: 'نُقلت النافذة إلى {{x}}، {{y}}',\n resized: 'تغيّر حجم النافذة إلى {{width}} في {{height}}',\n },\n dialog: {\n close: 'إغلاق مربع الحوار',\n },\n // Deliberately generic: a popover panel has no universal name, and an unnamed\n // `role=\"dialog\"` announces as nothing at all. Override per instance with\n // `[ariaLabel]`.\n popover: {\n label: 'لوحة منبثقة',\n },\n editor: {\n label: 'نص منسق',\n toolbar: 'التنسيق',\n bold: 'غامق',\n italic: 'مائل',\n underline: 'تسطير',\n strike: 'يتوسطه خط',\n code: 'رمز مضمّن',\n paragraph: 'فقرة',\n heading: 'عنوان {{level}}',\n bulletList: 'قائمة نقطية',\n orderedList: 'قائمة مرقمة',\n blockquote: 'اقتباس',\n codeBlock: 'كتلة رمز',\n link: 'إدراج رابط',\n horizontalRule: 'خط أفقي',\n undo: 'تراجع',\n redo: 'إعادة',\n linkUrl: 'عنوان الرابط',\n linkApply: 'تطبيق',\n linkRemove: 'إزالة الرابط',\n linkInvalid: 'لا يمكن استخدام هذا العنوان رابطًا.',\n shortcut: '{{label}} ({{keys}})',\n keyCtrl: 'Ctrl',\n keyShift: 'Shift',\n keyAlt: 'Alt',\n taskDone: 'تم:',\n taskTodo: 'لم يتم:',\n },\n // Arabic inflects a counted noun differently at one, at two, at three-to-ten\n // and at eleven-and-up, and the interpolator has no plural machinery — so a\n // string that counts ITEMS here does one of two things rather than write\n // \"{{count}} <noun>\" and be wrong at most counts. Either the number goes LAST,\n // after a colon, so no noun has to agree with it (`mention.available`), or\n // the noun is dropped: the overflow chips in `select`, `tree` and\n // `eventCalendar` read «+{{count}} أخرى», the invariable feminine-singular\n // form a non-human plural takes, leaving nothing for the count to inflect.\n marquee: {\n label: 'شريط متحرك',\n link: 'رابط',\n },\n mention: {\n listbox: 'الإشارات',\n available: 'المطابقات المتاحة: {{count}}',\n inserted: 'تم الإدراج: {{label}}',\n },\n drawer: {\n close: 'إغلاق اللوحة',\n },\n datePicker: {\n open: 'فتح التقويم',\n openTime: 'فتح منتقي الوقت',\n openDateTime: 'فتح منتقي التاريخ والوقت',\n openRange: 'فتح تقويم الفترة',\n panel: 'اختيار التاريخ',\n panelTime: 'اختيار الوقت',\n panelDateTime: 'اختيار التاريخ والوقت',\n panelRange: 'اختيار الفترة',\n panelRangeDateTime: 'اختيار الفترة بالتاريخ والوقت',\n rangeStart: 'بداية الفترة',\n rangeEnd: 'نهاية الفترة',\n startTime: 'وقت البدء',\n endTime: 'وقت الانتهاء',\n hours: 'الساعات',\n minutes: 'الدقائق',\n seconds: 'الثواني',\n incrementHours: 'زيادة الساعات',\n decrementHours: 'إنقاص الساعات',\n incrementMinutes: 'زيادة الدقائق',\n decrementMinutes: 'إنقاص الدقائق',\n incrementSeconds: 'زيادة الثواني',\n decrementSeconds: 'إنقاص الثواني',\n toggleAmPm: 'تبديل ص / م',\n am: 'ص',\n pm: 'م',\n },\n sidebar: {\n label: 'الشريط الجانبي',\n containsCurrent: 'تحتوي على الصفحة الحالية',\n subpages: 'الصفحات الفرعية لـ {{title}}',\n separator: '،',\n },\n spinner: {\n label: 'جارٍ التحميل',\n },\n rating: {\n label: 'التقييم',\n },\n gauge: {\n label: 'عداد',\n },\n graph: {\n label: 'مخطط',\n parents: 'الآباء: {{names}}.',\n children: 'الأبناء: {{names}}.',\n },\n progress: {\n label: 'التقدم',\n },\n meterGroup: {\n label: 'مقياس',\n },\n knob: {\n label: 'القيمة',\n },\n slider: {\n label: 'القيمة',\n lower: 'القيمة الدنيا',\n upper: 'القيمة العليا',\n },\n speedDial: {\n label: 'الإجراءات',\n },\n statistic: {\n delta: '{{value}}{{suffix}}',\n deltaSuffix: '%',\n },\n result: {\n notFound: 'عذرًا، الصفحة التي زرتها غير موجودة.',\n forbidden: 'عذرًا، ليس لديك إذن بالوصول إلى هذه الصفحة.',\n serverError: 'عذرًا، حدث خطأ ما.',\n },\n date: {\n months: {\n jan: 'يناير',\n feb: 'فبراير',\n mar: 'مارس',\n apr: 'أبريل',\n may: 'مايو',\n jun: 'يونيو',\n jul: 'يوليو',\n aug: 'أغسطس',\n sep: 'سبتمبر',\n oct: 'أكتوبر',\n nov: 'نوفمبر',\n dec: 'ديسمبر',\n },\n },\n};\n"],"mappings":"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CACX;CASD,SAAS;EACP,OAAO;EACP,MAAM;CACP;CACD,SAAS;EACP,SAAS;EACT,WAAW;EACX,UAAU;CACX;CACD,QAAQ,EACN,OAAO,eACR;CACD,YAAY;EACV,MAAM;EACN,UAAU;EACV,cAAc;EACd,WAAW;EACX,OAAO;EACP,WAAW;EACX,eAAe;EACf,YAAY;EACZ,oBAAoB;EACpB,YAAY;EACZ,UAAU;EACV,WAAW;EACX,SAAS;EACT,OAAO;EACP,SAAS;EACT,SAAS;EACT,gBAAgB;EAChB,gBAAgB;EAChB,kBAAkB;EAClB,kBAAkB;EAClB,kBAAkB;EAClB,kBAAkB;EAClB,YAAY;EACZ,IAAI;EACJ,IAAI;CACL;CACD,SAAS;EACP,OAAO;EACP,iBAAiB;EACjB,UAAU;EACV,WAAW;CACZ;CACD,SAAS,EACP,OAAO,eACR;CACD,QAAQ,EACN,OAAO,UACR;CACD,OAAO,EACL,OAAO,OACR;CACD,OAAO;EACL,OAAO;EACP,SAAS;EACT,UAAU;CACX;CACD,UAAU,EACR,OAAO,SACR;CACD,YAAY,EACV,OAAO,QACR;CACD,MAAM,EACJ,OAAO,SACR;CACD,QAAQ;EACN,OAAO;EACP,OAAO;EACP,OAAO;CACR;CACD,WAAW,EACT,OAAO,YACR;CACD,WAAW;EACT,OAAO;EACP,aAAa;CACd;CACD,QAAQ;EACN,UAAU;EACV,WAAW;EACX,aAAa;CACd;CACD,MAAM,EACJ,QAAQ;EACN,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACN,EACF;AACF"}
|