diff --git a/devtools/projects/demo-standalone/BUILD.bazel b/devtools/projects/demo-standalone/BUILD.bazel new file mode 100644 index 00000000000..ffd0fb0cdc5 --- /dev/null +++ b/devtools/projects/demo-standalone/BUILD.bazel @@ -0,0 +1 @@ +package(default_visibility = ["//visibility:public"]) diff --git a/devtools/projects/demo-standalone/src/BUILD.bazel b/devtools/projects/demo-standalone/src/BUILD.bazel new file mode 100644 index 00000000000..76ff76d8810 --- /dev/null +++ b/devtools/projects/demo-standalone/src/BUILD.bazel @@ -0,0 +1,90 @@ +load("//devtools/tools:ng_module.bzl", "ng_module") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("@build_bazel_rules_nodejs//:index.bzl", "pkg_web") +load("//tools:defaults.bzl", "esbuild", "http_server") +load("//devtools/tools/esbuild:index.bzl", "LINKER_PROCESSED_FW_PACKAGES") + +package(default_visibility = ["//visibility:public"]) + +sass_binary( + name = "demo_styles", + src = "styles.scss", + include_paths = ["external/npm/node_modules"], + sourcemap = False, + deps = ["//devtools:material_sass_deps"], +) + +sass_binary( + name = "firefox_styles", + src = "styles/firefox_styles.scss", +) + +sass_binary( + name = "chrome_styles", + src = "styles/chrome_styles.scss", +) + +ng_module( + name = "demo", + srcs = ["main.ts"], + deps = [ + "//devtools/projects/demo-standalone/src/app", + "//devtools/src:demo_application_environment", + "//devtools/src:demo_application_operations", + "//packages/common", + "//packages/common/http", + "//packages/core", + "//packages/core/src/util", + "//packages/platform-browser", + "@npm//@types", + "@npm//rxjs", + ], +) + +esbuild( + name = "bundle", + config = "//devtools/tools/esbuild:esbuild_config_esm", + entry_points = [":main.ts"], + platform = "browser", + splitting = True, + target = "es2016", + deps = LINKER_PROCESSED_FW_PACKAGES + [":demo"], +) + +exports_files(["index.html"]) + +filegroup( + name = "dev_app_static_files", + srcs = [ + ":chrome_styles", + ":demo_styles", + ":firefox_styles", + ":index.html", + "//packages/zone.js/bundles:zone.umd.js", + ], +) + +pkg_web( + name = "devapp", + srcs = [":dev_app_static_files"] + [ + ":bundle", + "@npm//:node_modules/tslib/tslib.js", + ], + # Currently, ibazel doesn't allow passing in flags to bazel run. + # This means we are not able to use --config snapshot-build + # to access the current commit SHA. + # Since we still want to be able to use ibazel to speed up + # local development, we supply an empty string for the SHA substitution. + # This does not effect production builds. + substitutions = {"BUILD_SCM_COMMIT_SHA": ""}, +) + +http_server( + name = "devserver", + srcs = [":dev_app_static_files"], + additional_root_paths = ["angular/devtools/projects/demo-standalone/src/devapp"], + tags = ["manual"], + deps = [ + ":devapp", + ], +) diff --git a/devtools/projects/demo-standalone/src/app/BUILD.bazel b/devtools/projects/demo-standalone/src/app/BUILD.bazel new file mode 100644 index 00000000000..087551ad399 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/BUILD.bazel @@ -0,0 +1,19 @@ +load("//devtools/tools:ng_module.bzl", "ng_module") + +package(default_visibility = ["//visibility:public"]) + +ng_module( + name = "app", + srcs = [ + "app.component.ts", + ], + deps = [ + "//devtools/projects/demo-standalone/src/app/demo-app", + "//devtools/projects/demo-standalone/src/app/devtools-app", + "//devtools/projects/ng-devtools", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser/animations", + "//packages/router", + ], +) diff --git a/devtools/projects/demo-standalone/src/app/app.component.ts b/devtools/projects/demo-standalone/src/app/app.component.ts new file mode 100644 index 00000000000..f7724ead247 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/app.component.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component} from '@angular/core'; +import {Router, RouterOutlet} from '@angular/router'; + +@Component({ + selector: 'app-root', + template: ``, + standalone: true, + imports: [RouterOutlet] +}) +export class AppComponent { + constructor(public router: Router) {} +} diff --git a/devtools/projects/demo-standalone/src/app/demo-app/BUILD.bazel b/devtools/projects/demo-standalone/src/app/demo-app/BUILD.bazel new file mode 100644 index 00000000000..5af1197e8d2 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/BUILD.bazel @@ -0,0 +1,41 @@ +load("//devtools/tools:ng_module.bzl", "ng_module") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary", "sass_library") + +package(default_visibility = ["//visibility:public"]) + +sass_library( + name = "todo_mvc", + srcs = [ + "@npm//:node_modules/todomvc-app-css/index.css", + "@npm//:node_modules/todomvc-common/base.css", + ], +) + +sass_binary( + name = "demo_app_component_styles", + src = "demo-app.component.scss", + deps = [ + ":todo_mvc", + ], +) + +ng_module( + name = "demo-app", + srcs = [ + "demo-app.component.ts", + "heavy.component.ts", + "zippy.component.ts", + ], + angular_assets = [ + "demo-app.component.html", + ":demo_app_component_styles", + ], + deps = [ + "//devtools/projects/demo-standalone/src/app/demo-app/todo", + "//devtools/projects/ng-devtools-backend", + "//devtools/src:zone-unaware-iframe_message_bus", + "//packages/core", + "//packages/elements", + "//packages/router", + ], +) diff --git a/devtools/projects/demo-standalone/src/app/demo-app/demo-app.component.html b/devtools/projects/demo-standalone/src/app/demo-app/demo-app.component.html new file mode 100644 index 00000000000..36cc4c6bd2e --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/demo-app.component.html @@ -0,0 +1,4 @@ + +This is my content + +
HTMLElement
diff --git a/devtools/projects/demo-standalone/src/app/demo-app/demo-app.component.scss b/devtools/projects/demo-standalone/src/app/demo-app/demo-app.component.scss new file mode 100644 index 00000000000..e281c4b6858 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/demo-app.component.scss @@ -0,0 +1,2 @@ +@use 'external/npm/node_modules/todomvc-app-css/index.css'; +@use 'external/npm/node_modules/todomvc-common/base.css'; diff --git a/devtools/projects/demo-standalone/src/app/demo-app/demo-app.component.ts b/devtools/projects/demo-standalone/src/app/demo-app/demo-app.component.ts new file mode 100644 index 00000000000..636a311c182 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/demo-app.component.ts @@ -0,0 +1,65 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, CUSTOM_ELEMENTS_SCHEMA, ElementRef, EventEmitter, inject, Injector, Input, Output, ViewChild, ViewEncapsulation} from '@angular/core'; +import {createCustomElement} from '@angular/elements'; +import {RouterOutlet} from '@angular/router'; +import {initializeMessageBus} from 'ng-devtools-backend'; + +import {ZoneUnawareIFrameMessageBus} from '../../../../../src/zone-unaware-iframe-message-bus'; + +import {HeavyComponent} from './heavy.component'; +import {ZippyComponent} from './zippy.component'; + +@Component({ + selector: 'app-demo-component', + templateUrl: './demo-app.component.html', + styleUrls: ['./demo-app.component.scss'], + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [HeavyComponent, RouterOutlet], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class DemoAppComponent { + @ViewChild(ZippyComponent) zippy: ZippyComponent; + @ViewChild('elementReference') elementRef: ElementRef; + + @Input('input_one') inputOne = 'input one'; + @Input() inputTwo = 'input two'; + + @Output() outputOne = new EventEmitter(); + @Output('output_two') outputTwo = new EventEmitter(); + + constructor() { + const el = createCustomElement(ZippyComponent, {injector: inject(Injector)}); + customElements.define('app-zippy', el as any); + } + + getTitle(): '► Click to expand'|'▼ Click to collapse' { + if (!this.zippy || !this.zippy.visible) { + return '► Click to expand'; + } + return '▼ Click to collapse'; + } +} + +export const ROUTES = [ + { + path: '', + component: DemoAppComponent, + children: [ + { + path: '', + loadChildren: () => import('./todo/todo-app.component').then((m) => m.ROUTES), + }, + ], + }, +]; + +initializeMessageBus(new ZoneUnawareIFrameMessageBus( + 'angular-devtools-backend', 'angular-devtools', () => window.parent)); diff --git a/devtools/projects/demo-standalone/src/app/demo-app/heavy.component.ts b/devtools/projects/demo-standalone/src/app/demo-app/heavy.component.ts new file mode 100644 index 00000000000..bca53cb54f1 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/heavy.component.ts @@ -0,0 +1,43 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, Input} from '@angular/core'; + +const fib = (n: number) => { + if (n === 1 || n === 2) { + return 1; + } + return fib(n - 1) + fib(n - 2); +}; + +@Component({selector: 'app-heavy', template: `

{{ calculate() }}

`, standalone: true}) +export class HeavyComponent { + @Input() + set foo(_: any) { + } + + state = { + nested: { + props: { + foo: 1, + bar: 2, + }, + [Symbol(3)](): + number { + return 1.618; + }, + get foo(): + number { + return 42; + }, + }, + }; + calculate(): number { + return fib(15); + } +} diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/BUILD.bazel b/devtools/projects/demo-standalone/src/app/demo-app/todo/BUILD.bazel new file mode 100644 index 00000000000..10b72fee328 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/BUILD.bazel @@ -0,0 +1,20 @@ +load("//devtools/tools:ng_module.bzl", "ng_module") + +package(default_visibility = ["//visibility:public"]) + +ng_module( + name = "todo", + srcs = [ + "dialog.component.ts", + "todo-app.component.ts", + ], + deps = [ + "//devtools/projects/demo-standalone/src/app/demo-app/todo/about", + "//devtools/projects/demo-standalone/src/app/demo-app/todo/home", + "//packages/common", + "//packages/core", + "//packages/forms", + "//packages/router", + "@npm//@angular/material", + ], +) diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/about/BUILD.bazel b/devtools/projects/demo-standalone/src/app/demo-app/todo/about/BUILD.bazel new file mode 100644 index 00000000000..e19d51b17c4 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/about/BUILD.bazel @@ -0,0 +1,12 @@ +load("//devtools/tools:ng_module.bzl", "ng_module") + +package(default_visibility = ["//visibility:public"]) + +ng_module( + name = "about", + srcs = ["about.component.ts"], + deps = [ + "//packages/core", + "//packages/router", + ], +) diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/about/about.component.ts b/devtools/projects/demo-standalone/src/app/demo-app/todo/about/about.component.ts new file mode 100644 index 00000000000..51a288972fa --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/about/about.component.ts @@ -0,0 +1,24 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component} from '@angular/core'; +import {RouterLink, RouterOutlet} from '@angular/router'; + +@Component({ + selector: 'app-about', + standalone: true, + imports: [RouterOutlet, RouterLink], + template: ` + About component + Home + Home + Home + ` +}) +export class AboutComponent { +} diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/dialog.component.ts b/devtools/projects/demo-standalone/src/app/demo-app/todo/dialog.component.ts new file mode 100644 index 00000000000..c0cbda8eb65 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/dialog.component.ts @@ -0,0 +1,48 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {CommonModule} from '@angular/common'; +import {Component, Inject} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogModule as MatDialogModule, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatLegacyFormFieldModule as MatFormFieldModule} from '@angular/material/legacy-form-field'; + + +export interface DialogData { + animal: string; + name: string; +} + +@Component({ + selector: 'app-dialog', + standalone: true, + imports: [MatDialogModule, MatFormFieldModule, FormsModule, CommonModule], + template: ` +

Hi {{ data.name }}

+
+

What's your favorite animal?

+ + Favorite Animal + + +
+
+ + +
+ `, +}) +export class DialogComponent { + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: DialogData) {} + + onNoClick(): void { + this.dialogRef.close(); + } +} diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/home/BUILD.bazel b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/BUILD.bazel new file mode 100644 index 00000000000..9a470375245 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/BUILD.bazel @@ -0,0 +1,18 @@ +load("//devtools/tools:ng_module.bzl", "ng_module") + +package(default_visibility = ["//visibility:public"]) + +ng_module( + name = "home", + srcs = [ + "sample.pipe.ts", + "todo.component.ts", + "todos.component.ts", + "tooltip.directive.ts", + ], + deps = [ + "//packages/common", + "//packages/core", + "//packages/router", + ], +) diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/home/sample.pipe.ts b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/sample.pipe.ts new file mode 100644 index 00000000000..9b7ad7eef84 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/sample.pipe.ts @@ -0,0 +1,21 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {OnDestroy, Pipe, PipeTransform} from '@angular/core'; + +@Pipe({name: 'sample', pure: false, standalone: true}) +export class SamplePipe implements PipeTransform, OnDestroy { + transform(val: any): void { + return val; + } + + ngOnDestroy(): void { + // tslint:disable-next-line:no-console + console.log('Destroying'); + } +} diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/home/todo.component.ts b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/todo.component.ts new file mode 100644 index 00000000000..34c62bf47e9 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/todo.component.ts @@ -0,0 +1,68 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {CommonModule} from '@angular/common'; +import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core'; + +import {TooltipDirective} from './tooltip.directive'; + +export interface Todo { + id: string; + completed: boolean; + label: string; +} + +@Component({ + selector: 'app-todo', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [CommonModule, TooltipDirective], + styles: [` + .destroy { + cursor: pointer; + display: unset !important; + } + `], + template: ` +
  • +
    + + + +
    + +
  • + ` +}) +export class TodoComponent { + @Input() todo: Todo; + @Output() update = new EventEmitter(); + @Output() delete = new EventEmitter(); + + editMode = false; + + toggle(): void { + this.todo.completed = !this.todo.completed; + this.update.emit(this.todo); + } + + completeEdit(label: string): void { + this.todo.label = label; + this.editMode = false; + this.update.emit(this.todo); + } + + enableEditMode(): void { + this.editMode = true; + } +} diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/home/todos.component.ts b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/todos.component.ts new file mode 100644 index 00000000000..ffc009cf24e --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/todos.component.ts @@ -0,0 +1,165 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {NgForOf} from '@angular/common'; +import {ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output, Pipe, PipeTransform} from '@angular/core'; +import {RouterLink} from '@angular/router'; + +import {SamplePipe} from './sample.pipe'; +import {Todo, TodoComponent} from './todo.component'; +import {TooltipDirective} from './tooltip.directive'; + +export const enum TodoFilter { + All = 'all', + Completed = 'completed', + Active = 'active', +} + +@Pipe({pure: false, name: 'todosFilter', standalone: true}) +export class TodosFilter implements PipeTransform { + transform(todos: Todo[], filter: TodoFilter): Todo[] { + return (todos || []).filter((t) => { + if (filter === TodoFilter.All) { + return true; + } + if (filter === TodoFilter.Active && !t.completed) { + return true; + } + if (filter === TodoFilter.Completed && t.completed) { + return true; + } + return false; + }); + } +} + +const fib = (n: number) => { + if (n === 1 || n === 2) { + return 1; + } + return fib(n - 1) + fib(n - 2); +}; + +@Component({ + selector: 'app-todos', + imports: [NgForOf, RouterLink, TodoComponent, SamplePipe, TodosFilter, TooltipDirective], + standalone: true, + template: ` + Home + Home + Home + +

    {{ 'Sample text processed by a pipe' | sample }}

    + +
    +
    +

    todos

    + +
    +
    + + +
      + +
    +
    +
    + + {{ itemsLeft }} item left + + +
    +
    + ` +}) +export class TodosComponent implements OnInit, OnDestroy { + todos: Todo[] = [ + { + label: 'Buy milk', + completed: false, + id: '42', + }, + { + label: 'Build something fun!', + completed: false, + id: '43', + }, + ]; + + @Output() update = new EventEmitter(); + @Output() delete = new EventEmitter(); + @Output() add = new EventEmitter(); + + private hashListener: EventListenerOrEventListenerObject; + + constructor(private cdRef: ChangeDetectorRef) {} + + ngOnInit(): void { + if (typeof window !== 'undefined') { + window.addEventListener('hashchange', (this.hashListener = () => this.cdRef.markForCheck())); + } + } + + ngOnDestroy(): void { + fib(40); + if (typeof window !== 'undefined') { + window.removeEventListener('hashchange', this.hashListener); + } + } + + get filterValue(): TodoFilter { + if (typeof window !== 'undefined') { + return (window.location.hash.replace(/^#\//, '') as TodoFilter) || TodoFilter.All; + } + return TodoFilter.All; + } + + get itemsLeft(): number { + return (this.todos || []).filter((t) => !t.completed).length; + } + + clearCompleted(): void { + (this.todos || []).filter((t) => t.completed).forEach((t) => this.delete.emit(t)); + } + + addTodo(input: HTMLInputElement): void { + const todo = { + completed: false, + label: input.value, + }; + const result: Todo = {...todo, id: Math.random().toString()}; + this.todos.push(result); + input.value = ''; + } + + onChange(todo: Todo): void { + if (!todo.id) { + return; + } + } + + onDelete(todo: Todo): void { + if (!todo.id) { + return; + } + const idx = this.todos.findIndex((t) => t.id === todo.id); + if (idx < 0) { + return; + } + // tslint:disable-next-line:no-console + console.log('Deleting', idx); + + this.todos.splice(idx, 1); + } +} diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/home/tooltip.directive.ts b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/tooltip.directive.ts new file mode 100644 index 00000000000..f5b5ec29c19 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/home/tooltip.directive.ts @@ -0,0 +1,35 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Directive, HostListener} from '@angular/core'; + +@Directive({selector: '[appTooltip]', standalone: true}) +export class TooltipDirective { + visible = false; + nested = { + child: { + grandchild: { + prop: 1, + }, + }, + }; + + constructor() { + // setInterval(() => this.nested.child.grandchild.prop++, 500); + } + + @HostListener('click') + handleClick(): void { + this.visible = !this.visible; + if (this.visible) { + (this as any).extraProp = true; + } else { + delete (this as any).extraProp; + } + } +} diff --git a/devtools/projects/demo-standalone/src/app/demo-app/todo/todo-app.component.ts b/devtools/projects/demo-standalone/src/app/demo-app/todo/todo-app.component.ts new file mode 100644 index 00000000000..1ab429e754d --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/todo/todo-app.component.ts @@ -0,0 +1,98 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {CommonModule} from '@angular/common'; +import {Component} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {MatLegacyDialog as MatDialog, MatLegacyDialogModule as MatDialogModule} from '@angular/material/legacy-dialog'; +import {MatLegacyFormFieldModule as MatFormFieldModule} from '@angular/material/legacy-form-field'; +import {MatLegacyInputModule as MatInputModule} from '@angular/material/legacy-input'; +import {RouterLink, RouterOutlet} from '@angular/router'; + +import {DialogComponent} from './dialog.component'; + +@Component({ + selector: 'app-todo-demo', + standalone: true, + imports: [ + RouterLink, RouterOutlet, MatDialogModule, MatFormFieldModule, MatInputModule, FormsModule, + CommonModule + ], + styles: [` + nav { + padding-top: 20px; + padding-bottom: 10px; + + a { + margin-right: 15px; + text-decoration: none; + } + } + + .dialog-open-button { + border: 1px solid #ccc; + padding: 10px; + margin-right: 20px; + } + `], + template: ` + + + + + + ` +}) +export class TodoAppComponent { + name: string; + animal: string; + + constructor(public dialog: MatDialog) {} + + openDialog(): void { + const dialogRef = this.dialog.open(DialogComponent, { + width: '250px', + data: {name: this.name, animal: this.animal}, + }); + + dialogRef.afterClosed().subscribe((result) => { + // tslint:disable-next-line:no-console + console.log('The dialog was closed'); + + this.animal = result; + }); + } +} + +export const ROUTES = [ + { + path: 'todos', + component: TodoAppComponent, + children: [ + { + path: 'app', + loadComponent: () => import('./home/todos.component').then((m) => m.TodosComponent), + }, + { + path: 'about', + loadComponent: () => import('./about/about.component').then((m) => m.AboutComponent), + }, + { + path: '**', + redirectTo: 'app', + }, + ], + }, + { + path: '**', + redirectTo: 'todos', + }, +]; diff --git a/devtools/projects/demo-standalone/src/app/demo-app/zippy.component.ts b/devtools/projects/demo-standalone/src/app/demo-app/zippy.component.ts new file mode 100644 index 00000000000..c01a08d9ed8 --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/demo-app/zippy.component.ts @@ -0,0 +1,47 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'app-zippy', + standalone: true, + styles: [` + :host { + user-select: none; + } + + header { + max-width: 120px; + border: 1px solid #ccc; + padding-left: 10px; + padding-right: 10px; + cursor: pointer; + } + + div { + max-width: 120px; + border-left: 1px solid #ccc; + border-right: 1px solid #ccc; + border-bottom: 1px solid #ccc; + padding: 10px; + } + `], + template: ` +
    +
    {{ title }}
    +
    + +
    +
    + ` +}) +export class ZippyComponent { + @Input() title: string; + visible = false; +} diff --git a/devtools/projects/demo-standalone/src/app/devtools-app/BUILD.bazel b/devtools/projects/demo-standalone/src/app/devtools-app/BUILD.bazel new file mode 100644 index 00000000000..8f5be35470b --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/devtools-app/BUILD.bazel @@ -0,0 +1,16 @@ +load("//devtools/tools:ng_module.bzl", "ng_module") + +package(default_visibility = ["//visibility:public"]) + +ng_module( + name = "devtools-app", + srcs = ["devtools-app.component.ts"], + deps = [ + "//devtools/projects/ng-devtools", + "//devtools/projects/protocol", + "//devtools/src:iframe_message_bus", + "//packages/common", + "//packages/core", + "//packages/router", + ], +) diff --git a/devtools/projects/demo-standalone/src/app/devtools-app/devtools-app.component.ts b/devtools/projects/demo-standalone/src/app/devtools-app/devtools-app.component.ts new file mode 100644 index 00000000000..912c699c6ca --- /dev/null +++ b/devtools/projects/demo-standalone/src/app/devtools-app/devtools-app.component.ts @@ -0,0 +1,51 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, ElementRef, ViewChild} from '@angular/core'; +import {DevToolsModule as NgDevToolsModule} from 'ng-devtools'; +import {Events, MessageBus, PriorityAwareMessageBus} from 'protocol'; + +import {IFrameMessageBus} from '../../../../../src/iframe-message-bus'; + +@Component({ + standalone: true, + imports: [NgDevToolsModule], + providers: [ + { + provide: MessageBus, + useFactory(): MessageBus { + return new PriorityAwareMessageBus(new IFrameMessageBus( + 'angular-devtools', 'angular-devtools-backend', + // tslint:disable-next-line: no-non-null-assertion + () => (document.querySelector('#sample-app') as HTMLIFrameElement).contentWindow!)); + }, + }, + ], + styles: [` + iframe { + height: 340px; + width: 100%; + border: 0; + } + + .devtools-wrapper { + height: calc(100vh - 345px); + } + `], + template: ` + +
    +
    + +
    + ` +}) +export class DevToolsComponent { + messageBus: IFrameMessageBus|null = null; + @ViewChild('ref') iframe: ElementRef; +} diff --git a/devtools/projects/demo-standalone/src/assets/.gitkeep b/devtools/projects/demo-standalone/src/assets/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/devtools/projects/demo-standalone/src/environments/BUILD.bazel b/devtools/projects/demo-standalone/src/environments/BUILD.bazel new file mode 100644 index 00000000000..47a65ebf603 --- /dev/null +++ b/devtools/projects/demo-standalone/src/environments/BUILD.bazel @@ -0,0 +1,13 @@ +load("//devtools/tools:typescript.bzl", "ts_library") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "environments", + srcs = [ + "environment.ts", + ], + deps = [ + "//packages/platform-browser", + ], +) diff --git a/devtools/projects/demo-standalone/src/environments/environment.ts b/devtools/projects/demo-standalone/src/environments/environment.ts new file mode 100644 index 00000000000..6830d2daa76 --- /dev/null +++ b/devtools/projects/demo-standalone/src/environments/environment.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export const environment = { + production: false, + LATEST_SHA: 'BUILD_SCM_COMMIT_SHA', // Stamped at build time by bazel +}; diff --git a/devtools/projects/demo-standalone/src/index.html b/devtools/projects/demo-standalone/src/index.html new file mode 100644 index 00000000000..9e37f92c6a5 --- /dev/null +++ b/devtools/projects/demo-standalone/src/index.html @@ -0,0 +1,21 @@ + + + + + AngularDevtools + + + + + + + + +
    + +
    + + + + + diff --git a/devtools/projects/demo-standalone/src/main.ts b/devtools/projects/demo-standalone/src/main.ts new file mode 100644 index 00000000000..353cacd0108 --- /dev/null +++ b/devtools/projects/demo-standalone/src/main.ts @@ -0,0 +1,44 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {bootstrapApplication} from '@angular/platform-browser'; +import {provideAnimations} from '@angular/platform-browser/animations'; +import {provideRouter} from '@angular/router'; +import {ApplicationEnvironment, ApplicationOperations} from 'ng-devtools'; + +import {DemoApplicationEnvironment} from '../../../src/demo-application-environment'; +import {DemoApplicationOperations} from '../../../src/demo-application-operations'; + +import {AppComponent} from './app/app.component'; + + +bootstrapApplication(AppComponent, { + providers: [ + provideAnimations(), + provideRouter([ + { + path: '', + loadComponent: () => + import('./app/devtools-app/devtools-app.component').then((m) => m.DevToolsComponent), + pathMatch: 'full', + }, + { + path: 'demo-app', + loadChildren: () => import('./app/demo-app/demo-app.component').then((m) => m.ROUTES), + }, + ]), + { + provide: ApplicationOperations, + useClass: DemoApplicationOperations, + }, + { + provide: ApplicationEnvironment, + useClass: DemoApplicationEnvironment, + }, + ] +}); diff --git a/devtools/projects/demo-standalone/src/styles.scss b/devtools/projects/demo-standalone/src/styles.scss new file mode 100644 index 00000000000..bb87d3e30fd --- /dev/null +++ b/devtools/projects/demo-standalone/src/styles.scss @@ -0,0 +1,48 @@ +@use 'sass:map'; +@use 'external/npm/node_modules/@angular/material/index' as mat; +@include mat.all-legacy-component-typographies(); +@include mat.legacy-core(); + +html, +body { + padding: 0; + margin: 0; +} + +// Light theme +$light-primary: mat.define-palette(mat.$grey-palette, 700, 200); +$light-accent: mat.define-palette(mat.$blue-palette, 800); +$light-theme: mat.define-light-theme($light-primary, $light-accent); + +// Dark theme +$dark-primary: mat.define-palette(mat.$blue-grey-palette, 50); +$dark-accent: mat.define-palette(mat.$blue-palette, 200); +$dark-theme: map.deep-merge( + mat.define-dark-theme($dark-primary, $dark-accent), + ( + 'color': ( + 'background': ( + background: #202124, + card: #202124, + ), + 'foreground': ( + text: #bcc5ce, + ), + ), + 'background': ( + background: #202124, + card: #202124, + ), + 'foreground': ( + 'text': #bcc5ce, + ), + ) +); + +.light-theme { + @include mat.all-legacy-component-themes($light-theme); +} + +.dark-theme { + @include mat.all-legacy-component-themes($dark-theme); +} diff --git a/devtools/projects/demo-standalone/src/styles/chrome_styles.scss b/devtools/projects/demo-standalone/src/styles/chrome_styles.scss new file mode 100644 index 00000000000..f7b37f49000 --- /dev/null +++ b/devtools/projects/demo-standalone/src/styles/chrome_styles.scss @@ -0,0 +1,2 @@ +/** Specific style for Chrome browser */ + diff --git a/devtools/projects/demo-standalone/src/styles/firefox_styles.scss b/devtools/projects/demo-standalone/src/styles/firefox_styles.scss new file mode 100644 index 00000000000..824bf3f4bb1 --- /dev/null +++ b/devtools/projects/demo-standalone/src/styles/firefox_styles.scss @@ -0,0 +1,2 @@ +/** Specific style for Firefox browser */ + diff --git a/devtools/src/index.html b/devtools/src/index.html index c397bc74d1f..9e37f92c6a5 100644 --- a/devtools/src/index.html +++ b/devtools/src/index.html @@ -8,7 +8,6 @@ - diff --git a/package.json b/package.json index a3e30579641..b91597222a3 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "ts-circular-deps:approve": "yarn -s ng-dev ts-circular-deps approve --config ./packages/circular-deps-test.conf.js", "check-tooling-setup": "yarn tsc --project .ng-dev/tsconfig.json && yarn tsc --project scripts/tsconfig.json", "devtools:devserver": "ibazel run //devtools/src:devserver", + "devtools:devserver:demo-standalone": "ibazel run //devtools/projects/demo-standalone/src:devserver", "devtools:build:chrome": "bazelisk build --config snapshot-build --//devtools/projects/shell-browser/src:flag_browser=chrome -- devtools/projects/shell-browser/src:prodapp", "devtools:build:firefox": "bazelisk build --config snapshot-build --//devtools/projects/shell-browser/src:flag_browser=firefox -- devtools/projects/shell-browser/src:prodapp", "devtools:test": "bazelisk test --config snapshot-build --//devtools/projects/shell-browser/src:flag_browser=chrome -- //devtools/..."