ngwr 14.5.1 → 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/avatar/styles/_index.scss +46 -0
- package/fesm2022/ngwr-avatar.mjs +58 -7
- package/fesm2022/ngwr-avatar.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-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/image-cropper/styles/_index.scss +7 -0
- package/llms-full.txt +4 -4
- package/package.json +1 -1
- package/schematics/use/symbol-map.json +1 -0
- package/select/styles/_index.scss +34 -0
- package/skills/ngwr/references/catalog.md +1 -1
- package/types/ngwr-avatar.d.ts +36 -3
- 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-version.d.ts +1 -1
|
@@ -16,7 +16,7 @@ import { InjectionToken } from '@angular/core';
|
|
|
16
16
|
* Distinct from `Version` exported by `@angular/core`, which reports the
|
|
17
17
|
* loaded Angular runtime version (e.g. `'22.0.0'`), not ngwr's.
|
|
18
18
|
*/
|
|
19
|
-
const NGWR_VERSION = '14.
|
|
19
|
+
const NGWR_VERSION = '14.6.0';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* @license
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-version.mjs","sources":["../../../projects/lib/version/version.ts","../../../projects/lib/version/version.token.ts","../../../projects/lib/version/ngwr-version.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\n/**\n * The ngwr library version string, kept in sync with\n * `projects/lib/package.json` by `scripts/release-prepare.ts`.\n *\n * Prefer this over reading `package.json` at runtime — that requires a JSON\n * import or `require`, neither of which tree-shakes well in Angular builds.\n *\n * Distinct from `Version` exported by `@angular/core`, which reports the\n * loaded Angular runtime version (e.g. `'22.0.0'`), not ngwr's.\n */\nexport const NGWR_VERSION = '14.
|
|
1
|
+
{"version":3,"file":"ngwr-version.mjs","sources":["../../../projects/lib/version/version.ts","../../../projects/lib/version/version.token.ts","../../../projects/lib/version/ngwr-version.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\n/**\n * The ngwr library version string, kept in sync with\n * `projects/lib/package.json` by `scripts/release-prepare.ts`.\n *\n * Prefer this over reading `package.json` at runtime — that requires a JSON\n * import or `require`, neither of which tree-shakes well in Angular builds.\n *\n * Distinct from `Version` exported by `@angular/core`, which reports the\n * loaded Angular runtime version (e.g. `'22.0.0'`), not ngwr's.\n */\nexport const NGWR_VERSION = '14.6.0';\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 { InjectionToken } from '@angular/core';\n\nimport { NGWR_VERSION } from './version';\n\n/**\n * Injection token holding the ngwr library version string.\n *\n * Default factory returns {@link NGWR_VERSION}. Override it in tests or in\n * apps that want to surface a custom build identifier.\n *\n * @example\n * ```ts\n * @Component({...})\n * export class FooterComponent {\n * readonly version = inject(NGWR_VERSION_TOKEN);\n * }\n * ```\n */\nexport const NGWR_VERSION_TOKEN = new InjectionToken<string>('NGWR_VERSION_TOKEN', {\n providedIn: 'root',\n factory: () => NGWR_VERSION,\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAEH;;;;;;;;;AASG;AACI,MAAM,YAAY,GAAG;;ACjB5B;;;;;AAKG;AAMH;;;;;;;;;;;;;AAaG;MACU,kBAAkB,GAAG,IAAI,cAAc,CAAS,oBAAoB,EAAE;AACjF,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM,YAAY;AAC5B,CAAA;;AC5BD;;AAEG;;;;"}
|
|
@@ -23,6 +23,13 @@
|
|
|
23
23
|
user-select: none;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// A source the browser could not decode. The `<img>` stays in the DOM, since the
|
|
27
|
+
// next `src` goes through the same element, but some engines draw a broken-image
|
|
28
|
+
// glyph for it — and the failure is the host's to explain, not a stray icon's.
|
|
29
|
+
&--failed &__image {
|
|
30
|
+
display: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
&__backdrop {
|
|
27
34
|
position: absolute;
|
|
28
35
|
inset: 0;
|
package/llms-full.txt
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
- import: `import { WrAvatar } from 'ngwr/avatar'`
|
|
46
46
|
- selector: `wr-avatar`
|
|
47
47
|
- exports: WrAvatar, WrAvatarSize, WrAvatarShape
|
|
48
|
-
- Image avatar with a
|
|
48
|
+
- Image avatar with a square, rounded, circle or squircle shape. Projected initials stand in while the image loads and when it fails.
|
|
49
49
|
|
|
50
50
|
## ngwr/back-top
|
|
51
51
|
- import: `import { WrBackTop } from 'ngwr/back-top'`
|
|
@@ -568,7 +568,7 @@
|
|
|
568
568
|
## ngwr/image-cropper
|
|
569
569
|
- import: `import { WrImageCropper } from 'ngwr/image-cropper'`
|
|
570
570
|
- selector: `wr-image-cropper`
|
|
571
|
-
- exports: WrImageCropper, WrCropRect, WrCropHandle, WrImageOutputType
|
|
571
|
+
- exports: WrImageCropper, WrCropRect, WrCropHandle, WrImageCropperStatus, WrImageLoadError, WrImageOutputType
|
|
572
572
|
- DOM-based crop UI. Drag the box to move, drag any of the eight handles to resize. Optional `[aspectRatio]` locks the box shape. `(cropped)` fires with a `Blob` after each drag end — wire to upload or preview.
|
|
573
573
|
|
|
574
574
|
## ngwr/image-cropper/testing
|
|
@@ -840,8 +840,8 @@
|
|
|
840
840
|
|
|
841
841
|
## ngwr/select
|
|
842
842
|
- import: `import { WrSelect } from 'ngwr/select'`
|
|
843
|
-
- selector: `wr-option-group`, `wr-option`, `wr-select`
|
|
844
|
-
- exports: WrSelect, WrOption, WrOptionGroup, WR_SELECT, WrSelectContext, WrSelectMode, WrSelectSearchLoader, WrSelectTagValidator, WrSelectSize
|
|
843
|
+
- selector: `wr-option-group`, `ng-template[wrOptionLeading]`, `wr-option`, `wr-select`
|
|
844
|
+
- exports: WrSelect, WrOption, WrOptionGroup, WrOptionLeading, WR_SELECT, WrSelectContext, WrOptionLeadingContext, WrOptionLeadingPlacement, WrSelectMode, WrSelectSearchLoader, WrSelectTagValidator, WrSelectSize
|
|
845
845
|
- Native-like select built on CDK Overlay. A signal-forms native control — it implements `FormValueControl`, so `[formField]` binds straight to its `value` model. `[(value)]` works standalone, and `[(ngModel)]` / reactive forms keep working through [Angular 22's forms bridge](/guides/forms).
|
|
846
846
|
|
|
847
847
|
## ngwr/select/testing
|
package/package.json
CHANGED
|
@@ -120,6 +120,14 @@
|
|
|
120
120
|
color: var(--wr-color-text-muted);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
// The selected option's leading visual on a single-mode button trigger. Never
|
|
124
|
+
// shrinks: the label beside it is the part that truncates.
|
|
125
|
+
&__value-leading {
|
|
126
|
+
display: inline-flex;
|
|
127
|
+
flex: none;
|
|
128
|
+
align-items: center;
|
|
129
|
+
}
|
|
130
|
+
|
|
123
131
|
&__chevron {
|
|
124
132
|
--wr-icon-size: 1rem;
|
|
125
133
|
flex: 0 0 auto;
|
|
@@ -268,6 +276,17 @@
|
|
|
268
276
|
user-select: none;
|
|
269
277
|
}
|
|
270
278
|
|
|
279
|
+
// A selected option's leading visual — an avatar, an icon. Pulled toward the
|
|
280
|
+
// chip's start edge so a round avatar reads as the chip's cap rather than as a
|
|
281
|
+
// glyph floating in the padding, and spaced from the label by a little more
|
|
282
|
+
// than the chip's own gap.
|
|
283
|
+
&__chip-leading {
|
|
284
|
+
display: inline-flex;
|
|
285
|
+
flex: none;
|
|
286
|
+
align-items: center;
|
|
287
|
+
margin-inline: -0.25rem 0.125rem;
|
|
288
|
+
}
|
|
289
|
+
|
|
271
290
|
&__chip-label {
|
|
272
291
|
overflow: hidden;
|
|
273
292
|
text-overflow: ellipsis;
|
|
@@ -424,6 +443,14 @@
|
|
|
424
443
|
}
|
|
425
444
|
}
|
|
426
445
|
|
|
446
|
+
// An option's leading visual — a sibling of the label inside the row's flex,
|
|
447
|
+
// so `--wr-option-inline-gap` spaces it like any projected icon.
|
|
448
|
+
&__leading {
|
|
449
|
+
display: inline-flex;
|
|
450
|
+
flex: none;
|
|
451
|
+
align-items: center;
|
|
452
|
+
}
|
|
453
|
+
|
|
427
454
|
// Search-mode filter — out-of-match options collapse but stay in the
|
|
428
455
|
// DOM so registration order survives the panel re-open.
|
|
429
456
|
&--hidden {
|
|
@@ -461,6 +488,13 @@
|
|
|
461
488
|
position: relative;
|
|
462
489
|
}
|
|
463
490
|
|
|
491
|
+
// A virtual row is a block, not a flex row (one line, so it can ellipsize),
|
|
492
|
+
// so the leading visual takes its spacing as a margin instead of the gap.
|
|
493
|
+
.wr-option__leading {
|
|
494
|
+
vertical-align: middle;
|
|
495
|
+
margin-inline-end: var(--wr-option-inline-gap, 0.5rem);
|
|
496
|
+
}
|
|
497
|
+
|
|
464
498
|
// Keyboard cursor highlight — the virtualized list is navigated by
|
|
465
499
|
// aria-activedescendant, so real focus never lands on the row and the tint
|
|
466
500
|
// is all there was. `--wr-color-hover` is translucent and lands within about
|
|
@@ -171,7 +171,7 @@ root barrel for components.
|
|
|
171
171
|
| `ngwr/scroll` | `import { WrScroll } from 'ngwr/scroll'` | — |
|
|
172
172
|
| `ngwr/segmented` | `import { WrSegmented } from 'ngwr/segmented'` | `wr-segmented` |
|
|
173
173
|
| `ngwr/segmented/testing` | `import { WrSegmentedHarness } from 'ngwr/segmented/testing'` | — |
|
|
174
|
-
| `ngwr/select` | `import { WrSelect } from 'ngwr/select'` | `wr-option-group` `wr-option` `wr-select` |
|
|
174
|
+
| `ngwr/select` | `import { WrSelect } from 'ngwr/select'` | `wr-option-group` `ng-template[wrOptionLeading]` `wr-option` `wr-select` |
|
|
175
175
|
| `ngwr/select/testing` | `import { WrOptionHarness } from 'ngwr/select/testing'` | — |
|
|
176
176
|
| `ngwr/shiny-text` | `import { WrShinyText } from 'ngwr/shiny-text'` | `[wrShimmer]` `wr-shiny-text` |
|
|
177
177
|
| `ngwr/shiny-text/testing` | `import { WrShinyTextHarness } from 'ngwr/shiny-text/testing'` | — |
|
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>;
|
|
@@ -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. */
|