@uppy/angular: declare components as standalone & support 20.x (#5843)

Closes #5759 
Closes #5833.

This PR: 

- Introduces updates in @uppy/angular that improve developer experience
(DX) and also address open issues

The @uppy/angular package underwent major updates in v0.80
([27492bc](27492bca8a)),
where we dropped support for NgModules in favor of standalone
components. This change aligns with the direction set by the Angular
team — starting from Angular v17, and becoming default in v19, all
components are standalone by default. This is now the recommended way to
build UI components in Angular.
 
However, the docs and examples have not yet been updated to reflect
this. That will be addressed in #5818.

Even though components are standalone by default starting from Angular
17+, it is still considered good practice to explicitly declare them as
standalone. This is also validated by the Angular LSP, which raises an
error when this declaration is missing.

<img width="1042" height="742" alt="image"
src="https://github.com/user-attachments/assets/1f557871-c302-4f02-9ded-ddf27c6175bd"
/>


Changes in this PR:

- Explicitly mark all components as standalone
- Fix demo components
- Add support for Angular 20

---------

Co-authored-by: Merlijn Vos <merlijn@soverin.net>
This commit is contained in:
Prakash 2025-08-01 20:52:19 +05:30 committed by GitHub
parent 1b1a9e3591
commit 8b8ab01440
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 62 additions and 13 deletions

View file

@ -0,0 +1,5 @@
---
"@uppy/angular": minor
---
Declare components as standalone & support 20.x

View file

@ -40,6 +40,6 @@
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"ng-packagr": "^19.0.0",
"typescript": "^5.6"
"typescript": "~5.5.4"
}
}

View file

@ -28,8 +28,8 @@
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/common": "^17.0.0 || ^18.0.0 || ^19.0.0",
"@angular/core": "^17.0.0 || ^18.0.0 || ^19.0.0",
"@angular/common": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0",
"@angular/core": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0",
"@uppy/core": "workspace:^",
"@uppy/dashboard": "workspace:^",
"@uppy/drag-drop": "workspace:^",

View file

