ngwr 14.5.0 → 14.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/avatar/styles/_index.scss +46 -0
- package/fesm2022/ngwr-avatar.mjs +58 -7
- package/fesm2022/ngwr-avatar.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +16 -5
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n.mjs +13 -0
- package/fesm2022/ngwr-i18n.mjs.map +1 -1
- package/fesm2022/ngwr-image-cropper-testing.mjs +34 -3
- package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
- package/fesm2022/ngwr-image-cropper.mjs +98 -5
- package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
- package/fesm2022/ngwr-pagination.mjs +1 -1
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-schema-form.mjs +1 -1
- package/fesm2022/ngwr-schema-form.mjs.map +1 -1
- package/fesm2022/ngwr-select-testing.mjs +21 -2
- package/fesm2022/ngwr-select-testing.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +233 -35
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-table.mjs +10 -2
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/image-cropper/styles/_index.scss +7 -0
- package/llms-full.txt +5 -5
- package/llms.txt +12 -3
- package/mcp/providers.js +8 -2
- package/package.json +1 -1
- package/schematics/migrations/v14/index.js +90 -34
- package/schematics/migrations/v7/index.js +15 -4
- package/schematics/migrations/v8/index.js +13 -2
- package/schematics/migrations/v9/index.js +19 -10
- package/schematics/use/symbol-map.json +1 -0
- package/select/styles/_index.scss +34 -0
- package/skills/ngwr/SKILL.md +9 -4
- package/skills/ngwr/references/catalog.md +1 -1
- package/skills/ngwr/references/setup.md +2 -2
- package/table/styles/_index.scss +39 -12
- package/types/ngwr-avatar.d.ts +36 -3
- package/types/ngwr-i18n-en.d.ts +16 -5
- package/types/ngwr-i18n.d.ts +13 -0
- package/types/ngwr-image-cropper-testing.d.ts +25 -3
- package/types/ngwr-image-cropper.d.ts +88 -2
- package/types/ngwr-select-testing.d.ts +18 -1
- package/types/ngwr-select.d.ts +181 -10
- package/types/ngwr-table.d.ts +8 -0
- package/types/ngwr-version.d.ts +1 -1
package/table/styles/_index.scss
CHANGED
|
@@ -389,6 +389,14 @@
|
|
|
389
389
|
padding: 0;
|
|
390
390
|
cursor: pointer;
|
|
391
391
|
color: inherit;
|
|
392
|
+
// The indicator inside is a bare `.wr-icon__svg`, which is `1em`, and a
|
|
393
|
+
// `<button>` does not inherit its font-size: it takes the browser's control
|
|
394
|
+
// font (about 13.33px) unless the app resets it. So the same glyph measured
|
|
395
|
+
// 13.33px on a page with no reset and 12px under `ngwr/reset`, which sets
|
|
396
|
+
// `font: inherit`. Inheriting the size makes `1em` the header's own text in
|
|
397
|
+
// every app. `--wr-icon-size` cannot do this job — only a `<wr-icon>` host
|
|
398
|
+
// reads it, and the rule here used to set it for nothing.
|
|
399
|
+
font-size: inherit;
|
|
392
400
|
line-height: 0;
|
|
393
401
|
}
|
|
394
402
|
|
|
@@ -741,21 +749,35 @@
|
|
|
741
749
|
|
|
742
750
|
.wr-table-sort {
|
|
743
751
|
display: inline-flex;
|
|
744
|
-
|
|
752
|
+
// Unsorted is the flat line the template draws, at full strength in the muted
|
|
753
|
+
// role — the same ink as the filter funnel beside it. It used to be the sort
|
|
754
|
+
// ARROW at half opacity, which is how an unsorted column came to read as
|
|
755
|
+
// "sorted ascending, dimmed". The glyph carries the state now, so the opacity
|
|
756
|
+
// has no job left, and dropping it is what lifts the indicator over the 3:1 a
|
|
757
|
+
// graphic that identifies a control is held to. Measured on the header's own
|
|
758
|
+
// background in Chromium, after the colour transition settled: from 1.98:1 to
|
|
759
|
+
// 4.78:1 in light (`#5f6c7d` on `#eff2f6`) and from 2.74:1 to 7.04:1 in dark
|
|
760
|
+
// (`#9aa6b8` on `#131a2b`). An SVG stroke is invisible to axe, so re-measure
|
|
761
|
+
// by hand if this ink or the header fill ever moves.
|
|
745
762
|
color: var(--wr-color-on-surface-muted);
|
|
746
|
-
transition
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
763
|
+
// Only the colour eases back to unsorted. A transition is taken from the
|
|
764
|
+
// state being ENTERED, so leaving `--desc` for the base would otherwise spin
|
|
765
|
+
// the flat line from 180deg to 0 — motion with no direction to report. The
|
|
766
|
+
// turn between the two arrows still animates, since both modifiers carry it.
|
|
767
|
+
transition: color var(--wr-transition-base);
|
|
768
|
+
|
|
769
|
+
// The template swaps the glyph — a flat line while unsorted, an arrow here
|
|
770
|
+
// (table-sort.ts) — so the state reads from the shape, and the primary ink
|
|
771
|
+
// only says which column is the sorted one.
|
|
772
|
+
&--asc,
|
|
773
|
+
&--desc {
|
|
753
774
|
color: var(--wr-color-primary);
|
|
775
|
+
transition:
|
|
776
|
+
transform var(--wr-transition-base),
|
|
777
|
+
color var(--wr-transition-base);
|
|
754
778
|
}
|
|
755
779
|
|
|
756
780
|
&--desc {
|
|
757
|
-
opacity: 1;
|
|
758
|
-
color: var(--wr-color-primary);
|
|
759
781
|
transform: rotate(180deg);
|
|
760
782
|
}
|
|
761
783
|
}
|
|
@@ -781,7 +803,13 @@
|
|
|
781
803
|
padding: 0;
|
|
782
804
|
cursor: pointer;
|
|
783
805
|
color: inherit;
|
|
784
|
-
|
|
806
|
+
// The funnel is the same bare `1em` svg as the sort indicator beside it, in
|
|
807
|
+
// the same kind of `<button>`, so it inherits the header's font-size for the
|
|
808
|
+
// same reason (see `.wr-table__sort-btn`). The size only, not the `font`
|
|
809
|
+
// shorthand: that would also bring the header's 1.25rem line-height, and the
|
|
810
|
+
// count pill beside the funnel — 10px type with no line-height of its own —
|
|
811
|
+
// grows from 12px to 20px tall under it.
|
|
812
|
+
font-size: inherit;
|
|
785
813
|
}
|
|
786
814
|
|
|
787
815
|
&__count {
|
|
@@ -855,7 +883,6 @@
|
|
|
855
883
|
border-radius: var(--wr-border-radius-sm);
|
|
856
884
|
border: 1px solid var(--wr-color-outline);
|
|
857
885
|
color: transparent;
|
|
858
|
-
--wr-icon-size: 0.75rem;
|
|
859
886
|
transition: var(--wr-transition-base);
|
|
860
887
|
}
|
|
861
888
|
|
package/types/ngwr-avatar.d.ts
CHANGED
|
@@ -40,19 +40,25 @@ type WrAvatarSize = number | `${number}` | `${number}px` | `${number}rem`;
|
|
|
40
40
|
/**
|
|
41
41
|
* Image avatar with configurable corner treatment.
|
|
42
42
|
*
|
|
43
|
-
*
|
|
43
|
+
* Projected content (typically initials) is the FALLBACK: it shows with no
|
|
44
|
+
* `url`, while the image loads and after it fails, and leaves the paint once the
|
|
45
|
+
* image has loaded. It is projected into a `.wr-avatar__content` wrapper, so a
|
|
46
|
+
* `wr-avatar > …` child selector no longer reaches it. While it is there, no
|
|
47
|
+
* spinner is drawn over it; with nothing projected, the spinner marks the
|
|
48
|
+
* loading state instead. See `alt` for what a screen reader hears.
|
|
44
49
|
*
|
|
45
50
|
* @example
|
|
46
51
|
* ```html
|
|
47
52
|
* <wr-avatar url="/me.png" alt="Roman" size="3rem" shape="circle" />
|
|
48
|
-
* <wr-avatar url="
|
|
53
|
+
* <wr-avatar [url]="photo" alt="Roman Khegay" [size]="48">RK</wr-avatar>
|
|
49
54
|
* ```
|
|
50
55
|
*
|
|
51
56
|
* @see https://ngwr.dev/reference/components/avatar
|
|
52
57
|
*/
|
|
53
58
|
declare class WrAvatar {
|
|
54
59
|
/**
|
|
55
|
-
* Image URL.
|
|
60
|
+
* Image URL. Projected content (e.g. initials) shows while it is unset,
|
|
61
|
+
* loading or broken, and gives way once the image has loaded.
|
|
56
62
|
*
|
|
57
63
|
* @default null
|
|
58
64
|
*/
|
|
@@ -61,6 +67,11 @@ declare class WrAvatar {
|
|
|
61
67
|
* Alt text for the image. Falls back to `avatar.alt`, then `'Avatar'` — pass
|
|
62
68
|
* the person's name where you have it, since that is what a reader wants.
|
|
63
69
|
*
|
|
70
|
+
* With an `alt`, projected initials are hidden from assistive technology while
|
|
71
|
+
* an image is in play, so the name is announced once. Without one, the image
|
|
72
|
+
* carries only the generic name, so the initials stay announced beside it —
|
|
73
|
+
* visually hidden once it has loaded, never dropped.
|
|
74
|
+
*
|
|
64
75
|
* @default null
|
|
65
76
|
*/
|
|
66
77
|
readonly alt: _angular_core.InputSignal<string | null>;
|
|
@@ -85,8 +96,30 @@ declare class WrAvatar {
|
|
|
85
96
|
* worth showing instead.
|
|
86
97
|
*/
|
|
87
98
|
protected readonly failed: _angular_core.WritableSignal<boolean>;
|
|
99
|
+
private readonly img;
|
|
88
100
|
constructor();
|
|
101
|
+
/**
|
|
102
|
+
* A prerendered `<img>` starts loading when the browser parses the HTML, and
|
|
103
|
+
* `(load)` / `(error)` are only attached at hydration — so on a slow bundle the
|
|
104
|
+
* image settles first, both events go nowhere, and the avatar sits on its
|
|
105
|
+
* fallback over a photo it already has (or names a broken image it never
|
|
106
|
+
* learns about). Only the FIRST render can race: every later `<img>` is
|
|
107
|
+
* created on the client with its listeners in place before `src` is set.
|
|
108
|
+
*/
|
|
109
|
+
private adoptSettledImage;
|
|
89
110
|
protected readonly resolved: _angular_core.Signal<ResolvedCssSize>;
|
|
111
|
+
/**
|
|
112
|
+
* Whether the projected fallback is `aria-hidden`: an `<img>` is in the DOM
|
|
113
|
+
* (loading or loaded) AND the consumer named it. Then the image's `alt` owns
|
|
114
|
+
* the name, announced once and unchanged at the moment the photo arrives.
|
|
115
|
+
* Without a real `alt` the image is only "Avatar", and hiding the initials
|
|
116
|
+
* would drop the one thing that says who this is.
|
|
117
|
+
*
|
|
118
|
+
* The stylesheet keys on the same attribute once `--loaded`: a hidden fallback
|
|
119
|
+
* leaves the paint through `visibility`, a named-by-initials one is clipped and
|
|
120
|
+
* stays in the accessibility tree. While loading it is painted either way.
|
|
121
|
+
*/
|
|
122
|
+
protected readonly fallbackHidden: _angular_core.Signal<boolean>;
|
|
90
123
|
protected readonly cssSize: _angular_core.Signal<string>;
|
|
91
124
|
protected readonly pxSize: _angular_core.Signal<number | null>;
|
|
92
125
|
protected readonly classes: _angular_core.Signal<string>;
|
package/types/ngwr-i18n-en.d.ts
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
import { WrI18nCatalog } from 'ngwr/i18n';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Base English catalog for ngwr built-in component strings.
|
|
5
|
-
*
|
|
4
|
+
* Base English catalog for ngwr built-in component strings. Register it with
|
|
5
|
+
* `provideWrI18nBaseCatalogs` and keep only your own keys in the loader.
|
|
6
|
+
*
|
|
7
|
+
* Do not spread it into your own catalog. A spread is shallow, so any namespace
|
|
8
|
+
* you share with ngwr, e.g. `common`, `validation`, `table`, keeps only the keys
|
|
9
|
+
* of the side spread last, and the other side's keys stop resolving with nothing
|
|
10
|
+
* logged: ngwr's components fall back to their English defaults, and a `wrT`
|
|
11
|
+
* read of a lost key renders the raw key under the default missing handler. A
|
|
12
|
+
* base catalog is looked up key by key underneath yours, so both halves of a
|
|
13
|
+
* shared namespace resolve.
|
|
6
14
|
*
|
|
7
15
|
* @example
|
|
8
16
|
* ```ts
|
|
17
|
+
* import { provideWrI18n, provideWrI18nBaseCatalogs, provideWrI18nStaticLoader } from 'ngwr/i18n';
|
|
9
18
|
* import { wrEn } from 'ngwr/i18n/en';
|
|
10
19
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* })
|
|
20
|
+
* providers: [
|
|
21
|
+
* provideWrI18n(),
|
|
22
|
+
* provideWrI18nBaseCatalogs({ en: wrEn }),
|
|
23
|
+
* provideWrI18nStaticLoader({ en: { app: { title: 'My app' } } }),
|
|
24
|
+
* ]
|
|
14
25
|
* ```
|
|
15
26
|
*/
|
|
16
27
|
declare const wrEn: WrI18nCatalog;
|
package/types/ngwr-i18n.d.ts
CHANGED
|
@@ -403,6 +403,15 @@ declare function provideWrI18n(options?: ProvideWrI18nOptions): EnvironmentProvi
|
|
|
403
403
|
/**
|
|
404
404
|
* Provide a static loader — catalogs already in memory.
|
|
405
405
|
*
|
|
406
|
+
* A loader serves only the catalog you pass it, and ngwr registers none of its
|
|
407
|
+
* own. Pass only your own keys here and register ngwr's catalogs with
|
|
408
|
+
* {@link provideWrI18nBaseCatalogs} — not `{ ...wrRu, ...yours }`. A spread is
|
|
409
|
+
* shallow, so any namespace you share with ngwr, e.g. `common`, `validation`,
|
|
410
|
+
* `table`, keeps only the keys of the side spread last, and the other side's
|
|
411
|
+
* keys stop resolving with nothing logged: ngwr's components fall back to their
|
|
412
|
+
* English defaults, and a `wrT` read of a lost key renders the raw key under the
|
|
413
|
+
* default missing handler.
|
|
414
|
+
*
|
|
406
415
|
* @param catalogs Root catalogs keyed by locale.
|
|
407
416
|
* @param scopes Optional per-scope catalogs served to `registerScope(name)`.
|
|
408
417
|
*/
|
|
@@ -428,6 +437,10 @@ declare function provideWrI18nStaticLoader(catalogs: WrI18nStaticCatalogs, scope
|
|
|
428
437
|
*
|
|
429
438
|
* Pass only the locales you ship — the ones you leave out stay out of the
|
|
430
439
|
* bundle. Your own keys always win; this is a floor, not an override.
|
|
440
|
+
*
|
|
441
|
+
* Use it instead of spreading `wrRu` into your own catalog, too: the lookup
|
|
442
|
+
* walks these key by key after the loader's catalog misses, so a namespace both
|
|
443
|
+
* define keeps both halves, where a shallow spread keeps only one.
|
|
431
444
|
*/
|
|
432
445
|
declare function provideWrI18nBaseCatalogs(catalogs: WrI18nBaseCatalogs): Provider;
|
|
433
446
|
/** Provide an HTTP loader — catalogs fetched from URLs. Requires `provideHttpClient`. */
|
|
@@ -72,9 +72,10 @@ interface WrCropWindowBox {
|
|
|
72
72
|
* arrives on the `(cropped)` output, which emits a `Blob` after each drag end or
|
|
73
73
|
* each run of arrow keys, and a consumer who wants a one-off read calls `toBlob()` /
|
|
74
74
|
* `toDataUrl()` — or `cropRect()` for the geometry — on the component through a
|
|
75
|
-
* `viewChild`.
|
|
76
|
-
*
|
|
77
|
-
* rather than
|
|
75
|
+
* `viewChild`. The same goes for `(loadError)` and `status()`, which is why
|
|
76
|
+
* {@link isFailed} reads the failure off the host class instead. Outputs and instance
|
|
77
|
+
* members are component API rather than DOM, so all of it is outside what a harness
|
|
78
|
+
* can reach at all, which is worth knowing rather than discovering.
|
|
78
79
|
*
|
|
79
80
|
* @example
|
|
80
81
|
* ```ts
|
|
@@ -127,6 +128,27 @@ declare class WrImageCropperHarness extends ComponentHarness {
|
|
|
127
128
|
* a zero-sized image.
|
|
128
129
|
*/
|
|
129
130
|
dispatchImageLoad(): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Fire the image's `error` event — what a browser does with a source it cannot
|
|
133
|
+
* decode, and the only way to get one in a unit test, where nothing is decoded.
|
|
134
|
+
*
|
|
135
|
+
* Afterwards {@link isFailed} is `true` and the component has emitted
|
|
136
|
+
* `(loadError)`; a spec that wants the payload binds that output on its host.
|
|
137
|
+
*/
|
|
138
|
+
dispatchImageError(): Promise<void>;
|
|
139
|
+
/**
|
|
140
|
+
* Whether the browser failed to decode the current source.
|
|
141
|
+
*
|
|
142
|
+
* Read off the `wr-image-cropper--failed` host modifier — the part of the failure
|
|
143
|
+
* the DOM shows. It is a third answer beside {@link isEmpty} and {@link isReady},
|
|
144
|
+
* not a combination of them: a failed cropper has a `src` (so it is not empty) and
|
|
145
|
+
* no crop window (so it is not ready), which is also exactly what a cropper still
|
|
146
|
+
* LOADING looks like. Asking those two would call a broken image a slow one.
|
|
147
|
+
*
|
|
148
|
+
* The component renders no message for it, so there is no text to read here; the
|
|
149
|
+
* host's own message is the host's to assert.
|
|
150
|
+
*/
|
|
151
|
+
isFailed(): Promise<boolean>;
|
|
130
152
|
/**
|
|
131
153
|
* Where the crop window sits over the displayed image, in CSS pixels.
|
|
132
154
|
*
|
|
@@ -18,6 +18,45 @@ interface WrCropRect {
|
|
|
18
18
|
type WrCropHandle = 'move' | 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';
|
|
19
19
|
/** Supported output MIME types for {@link WrImageCropper.toBlob}. */
|
|
20
20
|
type WrImageOutputType = 'image/png' | 'image/jpeg' | 'image/webp';
|
|
21
|
+
/**
|
|
22
|
+
* Where the cropper's source stands.
|
|
23
|
+
*
|
|
24
|
+
* - `empty` — no `src`, so the placeholder is showing.
|
|
25
|
+
* - `loading` — a `src` has been handed to the `<img>` and the browser has not
|
|
26
|
+
* answered yet.
|
|
27
|
+
* - `loaded` — the image decoded. The crop window opens once it also has a
|
|
28
|
+
* measured size, which in a browser is the same moment.
|
|
29
|
+
* - `failed` — the browser could not decode it (a renamed `.heic`, a truncated
|
|
30
|
+
* file, a URL that 404s). `(loadError)` fired with the details.
|
|
31
|
+
*/
|
|
32
|
+
type WrImageCropperStatus = 'empty' | 'loading' | 'loaded' | 'failed';
|
|
33
|
+
/**
|
|
34
|
+
* The payload of `(loadError)` — plain strings and numbers, so it can be logged,
|
|
35
|
+
* sent to an error tracker or put into a store as it is.
|
|
36
|
+
*
|
|
37
|
+
* The browser's `error` event carries no reason at all, so none is invented here:
|
|
38
|
+
* what the source DECLARED is the most a host has to work with, and for the common
|
|
39
|
+
* case (a phone photo in a format this browser cannot decode) `type` and `name`
|
|
40
|
+
* are what tell the two apart from a broken upload.
|
|
41
|
+
*/
|
|
42
|
+
interface WrImageLoadError {
|
|
43
|
+
/**
|
|
44
|
+
* The URL the `<img>` was given — the `src` string itself, or the object URL
|
|
45
|
+
* made for a `File` / `Blob`. An object URL is revoked as soon as `src` changes,
|
|
46
|
+
* so it identifies the attempt rather than being something to fetch later.
|
|
47
|
+
*/
|
|
48
|
+
readonly url: string;
|
|
49
|
+
/** `File.name` for a `File` source; `null` for a `Blob` or a string. */
|
|
50
|
+
readonly name: string | null;
|
|
51
|
+
/**
|
|
52
|
+
* The MIME type a `File` / `Blob` declares — `''` when it declares none, and
|
|
53
|
+
* `null` for a string source. A `File`'s type comes from its extension, so a
|
|
54
|
+
* renamed file declares the type of the name it was given.
|
|
55
|
+
*/
|
|
56
|
+
readonly type: string | null;
|
|
57
|
+
/** Size in bytes for a `File` / `Blob`; `null` for a string source. */
|
|
58
|
+
readonly size: number | null;
|
|
59
|
+
}
|
|
21
60
|
|
|
22
61
|
interface RectPx {
|
|
23
62
|
x: number;
|
|
@@ -37,12 +76,18 @@ interface RectPx {
|
|
|
37
76
|
* freshly-rendered `Blob` of the cropped region. For one-off reads use
|
|
38
77
|
* `toBlob()` / `toDataUrl()`.
|
|
39
78
|
*
|
|
79
|
+
* A source the browser cannot decode fires `(loadError)` once, sets `status()` to
|
|
80
|
+
* `'failed'` and puts `wr-image-cropper--failed` on the host. The component renders
|
|
81
|
+
* no message of its own for it — what went wrong and what to do next is the host's
|
|
82
|
+
* to say.
|
|
83
|
+
*
|
|
40
84
|
* @example
|
|
41
85
|
* ```html
|
|
42
86
|
* <wr-image-cropper
|
|
43
87
|
* [src]="file"
|
|
44
88
|
* [aspectRatio]="1"
|
|
45
89
|
* (cropped)="onBlob($event)"
|
|
90
|
+
* (loadError)="onUnreadable($event)"
|
|
46
91
|
* />
|
|
47
92
|
* ```
|
|
48
93
|
*
|
|
@@ -61,8 +106,23 @@ declare class WrImageCropper {
|
|
|
61
106
|
readonly outputType: _angular_core.InputSignal<WrImageOutputType>;
|
|
62
107
|
/** JPEG / WebP quality for `(cropped)` in [0, 1]. @default 0.92 */
|
|
63
108
|
readonly outputQuality: _angular_core.InputSignal<number>;
|
|
109
|
+
/**
|
|
110
|
+
* Longest side of the exported image, in pixels — for `(cropped)`, `toBlob()` and
|
|
111
|
+
* `toDataUrl()` alike. A crop larger than this is scaled down to fit, keeping its
|
|
112
|
+
* aspect ratio; a smaller one is exported as it is, never upscaled. The crop itself
|
|
113
|
+
* — `cropRect()`, in source pixels — is not affected. `null` (or anything that is
|
|
114
|
+
* not a positive number) exports at the source image's own resolution.
|
|
115
|
+
* @default null
|
|
116
|
+
*/
|
|
117
|
+
readonly maxOutputSize: _angular_core.InputSignalWithTransform<number | null, unknown>;
|
|
64
118
|
/** Emits a Blob after each drag end. */
|
|
65
119
|
readonly cropped: _angular_core.OutputEmitterRef<Blob>;
|
|
120
|
+
/**
|
|
121
|
+
* Fires once when the browser cannot decode the current `src` — a format it does
|
|
122
|
+
* not support, a broken file, a URL that fails. Nothing is rendered for it; show
|
|
123
|
+
* your own message. A new `src` clears the failure.
|
|
124
|
+
*/
|
|
125
|
+
readonly loadError: _angular_core.OutputEmitterRef<WrImageLoadError>;
|
|
66
126
|
protected readonly imgEl: _angular_core.Signal<ElementRef<HTMLImageElement>>;
|
|
67
127
|
/** Resolved object URL for `src` (so File / Blob render in `<img>`). */
|
|
68
128
|
protected readonly emptyText: _angular_core.Signal<string>;
|
|
@@ -98,6 +158,13 @@ declare class WrImageCropper {
|
|
|
98
158
|
private startPointer;
|
|
99
159
|
private startRect;
|
|
100
160
|
private readonly destroyRef;
|
|
161
|
+
private readonly statusState;
|
|
162
|
+
/**
|
|
163
|
+
* Where the source stands: `'empty'`, `'loading'`, `'loaded'` or `'failed'`. Reset
|
|
164
|
+
* to `'loading'` (or `'empty'`) whenever `src` changes, so a failure never outlives
|
|
165
|
+
* the source that caused it.
|
|
166
|
+
*/
|
|
167
|
+
readonly status: _angular_core.Signal<WrImageCropperStatus>;
|
|
101
168
|
/** Resolved crop rect in natural (source) pixel coordinates. */
|
|
102
169
|
readonly cropRect: _angular_core.Signal<WrCropRect>;
|
|
103
170
|
constructor();
|
|
@@ -113,6 +180,18 @@ declare class WrImageCropper {
|
|
|
113
180
|
*/
|
|
114
181
|
private resetGeometry;
|
|
115
182
|
protected onImageLoad(): void;
|
|
183
|
+
/**
|
|
184
|
+
* The `<img>` could not decode its source.
|
|
185
|
+
*
|
|
186
|
+
* Before this handler existed a failed decode left the component exactly as it
|
|
187
|
+
* looks while loading — an image with no size, no crop window, nothing emitted —
|
|
188
|
+
* so a host had no way to tell "still decoding" from "never going to", and a user
|
|
189
|
+
* who picked a `.heic` the browser cannot read saw an empty box and no reason.
|
|
190
|
+
*
|
|
191
|
+
* Once per source: `status` is reset by a new `src` and by nothing else, so a
|
|
192
|
+
* second `error` for the same source says nothing new and is not re-emitted.
|
|
193
|
+
*/
|
|
194
|
+
protected onImageError(): void;
|
|
116
195
|
/**
|
|
117
196
|
* Keep `display` on the box the image is actually rendered at.
|
|
118
197
|
*
|
|
@@ -176,11 +255,18 @@ declare class WrImageCropper {
|
|
|
176
255
|
toDataUrl(type?: WrImageOutputType, quality?: number): string;
|
|
177
256
|
/** Re-emit the crop without waiting for a drag (e.g. after a programmatic change). */
|
|
178
257
|
refresh(): Promise<void>;
|
|
258
|
+
/**
|
|
259
|
+
* The exported image's pixel size: the crop in source pixels, scaled down so its
|
|
260
|
+
* longer side fits `maxOutputSize`. `Math.min(1, …)` is the never-upscale rule — a
|
|
261
|
+
* crop already inside the cap keeps its own size, which is also the whole of the
|
|
262
|
+
* uncapped path.
|
|
263
|
+
*/
|
|
264
|
+
private outputSize;
|
|
179
265
|
private toCanvas;
|
|
180
266
|
private emitCropped;
|
|
181
267
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrImageCropper, never>;
|
|
182
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrImageCropper, "wr-image-cropper", never, { "src": { "alias": "src"; "required": false; "isSignal": true; }; "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "minWidth": { "alias": "minWidth"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "outputType": { "alias": "outputType"; "required": false; "isSignal": true; }; "outputQuality": { "alias": "outputQuality"; "required": false; "isSignal": true; }; }, { "cropped": "cropped"; }, never, never, true, never>;
|
|
268
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrImageCropper, "wr-image-cropper", never, { "src": { "alias": "src"; "required": false; "isSignal": true; }; "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "minWidth": { "alias": "minWidth"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "outputType": { "alias": "outputType"; "required": false; "isSignal": true; }; "outputQuality": { "alias": "outputQuality"; "required": false; "isSignal": true; }; "maxOutputSize": { "alias": "maxOutputSize"; "required": false; "isSignal": true; }; }, { "cropped": "cropped"; "loadError": "loadError"; }, never, never, true, never>;
|
|
183
269
|
}
|
|
184
270
|
|
|
185
271
|
export { WrImageCropper };
|
|
186
|
-
export type { WrCropHandle, WrCropRect, WrImageOutputType };
|
|
272
|
+
export type { WrCropHandle, WrCropRect, WrImageCropperStatus, WrImageLoadError, WrImageOutputType };
|
|
@@ -51,8 +51,25 @@ declare class WrOptionHarness extends ComponentHarness {
|
|
|
51
51
|
static hostSelector: string;
|
|
52
52
|
/** Build a predicate that narrows the query. */
|
|
53
53
|
static with(options?: WrOptionHarnessFilters): HarnessPredicate<WrOptionHarness>;
|
|
54
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* The option's text as drawn, trimmed — without its leading visual.
|
|
56
|
+
*
|
|
57
|
+
* A `wrOptionLeading` template renders INSIDE the row, so reading the whole
|
|
58
|
+
* host would hand back an avatar's initials as the first word of the name. It
|
|
59
|
+
* is excluded here for the same reason the select excludes it from the label.
|
|
60
|
+
*
|
|
61
|
+
* This is the drawn text, not the `label` input: an option whose `label` is
|
|
62
|
+
* shorter than what it draws still answers with what it draws. What the select
|
|
63
|
+
* REPORTS for it is on the select harness, as `getValueText()` or
|
|
64
|
+
* `getChipLabels()`.
|
|
65
|
+
*/
|
|
55
66
|
getText(): Promise<string>;
|
|
67
|
+
/**
|
|
68
|
+
* Whether the row is drawing a leading visual right now. Reads the slot the
|
|
69
|
+
* select renders the template into, so it answers `false` for an option that
|
|
70
|
+
* declares a template while the panel is closed — which is the contract.
|
|
71
|
+
*/
|
|
72
|
+
hasLeading(): Promise<boolean>;
|
|
56
73
|
/** Whether the option is currently selected. */
|
|
57
74
|
isSelected(): Promise<boolean>;
|
|
58
75
|
/** Whether the option refuses selection. */
|