@ -2,6 +2,8 @@ import { ChangeDetectionStrategy, Component } from "@angular/core";
import { Uppy } from "@uppy/core";
import type * as Dashboard from "@uppy/dashboard";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { DashboardModalComponent } from "./dashboard-modal.component";
@Component({
selector: "uppy-dashboard-demo",
@ -10,8 +12,10 @@ import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
[props]="props"
></uppy-dashboard-modal>`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [DashboardModalComponent],
})
export class DashboardModalDemoComponent<M extends Meta, B extends Body> {
uppy: Uppy<M, B> = new Uppy({ debug: true, autoProceed: true });
props?: Dashboard.DashboardOptions<M, B>;
props: Dashboard.DashboardOptions<M, B> = {};
}

View file

@ -18,6 +18,7 @@ import { UppyAngularWrapper } from "../../utils/wrapper";
selector: "uppy-dashboard-modal",
template: "",
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class DashboardModalComponent<M extends Meta, B extends Body>
extends UppyAngularWrapper<M, B, DashboardOptions<M, B>, Dashboard<M, B>>

View file

@ -2,13 +2,16 @@ import { ChangeDetectionStrategy, Component } from "@angular/core";
import { Uppy } from "@uppy/core";
import type * as Dashboard from "@uppy/dashboard";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { DashboardComponent } from "./dashboard.component";
@Component({
selector: "uppy-dashboard-demo",
template: `<uppy-dashboard [uppy]="uppy" [props]="props"></uppy-dashboard>`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [DashboardComponent],
})
export class DashboardDemoComponent<M extends Meta, B extends Body> {
uppy: Uppy<M, B> = new Uppy({ debug: true, autoProceed: true });
props?: Dashboard.DashboardOptions<M, B>;
props: Dashboard.DashboardOptions<M, B> = {};
}

View file

@ -18,6 +18,7 @@ import { UppyAngularWrapper } from "../../utils/wrapper";
selector: "uppy-dashboard",
template: "",
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class DashboardComponent<M extends Meta, B extends Body>
extends UppyAngularWrapper<M, B, DashboardOptions<M, B>>

View file

@ -2,11 +2,15 @@ import { ChangeDetectionStrategy, Component } from "@angular/core";
import { Uppy } from "@uppy/core";
import type * as DragDrop from "@uppy/drag-drop";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { DragDropComponent } from "./drag-drop.component";
@Component({
selector: "uppy-drag-drop-demo",
template: ` <uppy-drag-drop [uppy]="uppy" [props]="props"></uppy-drag-drop> `,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [DragDropComponent],
})
export class DragDropDemoComponent<M extends Meta, B extends Body> {
uppy: Uppy<M, B> = new Uppy({ debug: true, autoProceed: true });

View file

@ -18,6 +18,7 @@ import { UppyAngularWrapper } from "../../utils/wrapper";
selector: "uppy-drag-drop",
template: "",
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class DragDropComponent<M extends Meta, B extends Body>
extends UppyAngularWrapper<M, B, DragDropOptions>

View file

@ -9,6 +9,9 @@ import { Uppy } from "@uppy/core";
import type { ProgressBarOptions } from "@uppy/progress-bar";
import Tus from "@uppy/tus";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { ProgressBarComponent } from "./progress-bar.component";
import { DragDropComponent } from "../drag-drop/drag-drop.component";
import { CommonModule } from "@angular/common";
@Component({
selector: "uppy-progress-bar-demo",
@ -56,6 +59,8 @@ import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
</section>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [ProgressBarComponent, DragDropComponent, CommonModule],
})
export class ProgressBarDemoComponent<M extends Meta, B extends Body>
implements OnInit
@ -81,9 +86,9 @@ export class ProgressBarDemoComponent<M extends Meta, B extends Body>
updateFileList =
(target: string) =>
(file, response): void => {
this[target] = [
...this[target],
(file: any, response: any): void => {
(this as any)[target] = [
...(this as any)[target],
{ url: response.uploadURL, fileName: file.name },
];
this.cdr.markForCheck();

View file

@ -18,6 +18,7 @@ import { UppyAngularWrapper } from "../../utils/wrapper";
selector: "uppy-progress-bar",
template: "",
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class ProgressBarComponent<M extends Meta, B extends Body>
extends UppyAngularWrapper<M, B, ProgressBarOptions>

View file

@ -4,6 +4,7 @@ import FileInput from "@uppy/file-input";
import type * as StatusBar from "@uppy/status-bar";
import Tus from "@uppy/tus";
import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
import { StatusBarComponent } from "./status-bar.component";
@Component({
selector: "uppy-status-bar-demo",
@ -12,6 +13,8 @@ import type { Body, Meta } from "@uppy/utils/lib/UppyFile";
<uppy-status-bar [uppy]="uppy" [props]="props"></uppy-status-bar>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [StatusBarComponent],
})
export class StatusBarDemoComponent<M extends Meta, B extends Body>
implements OnInit

View file

@ -18,6 +18,7 @@ import { UppyAngularWrapper } from "../../utils/wrapper";
selector: "uppy-status-bar",
template: "",
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class StatusBarComponent<M extends Meta, B extends Body>
extends UppyAngularWrapper<M, B, StatusBarOptions>

View file

@ -11227,8 +11227,8 @@ __metadata:
dependencies:
tslib: "npm:^2.0.0"
peerDependencies:
"@angular/common": ^17.0.0 || ^18.0.0 || ^19.0.0
"@angular/core": ^17.0.0 || ^18.0.0 || ^19.0.0
"@angular/common": ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0
"@angular/core": ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0
"@uppy/core": "workspace:^"
"@uppy/dashboard": "workspace:^"
"@uppy/drag-drop": "workspace:^"
@ -12868,7 +12868,7 @@ __metadata:
ng-packagr: "npm:^19.0.0"
rxjs: "npm:~7.8.0"
tslib: "npm:^2.3.0"
typescript: "npm:^5.6"
typescript: "npm:~5.5.4"
zone.js: "npm:~0.15.0"
languageName: unknown
linkType: soft
@ -29867,7 +29867,7 @@ __metadata:
languageName: node
linkType: hard
"typescript@npm:^5.0.0, typescript@npm:^5.6, typescript@npm:^5.8.3":
"typescript@npm:^5.0.0, typescript@npm:^5.8.3":
version: 5.8.3
resolution: "typescript@npm:5.8.3"
bin:
@ -29897,7 +29897,17 @@ __metadata:
languageName: node
linkType: hard
"typescript@patch:typescript@npm%3A^5.0.0#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.6#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.8.3#optional!builtin<compat/typescript>":
"typescript@npm:~5.5.4":
version: 5.5.4
resolution: "typescript@npm:5.5.4"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10/1689ccafef894825481fc3d856b4834ba3cc185a9c2878f3c76a9a1ef81af04194849840f3c69e7961e2312771471bb3b460ca92561e1d87599b26c37d0ffb6f
languageName: node
linkType: hard
"typescript@patch:typescript@npm%3A^5.0.0#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.8.3#optional!builtin<compat/typescript>":
version: 5.8.3
resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin<compat/typescript>::version=5.8.3&hash=8c6c40"
bin:
@ -29927,6 +29937,16 @@ __metadata:
languageName: node
linkType: hard
"typescript@patch:typescript@npm%3A~5.5.4#optional!builtin<compat/typescript>":
version: 5.5.4
resolution: "typescript@patch:typescript@npm%3A5.5.4#optional!builtin<compat/typescript>::version=5.5.4&hash=379a07"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10/746fdd0865c5ce4f15e494c57ede03a9e12ede59cfdb40da3a281807853fe63b00ef1c912d7222143499aa82f18b8b472baa1830df8804746d09b55f6cf5b1cc
languageName: node
linkType: hard
"ua-parser-js@npm:^0.7.30":
version: 0.7.38
resolution: "ua-parser-js@npm:0.7.38"