mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
211 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 70668befde | |||
| 767c6b4754 | |||
| 1bf6bfc07f | |||
| 70313f13fe | |||
| f9b69cc67b | |||
| 52dfcd9865 | |||
| d793dde00f | |||
| 04d518bc26 | |||
| 2cf4da0ea1 | |||
| f15d33d68b | |||
| 33e8cde034 | |||
| 8343b05ad7 | |||
| 443654ac77 | |||
| 49a36f4cc7 | |||
| 6505a26ee0 | |||
| 96095f435e | |||
| 2b254bc050 | |||
| e5110b4fa1 | |||
| f1e4446071 | |||
| 79519409cd | |||
| 4729e804ac | |||
| 575f8a39c7 | |||
| f80e6c2f77 | |||
| bbd5cf82b1 | |||
| c64db1d0f3 | |||
| 5301711b4e | |||
| 92ac00d507 | |||
| fdd7a4deb5 | |||
| df7bf134fe | |||
| 665b33ecdc | |||
| eb2803237b | |||
| 6f75b6e3f6 | |||
| efb64bf9fd | |||
| e0a260a425 | |||
| 8dfbb8b5d5 | |||
| 3845f7e930 | |||
| cc9a58a2ae | |||
| e3681b7b5f | |||
| 70a5b651be | |||
| 4c7126d23b | |||
| d6268c0bbb | |||
| 0a4c647ef0 | |||
| b9b934363a | |||
| cfe7340270 | |||
| 4f0d29d92a | |||
| 290b2814e1 | |||
| 9f99b14882 | |||
| 3de87e1eda | |||
| affd2362eb | |||
| 11657fb0b1 | |||
| 7242da24fb | |||
| 31e6f0d7dc | |||
| 6601f06e44 | |||
| fe69342545 | |||
| c57b0355b5 | |||
| 06952b4f0f | |||
| c133a2c1eb | |||
| 3151bc38a0 | |||
| 49e3c25d62 | |||
| b4227fb3f1 | |||
| 89525ec6b7 | |||
| 1234e873d8 | |||
| 359470979b | |||
| 27c7b60d81 | |||
| 72ed76feb3 | |||
| 278cfd3879 | |||
| 5903bf7c98 | |||
| 051ba061a0 | |||
| 01b035ab03 | |||
| 4742c703df | |||
| 21ecdc036a | |||
| 2499238c59 | |||
| e6ea328cf4 | |||
| b203ab0881 | |||
| f7eb996ad5 | |||
| d9e7ab3db6 | |||
| 458e21e0fe | |||
| e4c9ff7a34 | |||
| c9043fb876 | |||
| 61dbdee6fb | |||
| 27eeff9be6 | |||
| f577f8cb5c | |||
| 643f0f4b22 | |||
| ad9e473e73 | |||
| 18842266de | |||
| 223ff74891 | |||
| 0e1f1ed573 | |||
| b9c995e7d3 | |||
| 0d0a86be29 | |||
| 8078739e62 | |||
| 60aceefc75 | |||
| 696e827391 | |||
| 6a5620442f | |||
| 62d847325d | |||
| 3c8d69794c | |||
| 93f3cca5e9 | |||
| ea70b003b0 | |||
| 5d1b950324 | |||
| e6642496b0 | |||
| 26c2fe6db2 | |||
| e828f1c765 | |||
| 01e98ded2e | |||
| 4a1dcb2d82 | |||
| 58720dbc56 | |||
| 9cc0f4d003 | |||
| 82593de5a4 | |||
| 068bb9d3c5 | |||
| eb6af58446 | |||
| 760e2aaa79 | |||
| 85cf7f0daa | |||
| f0bcf876ec | |||
| 6b34e5f444 | |||
| ac50dbc8e1 | |||
| 32ad1e09b4 | |||
| cb75f9ce85 | |||
| ded654dc6b | |||
| 05adfcf8f2 | |||
| aa39f87021 | |||
| 0643f541f9 | |||
| d89a80a970 | |||
| 0f3f346ec4 | |||
| 74017eb355 | |||
| 72877b6c60 | |||
| c0446da35f | |||
| ae4e2e02d0 | |||
| 7f9990710e | |||
| 6027c9128c | |||
| b108ece707 | |||
| 3cc549c723 | |||
| e817f8c830 | |||
| 1ea5c97703 | |||
| d81f8ea0f6 | |||
| 654ed6512b | |||
| 134742fb7b | |||
| 5594a535c1 | |||
| 5097df84b4 | |||
| c4784bd39e | |||
| d576ea577d | |||
| 230b65cc81 | |||
| 6d3b09326a | |||
| 9a764e0f5f | |||
| 9c1a5a5433 | |||
| a649fc8f57 | |||
| 8f16846dd9 | |||
| 114d03f6a6 | |||
| bf5db2b8d3 | |||
| c8b1b15143 | |||
| 559797c19d | |||
| 33ea12a797 | |||
| 1dd06f5e5c | |||
| 76a6984d7b | |||
| f5ed514b41 | |||
| 3396943fd0 | |||
| eecbdc078e | |||
| 40864e85da | |||
| b1c68e66a7 | |||
| 757e0cfd26 | |||
| 532633301b | |||
| 8474277b49 | |||
| 5ad2e1bae0 | |||
| ab86c4dfaf | |||
| 0587bb77ad | |||
| 79f979a673 | |||
| cc066cb31f | |||
| 3932bab633 | |||
| e66a8ef0da | |||
| ed5b62a140 | |||
| 1f47e885fd | |||
| d1f6bcdacd | |||
| ed292e398a | |||
| 3954dc278b | |||
| 8cf3a72d57 | |||
| 481557e69f | |||
| 13a7ee8424 | |||
| fd3253e093 | |||
| addccead9b | |||
| 8f451b5647 | |||
| e4dcd72926 | |||
| 204aacadb4 | |||
| e9cb3cbefb | |||
| 4871131136 | |||
| fb21801827 | |||
| 3de709f41b | |||
| 47d89c8ca2 | |||
| c7d6053797 | |||
| 03e2b36826 | |||
| 29f074a93f | |||
| 62d7533ca6 | |||
| a59f51f0e6 | |||
| a201d33e0c | |||
| 0875deab8d | |||
| dd37fd821e | |||
| 7b396e8bb2 | |||
| 24b0920755 | |||
| f3a7b3ab67 | |||
| 1c055aa268 | |||
| 0c23d02944 | |||
| 83bac5adc9 | |||
| e01dcae4c5 | |||
| 4cdf4d5760 | |||
| f41d721ce0 | |||
| 0fd8477f3f | |||
| 5dd2f2bb98 | |||
| ca57165c7e | |||
| 4391c44801 | |||
| 985bdeefd3 | |||
| 95bc06d6c3 | |||
| 2c3a067bb6 | |||
| 2c74475969 | |||
| 74af7d85e5 | |||
| 6ad2ef6bd8 |
@@ -1 +0,0 @@
|
||||
../../AGENTS.md
|
||||
@@ -1 +0,0 @@
|
||||
../.gemini/skills
|
||||
+1
-1
@@ -1 +1 @@
|
||||
8.6.0
|
||||
8.5.1
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
description = "Researches part of the codebase and creates a skill for it"
|
||||
prompt="""
|
||||
## Role
|
||||
|
||||
You are an experienced senior developer specializing in reverse engineering and understanding
|
||||
complex code, prompt engineering, and context engineering.
|
||||
|
||||
Your task is to build a complete understanding of the mental model and architecture of the code,
|
||||
and to create an efficient context file that allows a coding agent to understand and work with the
|
||||
code.
|
||||
|
||||
## Guiding Principles
|
||||
|
||||
1. **Deep Analysis:** Understand the _why_ behind the code. Not just a surface level listing of
|
||||
files and classes.
|
||||
|
||||
2. **Curiosity:** Be curious. If something is unclear, confusing, or unexpected you _MUST_
|
||||
investigate further until you fully understand.
|
||||
|
||||
3. **Efficient Token Use:** The final output will be directly included into the context of the
|
||||
coding assistant, so be sure to make efficient use of tokens. Think deeply, but only capture the
|
||||
most important information for the coding agent in the final output
|
||||
|
||||
## Procedure
|
||||
|
||||
1. Fully explore the code before first, with a focus on understanding the architecture and how all
|
||||
of the pieces fit together.
|
||||
|
||||
2. Develop an understanding of the mental model behind the architecture. _Why_ is the code is
|
||||
architected this way? How should developers think about the system?
|
||||
|
||||
3. Document your findings using the given output format described in the next section.
|
||||
|
||||
## Output Format
|
||||
|
||||
Note the following placeholders below:
|
||||
|
||||
- `[package]`: is a unique identifier for the current code package (for example if you're looking at
|
||||
code under `packages/forms/signals` you might use `signal-forms` as the `[package]`)
|
||||
- `[code-location]`: is the location of the current code within the larger repository
|
||||
- `[context]`: is the context to add to the coding agent when it is working with this code.
|
||||
|
||||
With those placeholders in mind, write a file create a new directory under `.gemini/skills` with the
|
||||
name `reference-[package]/`, and under that directory add a `SKILL.md` file with the following
|
||||
content:
|
||||
|
||||
```md
|
||||
---
|
||||
name: reference-[package]
|
||||
description: Explains the mental model and architecture of the code under `[code-location]`. You MUST use this skill any time you plan to work with code in `[code-location]`
|
||||
---
|
||||
|
||||
[context]
|
||||
```
|
||||
|
||||
## Additional User Instructions
|
||||
|
||||
The user may have additional instructions.
|
||||
|
||||
- The user should indicate what package to research
|
||||
- The user may indicate that they want to update a package that has already been researched. In this
|
||||
case, read the existing skill and make any required updates based on your research
|
||||
- The user may request supplemental information be added to the skill (if so, add this to the
|
||||
existing skill in a new markdown file under a `references` directory within the skill. Add a
|
||||
section to the main `SKILL.md` that mentions what supplemental information is available)
|
||||
|
||||
Here are the user's additional instructions:
|
||||
|
||||
{{args}}
|
||||
"""
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"context": {
|
||||
"fileName": ["AGENTS.md", "GEMINI.md"]
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
---
|
||||
name: adev-writing-guide
|
||||
description: Comprehensive writing guide for Angular documentation (adev). Covers Google Technical Writing standards, Angular-specific markdown extensions, code blocks, and components. Use when authoring or reviewing content in adev/src/content.
|
||||
---
|
||||
|
||||
# Angular Documentation (adev) Writing Guide
|
||||
|
||||
This skill provides comprehensive guidelines for authoring content in `adev/src/content`. It combines Google's technical writing standards with Angular-specific markdown conventions, components, and best practices.
|
||||
|
||||
## I. Google Technical Writing Guidelines
|
||||
|
||||
### Tone and Content
|
||||
|
||||
- **Be conversational and friendly:** Maintain a helpful yet professional tone. Avoid being overly casual.
|
||||
- **Write accessibly:** Ensure documentation is understandable to a diverse global audience, including non-native English speakers.
|
||||
- **Audience-first:** Focus on what the user needs to do, not just what the system does.
|
||||
- **Avoid pre-announcing:** Do not mention unreleased features or make unsupported claims.
|
||||
- **Use descriptive link text:** Link text should clearly indicate the destination (e.g., avoid "click here").
|
||||
|
||||
### Language and Grammar
|
||||
|
||||
- **Use second person ("you"):** Address the reader directly.
|
||||
- **Prefer active voice:** Clearly state who or what is performing the action (e.g., "The system generates a token" vs "A token is generated").
|
||||
- **Standard American English:** Use standard American spelling and punctuation.
|
||||
- **Conditional clauses first:** Place "if" or "when" clauses before the instruction (e.g., "If you encounter an error, check the logs").
|
||||
- **Define terms:** Introduce new or unfamiliar terms/acronyms upon first use.
|
||||
- **Consistent terminology:** Use the same term for the same concept throughout the document.
|
||||
- **Conciseness:** Aim for one idea per sentence. Keep sentences short.
|
||||
|
||||
### Formatting and Organization
|
||||
|
||||
- **Sentence case for headings:** Capitalize only the first word and proper nouns in titles and headings.
|
||||
- **Lists:**
|
||||
- **Numbered lists:** Use for sequential steps or prioritized items.
|
||||
- **Bulleted lists:** Use for unordered collections of items.
|
||||
- **Description lists:** Use for term-definition pairs.
|
||||
- **Serial commas:** Use the Oxford comma (comma before the last item in a list of three or more).
|
||||
- **Code formatting:** Use code font for code-related text (filenames, variables, commands).
|
||||
- **UI Elements:** formatting user interface elements in **bold**.
|
||||
- **Date formatting:** Use unambiguous formats (e.g., "September 4, 2024" rather than "9/4/2024").
|
||||
- **Structure:** Use logical hierarchy with clear introductions and navigation. Headings should be task-based where possible.
|
||||
|
||||
### Images and Code Samples
|
||||
|
||||
- **Images:** Use simple, clear illustrations to enhance understanding.
|
||||
- **Captions:** Write captions that support the image.
|
||||
- **Code Samples:**
|
||||
- Ensure code is correct and builds without errors.
|
||||
- Follow language-specific conventions.
|
||||
- **Comments:** Focus on _why_, not _what_. Avoid commenting on obvious code.
|
||||
|
||||
### Reference Hierarchy
|
||||
|
||||
1. Project-specific style guidelines (if any exist in `CONTRIBUTING.md` or similar).
|
||||
2. Google Developer Documentation Style Guide.
|
||||
3. Merriam-Webster (spelling).
|
||||
4. Chicago Manual of Style (non-technical).
|
||||
5. Microsoft Writing Style Guide (technical).
|
||||
|
||||
---
|
||||
|
||||
## II. Angular Documentation Specifics
|
||||
|
||||
### Code Blocks
|
||||
|
||||
Use the appropriate language identifier for syntax highlighting:
|
||||
|
||||
- **TypeScript (Angular):** Use `angular-ts` when TypeScript code examples contain inline templates.
|
||||
- **HTML (Angular):** Use `angular-html` for Angular templates.
|
||||
- **TypeScript (Generic):** Use `ts` for plain TypeScript.
|
||||
- **HTML (Generic):** Use `html` for plain HTML.
|
||||
- **Shell/Terminal:** Use `shell` or `bash`.
|
||||
- **Mermaid Diagrams:** Use `mermaid`.
|
||||
|
||||
#### Attributes
|
||||
|
||||
You can enhance code blocks with attributes in curly braces `{}` after the language identifier:
|
||||
|
||||
- `header="Title"`: Adds a title to the code block.
|
||||
- `linenums`: Enables line numbering.
|
||||
- `highlight="[1, 3-5]"`: Highlights specific lines.
|
||||
- `hideCopy`: Hides the copy button.
|
||||
- `prefer`: Marks code as a preferred example (green border/check).
|
||||
- `avoid`: Marks code as an example to avoid (red border/cross).
|
||||
|
||||
**Example:**
|
||||
|
||||
````markdown
|
||||
```angular-ts {header:"My Component", linenums, highlight="[2]"}
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
template: '<h1>Hello</h1>',
|
||||
})
|
||||
export class App {}
|
||||
```
|
||||
````
|
||||
|
||||
#### `<docs-code>` Component
|
||||
|
||||
For more advanced code block features, use the `<docs-code>` component:
|
||||
|
||||
- `path`: Path to a source file (e.g., `adev/src/content/examples/...`).
|
||||
- `header`: Custom header text.
|
||||
- `language`: Language identifier (e.g., `angular-ts`).
|
||||
- `linenums`: Boolean attribute.
|
||||
- `highlight`: Array of line numbers/ranges (e.g., `[[3,7], 9]`).
|
||||
- `diff`: Path to diff file.
|
||||
- `visibleLines`: Range of lines to show initially (collapsible).
|
||||
- `region`: Region to extract from source file.
|
||||
- `preview`: Boolean. Renders a live preview (StackBlitz). _Only works with standalone examples._
|
||||
- `hideCode`: Boolean. Collapses code by default.
|
||||
|
||||
**Multifile Example:**
|
||||
|
||||
```html
|
||||
<docs-code-multifile path="..." preview>
|
||||
<docs-code path="..." />
|
||||
<docs-code path="..." />
|
||||
</docs-code-multifile>
|
||||
```
|
||||
|
||||
### Alerts / Admonitions
|
||||
|
||||
Use specific keywords followed by a colon for alerts. These render as styled blocks.
|
||||
|
||||
- `NOTE:` For ancillary information.
|
||||
- `TIP:` For helpful hints or shortcuts.
|
||||
- `IMPORTANT:` For crucial information.
|
||||
- `CRITICAL:` For warnings about potential data loss or severe issues.
|
||||
- `TODO`: For incomplete documentation.
|
||||
- `QUESTION:` To pose a question to the reader.
|
||||
- `SUMMARY:` For section summaries.
|
||||
- `TLDR:` For concise summaries.
|
||||
- `HELPFUL:` For best practices.
|
||||
|
||||
**Example:**
|
||||
|
||||
```markdown
|
||||
TIP: Use `ng serve` to run your application locally.
|
||||
```
|
||||
|
||||
### Custom Components
|
||||
|
||||
- **Cards (`<docs-card>`):**
|
||||
- Must be inside `<docs-card-container>`.
|
||||
- Attributes: `title`, `link`, `href`.
|
||||
- **Callouts (`<docs-callout>`):**
|
||||
- Attributes: `title`, `important`, `critical`.
|
||||
- **Pills (`<docs-pill>`):**
|
||||
- Must be inside `<docs-pill-row>`.
|
||||
- Attributes: `title`, `href`.
|
||||
- **Steps / Workflow (`<docs-step>`):**
|
||||
- Must be inside `<docs-workflow>`.
|
||||
- Attributes: `title`.
|
||||
- **Tabs (`<docs-tab>`):**
|
||||
- Must be inside `<docs-tab-group>`.
|
||||
- Attributes: `label`.
|
||||
- **Videos (`<docs-video>`):**
|
||||
- Attributes: `src` (YouTube embed URL), `alt`.
|
||||
|
||||
### Images
|
||||
|
||||
Use standard markdown syntax with optional attributes for sizing and loading behavior.
|
||||
|
||||
- `#small`, `#medium`: Append to image URL for sizing.
|
||||
- `{loading: 'lazy'}`: Add attribute for lazy loading.
|
||||
|
||||
**Example:**
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
### Headers
|
||||
|
||||
- Use markdown headers (`#`, `##`, `###`).
|
||||
- Ensure a logical hierarchy (don't skip levels).
|
||||
- `h2` and `h3` are most common for content structure.
|
||||
@@ -1,91 +0,0 @@
|
||||
---
|
||||
name: reference-compiler-cli
|
||||
description: Explains the mental model and architecture of the code under `packages/compiler-cli`. You MUST use this skill any time you plan to work with code in `packages/compiler-cli`
|
||||
---
|
||||
|
||||
# Angular Compiler CLI (`ngtsc`) Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
The `packages/compiler-cli` package contains the Angular Compiler (Ivy), often referred to as `ngtsc`. It is a wrapper around the TypeScript compiler (`tsc`) that extends it with Angular-specific capabilities.
|
||||
|
||||
The core goal of `ngtsc` is to compile Angular decorators (like `@Component`, `@Directive`, `@Pipe`) into static properties on the class (Ivy instructions, e.g., `static ɵcmp = ...`). It also performs template type checking and ahead-of-time (AOT) compilation.
|
||||
|
||||
## Mental Model
|
||||
|
||||
The compiler is designed as a **lazy, incremental, and partial** compilation pipeline.
|
||||
|
||||
1. **Wrapper Pattern**: `NgtscProgram` wraps the standard `ts.Program`. It intercepts calls to act as a drop-in replacement for standard tooling.
|
||||
2. **Traits System**: Every class with an Angular decorator is considered a "Trait". The compiler manages the state of these traits through a state machine:
|
||||
- **Pending**: Detected but not processed.
|
||||
- **Analyzed**: Metadata extracted, template parsed (but dependencies not yet linked).
|
||||
- **Resolved**: Dependencies (directives/pipes in template) resolved, import cycles handled.
|
||||
- **Skipped**: Not an Angular class.
|
||||
3. **Lazy Analysis**: Analysis only happens when necessary (e.g., when diagnostics are requested or emit is prepared).
|
||||
4. **Output AST**: The compiler generates an intermediate "Output AST" (`o.Expression`) for the generated code, which is then translated into TypeScript AST nodes during the emit phase.
|
||||
|
||||
## Key Subsystems
|
||||
|
||||
### 1. Core Orchestration (`ngtsc/core`)
|
||||
|
||||
- **`NgtscProgram`**: The public API implementing `api.Program`. It manages the `ts.Program` and the `NgCompiler`.
|
||||
- **`NgCompiler`**: The brain of the compiler. It orchestrates the compilation phases (Analysis, Resolution, Type Checking, Emit). It holds the `TraitCompiler`.
|
||||
|
||||
### 2. Trait Compilation (`ngtsc/transform`)
|
||||
|
||||
- **`TraitCompiler`**: Manages the lifecycle of "Traits". It iterates over source files, identifies decorated classes, and delegates to the appropriate `DecoratorHandler`.
|
||||
- **`Trait`**: A state container for a class, holding its handler, analysis results, and resolution results.
|
||||
|
||||
### 3. Decorator Handlers (`ngtsc/annotations`)
|
||||
|
||||
- **`DecoratorHandler`**: An interface for handling specific decorators.
|
||||
- **`ComponentDecoratorHandler`**: The most complex handler. It:
|
||||
- Extracts metadata (selector, inputs, outputs).
|
||||
- Parses the template.
|
||||
- Resolves used directives and pipes (`R3TargetBinder`).
|
||||
- Generates the `ɵcmp` instruction.
|
||||
- **`DirectiveDecoratorHandler`**, **`PipeDecoratorHandler`**, **`NgModuleDecoratorHandler`**: Handle their respective decorators.
|
||||
|
||||
### 4. Template Type Checking (`ngtsc/typecheck`)
|
||||
|
||||
- **`TemplateTypeChecker`**: Generates "Type Check Blocks" (TCBs). A TCB is a block of TypeScript code that represents the template's logic in a way `tsc` can understand and check for errors.
|
||||
- **`TypeCheckBlock`**: The actual generated code that validates bindings, events, and structural directives.
|
||||
|
||||
### 5. Metadata & Scope (`ngtsc/metadata`, `ngtsc/scope`)
|
||||
|
||||
- **`MetadataReader`**: Reads Angular metadata from source files (using `LocalMetadataRegistry`) and `.d.ts` files (using `DtsMetadataReader`).
|
||||
- **`ScopeRegistry`**: Determines the "compilation scope" of a component (which directives/pipes are available to it), handling `NgModule` transitive exports and Standalone Component imports.
|
||||
|
||||
### 6. Emit & Transformation (`ngtsc/transform`)
|
||||
|
||||
- **`ivyTransformFactory`**: A TypeScript transformer factory.
|
||||
- **`IvyCompilationVisitor`**: Visits classes, triggers compilation via `TraitCompiler`, and collects the Output AST.
|
||||
- **`IvyTransformationVisitor`**: Translates the Output AST into TypeScript AST, injects the `static ɵ...` fields, and removes the original decorators.
|
||||
|
||||
## Compilation Phases
|
||||
|
||||
1. **Construction**: `NgtscProgram` creates `NgCompiler`, which sets up all registries and the `TraitCompiler`.
|
||||
2. **Analysis** (`analyzeSync`):
|
||||
- The `TraitCompiler` scans files.
|
||||
- `DecoratorHandler`s extract metadata and parse templates.
|
||||
- No cross-file resolution happens here (allowing for parallelism and caching).
|
||||
3. **Resolution** (`resolve`):
|
||||
- `TraitCompiler` resolves traits.
|
||||
- Components link their templates to specific Directives and Pipes (found via `ScopeRegistry`).
|
||||
- Import cycles are detected and handled (e.g., via "remote scoping").
|
||||
4. **Type Checking**:
|
||||
- `TemplateTypeChecker` creates TCBs for all components.
|
||||
- TypeScript diagnostics are retrieved for these TCBs.
|
||||
5. **Emit** (`prepareEmit`):
|
||||
- `ivyTransformFactory` is created.
|
||||
- TS `emit` is called.
|
||||
- The transformers run, injecting the compiled Ivy instructions into the JS/DTS output.
|
||||
|
||||
## Important File Locations
|
||||
|
||||
- `packages/compiler-cli/src/ngtsc/program.ts`: Entry point (`NgtscProgram`).
|
||||
- `packages/compiler-cli/src/ngtsc/core/src/compiler.ts`: Core logic (`NgCompiler`).
|
||||
- `packages/compiler-cli/src/ngtsc/transform/src/trait.ts`: Trait state machine.
|
||||
- `packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts`: Component compilation logic.
|
||||
- `packages/compiler-cli/src/ngtsc/typecheck/src/template_type_checker.ts`: Type checking logic.
|
||||
- `packages/compiler-cli/src/ngtsc/transform/src/transform.ts`: AST transformation logic.
|
||||
@@ -1,96 +0,0 @@
|
||||
---
|
||||
name: reference-core
|
||||
description: Explains the mental model and architecture of the code under `packages/core`. You MUST use this skill any time you plan to work with code in `packages/core`
|
||||
---
|
||||
|
||||
# Angular Core (`packages/core`) Mental Model
|
||||
|
||||
This document outlines the architecture and mental model for `packages/core`, the heart of the Angular framework.
|
||||
|
||||
## 1. High-Level Architecture
|
||||
|
||||
`packages/core` contains the runtime logic for Angular. Its primary responsibilities are:
|
||||
|
||||
1. **Rendering (Ivy/Render3)**: Transforming templates into DOM updates.
|
||||
2. **Dependency Injection (DI)**: Managing object creation and lifetime.
|
||||
3. **Change Detection**: Synchronizing the model with the view.
|
||||
4. **Reactivity**: Signals and Zone.js integration.
|
||||
|
||||
## 2. Rendering Engine (Ivy / Render3)
|
||||
|
||||
The rendering engine (located in `packages/core/src/render3`) uses an **instruction-based** approach.
|
||||
|
||||
### Key Concepts
|
||||
|
||||
- **Instructions**: The Angular compiler transforms templates into a sequence of instruction calls (e.g., `ɵɵelementStart`, `ɵɵtext`, `ɵɵproperty`). These instructions are executed at runtime to create and update the view.
|
||||
- _Location_: `packages/core/src/render3/instructions`
|
||||
|
||||
- **LView (Logical View)**: An array containing the _state_ of a specific view instance. It holds:
|
||||
- DOM nodes (`RElement`, `RText`).
|
||||
- Binding values (for change detection).
|
||||
- Directive/Component instances.
|
||||
- _Context_: `packages/core/src/render3/interfaces/view.ts`
|
||||
|
||||
- **TView (Template View)**: An array containing the _static structure_ of a view. It is shared across all instances (`LView`s) of the same component/template. It holds:
|
||||
- Property names for bindings.
|
||||
- Node relationship information.
|
||||
- Compiled directive definitions.
|
||||
- _Context_: `packages/core/src/render3/interfaces/view.ts`
|
||||
|
||||
- **Memory Layout**: `LView` and `TView` are parallel arrays. Index `i` in `LView` corresponds to metadata at index `i` in `TView`.
|
||||
- `HEADER`: Fixed size, contains context (Parent, Host, etc.).
|
||||
- `DECLS`: Static nodes (elements, text, pipes).
|
||||
- `VARS`: Binding values.
|
||||
- `EXPANDO`: Dynamic data (host bindings, injectors).
|
||||
|
||||
### The Render Cycle
|
||||
|
||||
1. **Creation Mode**: Instructions create DOM nodes and store them in `LView`.
|
||||
2. **Update Mode**: Instructions check current values against previous values stored in `LView`. If changed, they update the DOM.
|
||||
|
||||
## 3. Dependency Injection (DI)
|
||||
|
||||
DI in Angular is hierarchical and split into two systems that interact:
|
||||
|
||||
### Module Injector (`R3Injector`)
|
||||
|
||||
- Configured via `@NgModule.providers` or `providedIn: 'root'`.
|
||||
- Stored in a hierarchy of `R3Injector` instances.
|
||||
- _Location_: `packages/core/src/di/r3_injector.ts`
|
||||
|
||||
### Node Injector
|
||||
|
||||
- Configured via `@Component.providers` or `@Directive.providers`.
|
||||
- **Not a class**, but a data structure embedded in the `LView` ("Expando" section).
|
||||
- Uses **Bloom Filters** (`TView.data`) to quickly check if a token is present at a specific node index before traversing up the tree.
|
||||
- Resolves tokens starting from the current node, walking up the view tree (Element Injector hierarchy), and falling back to the Module Injector if not found.
|
||||
|
||||
## 4. Change Detection
|
||||
|
||||
- **Dirty Checking**: Angular checks if values bound in templates have changed.
|
||||
- **Strategies**:
|
||||
- `Default`: Checks everything.
|
||||
- `OnPush`: Checks only if inputs change, events fire, or signals update.
|
||||
- **Signals**: The new reactivity primitive. Signals notify the scheduler when they change, potentially allowing for fine-grained updates (Zoneless).
|
||||
|
||||
## 5. Key Directories to Know
|
||||
|
||||
- `src/render3`: The Ivy rendering engine.
|
||||
- `instructions`: The runtime instructions called by compiled code.
|
||||
- `interfaces`: `LView`, `TView`, `TNode` definitions.
|
||||
- `src/di`: Dependency injection system.
|
||||
- `src/change_detection`: Change detection logic.
|
||||
- `src/zone`: Zone.js integration.
|
||||
- `src/signal`: Signals implementation (if present in this version, otherwise likely in `primitives`).
|
||||
|
||||
## 6. Conventions & Gotchas
|
||||
|
||||
- **Prefixes**: Private/Internal exports often start with `ɵ`.
|
||||
- **Global State**: Ivy relies heavily on global state (e.g., `getLView()`) during instruction execution to avoid passing context arguments everywhere. This is for performance and code size.
|
||||
- **Performance**: The code is highly optimized for performance and memory. You will see arrays used instead of objects, bitmasks, and manual memory management patterns. **Respect these patterns.**
|
||||
|
||||
## 7. How to Modify Core
|
||||
|
||||
1. **Understand the Instruction**: If modifying runtime behavior, find the corresponding instruction in `src/render3/instructions`.
|
||||
2. **Check `LView`/`TView` Impact**: If adding state, understand where it fits in the `LView` array.
|
||||
3. **Tests**: Core has extensive tests. Run them using Bazel.
|
||||
@@ -1,104 +0,0 @@
|
||||
---
|
||||
name: reference-signal-forms
|
||||
description: Explains the mental model and architecture of the code under `packages/forms/signals`. You MUST use this skill any time you plan to work with code in `packages/forms/signals`
|
||||
---
|
||||
|
||||
# Signal Forms Architecture
|
||||
|
||||
The `packages/forms/signals` directory contains an experimental, signal-based forms API for Angular.
|
||||
This system differs significantly from the existing Reactive and Template-driven forms.
|
||||
|
||||
## Mental Model
|
||||
|
||||
1. **Model-Driven**: The system is built around a `WritableSignal<T>` which serves as the **single source of truth**.
|
||||
Unlike Reactive Forms where the `FormControl` holds the value, here the `Signal` holds the value.
|
||||
The form is merely a _view_ or _projection_ of that signal, adding form-specific state (validity, dirty, touched).
|
||||
|
||||
2. **Proxy-Based Traversal**: The form API (`form(signal)`) returns a `FieldTree`. This object is a **Proxy**.
|
||||
It allows accessing nested fields (e.g., `myForm.user.name`) without manually creating control groups.
|
||||
Accessing a property on the proxy lazily resolves or creates the corresponding `FieldNode`.
|
||||
|
||||
3. **Schema-Based Logic**: Validation, disabled state, and other metadata are defined separately via **Schemas**.
|
||||
Schemas are applied to the form structure using functions like `apply`, `applyEach` (for arrays), and `applyWhen`.
|
||||
This separates the _structure_ of the data from the _rules_ governing it.
|
||||
|
||||
4. **Directives as Glue**: The `[formField]` directive binds a DOM element (native input or custom control) to a `FieldNode`.
|
||||
It handles:
|
||||
- Syncing the value between the DOM and the Signal.
|
||||
- Reflecting state (valid, touched, etc.) to the UI.
|
||||
- Handling user interaction events (blur, input).
|
||||
|
||||
## Key Components
|
||||
|
||||
### 1. `FieldNode` (`src/field/node.ts`)
|
||||
|
||||
The central internal class representing a single field in the form graph. It aggregates several state managers:
|
||||
|
||||
- `structure`: Manages parent/child relationships and signal slicing.
|
||||
- `validationState`: Computes `valid`, `invalid`, `errors` signals.
|
||||
- `nodeState`: Tracks `touched`, `dirty`, `pristine`.
|
||||
- `metadataState`: Stores metadata like `min`, `max`, `required`.
|
||||
- `submitState`: Tracks submission status and server errors.
|
||||
|
||||
### 2. `ValidationState` (`src/field/validation.ts`)
|
||||
|
||||
Manages the complexity of validation:
|
||||
|
||||
- **Synchronous Errors**: Derived from schema rules.
|
||||
- **Asynchronous Errors**: Handled via signals, including 'pending' states.
|
||||
- **Tree Errors**: Errors that bubble up or are targeted at specific fields.
|
||||
- **Submission Errors**: Server-side errors injected imperatively via `submit()`.
|
||||
|
||||
### 3. `FormField` Directive (`src/directive/form_field_directive.ts`)
|
||||
|
||||
The bridge between the `FieldNode` and the DOM.
|
||||
|
||||
- Selector: `[formField]`
|
||||
- It supports:
|
||||
- **Native Elements**: `<input>`, `<select>`, `<textarea>`.
|
||||
- **Custom Controls**: Components implementing `FormUiControl` or `FormValueControl`.
|
||||
- **Legacy Interop**: Components implementing `ControlValueAccessor` (via `InteropNgControl`).
|
||||
|
||||
### 4. `Schema` (`src/api/structure.ts` & `src/api/rules`)
|
||||
|
||||
Defines the behavior.
|
||||
|
||||
- Created via `schema(fn)`.
|
||||
- Applied via `apply(path, schema)`.
|
||||
- Rules include validators (`required`, `pattern`, `min`, `max`) and state modifiers (`disabled`, `hidden`).
|
||||
|
||||
## Data Flow
|
||||
|
||||
1. **Read**: `form.field.value()` reads directly from the underlying signal (projected to the specific path).
|
||||
2. **Write**: Writing to the form (e.g., via UI) updates the underlying signal.
|
||||
3. **Validation**: A computed effect observes the value signal and runs validators defined in the schema.
|
||||
|
||||
## Usage Example (Conceptual)
|
||||
|
||||
```typescript
|
||||
// 1. Define Model
|
||||
const user = signal({name: '', age: 0});
|
||||
|
||||
// 2. Define Schema
|
||||
const userRules = schema((u) => {
|
||||
required(u.name);
|
||||
min(u.age, 18);
|
||||
});
|
||||
|
||||
// 3. Create Form
|
||||
const userForm = form(user, userRules); // OR apply(userForm, userRules)
|
||||
|
||||
// 4. Bind in Template
|
||||
// <input [formField]="userForm.name">
|
||||
```
|
||||
|
||||
## Important Files
|
||||
|
||||
- `packages/forms/signals/src/api/structure.ts`: Public API entry points (`form`, `apply`).
|
||||
- `packages/forms/signals/src/api/control.ts`: Interfaces for custom controls (`FormUiControl`).
|
||||
- `packages/forms/signals/src/field/node.ts`: The `FieldNode` implementation.
|
||||
- `packages/forms/signals/src/directive/form_field_directive.ts`: The `[formField]` directive.
|
||||
|
||||
## Supplemental Information
|
||||
|
||||
- [Compiler & Core Integration](references/integration.md): Details how `[formField]` hooks into type-checking and the runtime.
|
||||
@@ -1,46 +0,0 @@
|
||||
# Signal Forms Integration: Compiler & Core
|
||||
|
||||
This document explains how the Signal Forms system hooks into the Angular compiler and runtime to provide seamless type-checking and efficient updates.
|
||||
|
||||
## 1. Compiler-CLI Integration (Type Checking)
|
||||
|
||||
The `packages/compiler-cli` package contains specific logic to support `[formField]`. This is primarily handled in `src/ngtsc/typecheck/src/ops/signal_forms.ts`.
|
||||
|
||||
### Key Mechanisms:
|
||||
|
||||
- **Detection**: The compiler identifies a directive as a "Field Directive" if it has the `ɵNgFieldDirective` property or comes from `@angular/forms/signals`.
|
||||
- **Synthetic Binding Expansion**: When you write `<input [formField]="mySignal" />`, the type checker doesn't just check `formField`. It synthetically expands this into a set of bindings for validation:
|
||||
- `[value]="mySignal()"` (or `checked` for checkboxes)
|
||||
- `[disabled]="mySignal.disabled()"`
|
||||
- `[required]="mySignal.required()"`
|
||||
- ...and so on.
|
||||
- This ensures that `mySignal` (the `FieldNode`) has all the necessary properties to drive the form control.
|
||||
- **Conflict Detection**: It actively prevents "double binding". If you bind `[formField]`, you are _banned_ from also binding `[value]`, `[disabled]`, `[required]`, etc., as the signal form should be the single source of truth.
|
||||
- **Element Type Validation**:
|
||||
- **Native Elements**: Checks that the signal's value type matches the element type (e.g., `<input type="checkbox">` requires a `boolean` signal).
|
||||
- **Custom Controls**: Detects if a custom component is a "Form Value Control" (has a `value` input/output) or "Form Checkbox Control" (has a `checked` input/output) and validates against that.
|
||||
|
||||
### Relevant Files:
|
||||
|
||||
- `packages/compiler-cli/src/ngtsc/typecheck/src/ops/signal_forms.ts`: The core logic for `TcbNativeFieldOp` and `SignalFormFieldOp`.
|
||||
|
||||
## 2. Core Runtime Integration
|
||||
|
||||
The `packages/core` package provides the low-level instructions that power the `FormField` directive. This allows it to do things normal directives cannot, like efficiently syncing state without change detection overhead for every property.
|
||||
|
||||
### Key Mechanisms:
|
||||
|
||||
- **`ɵngControlCreate` Hook**: The `FormField` directive defines a special method `ɵngControlCreate`.
|
||||
- **`ɵɵcontrol` Instructions**: When the compiler sees `ɵngControlCreate`, it emits:
|
||||
- `ɵɵcontrolCreate`: Called during the creation phase.
|
||||
- `ɵɵcontrol`: Called during the update phase.
|
||||
- **`ControlDirectiveHost`**: These instructions provide the directive with a `ControlDirectiveHost`. This is a privileged interface that allows the `FormField` directive to:
|
||||
- **Access the Element**: Get direct access to the native element or component instance.
|
||||
- **Set Inputs**: Write directly to inputs of _other directives_ on the same node (e.g., setting the `value` input of a custom control).
|
||||
- **Listen to Outputs**: Subscribe to outputs of other directives (e.g., `valueChange`).
|
||||
- **Bypass Templates**: It effectively acts as a "meta-directive" that manages the bindings for you, bypassing the need for explicit template syntax for every property.
|
||||
|
||||
### Relevant Files:
|
||||
|
||||
- `packages/core/src/render3/instructions/control.ts`: Implementation of `ɵɵcontrol` instructions.
|
||||
- `packages/forms/signals/src/directive/form_field_directive.ts`: The directive that implements the hook.
|
||||
+22979
-20338
File diff suppressed because one or more lines are too long
@@ -5,9 +5,9 @@ runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/saucelabs@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Starting Saucelabs tunnel service
|
||||
shell: bash
|
||||
run: ./tools/saucelabs/sauce-service.sh run &
|
||||
|
||||
@@ -21,17 +21,17 @@ jobs:
|
||||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'adev: preview'))
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Build adev
|
||||
# `snapshot-build` config is used to stamp the exact version with sha in the footer.
|
||||
run: pnpm bazel build //adev:build.production --config=snapshot-build
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
pull-number: '${{github.event.pull_request.number}}'
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
with:
|
||||
token: '${{secrets.GITHUB_TOKEN}}'
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
npx -y firebase-tools@latest target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs
|
||||
npx -y firebase-tools@latest target:apply --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs ${{env.PREVIEW_SITE}}
|
||||
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
github-token: '${{secrets.GITHUB_TOKEN}}'
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
|
||||
@@ -17,6 +17,6 @@ jobs:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
|
||||
+26
-28
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Check code lint
|
||||
@@ -32,8 +32,6 @@ jobs:
|
||||
run: pnpm ng-dev pullapprove verify
|
||||
- name: Validate angular robot configuration
|
||||
run: pnpm ng-dev ngbot verify
|
||||
- name: Validate agent skills
|
||||
run: pnpm ng-dev ai skills validate
|
||||
- name: Confirm code builds with typescript as expected
|
||||
run: pnpm check-tooling-setup
|
||||
|
||||
@@ -41,13 +39,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
disable-package-manager-cache: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -57,7 +55,7 @@ jobs:
|
||||
- name: Test build
|
||||
run: pnpm devtools:build:chrome
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@bc22e01685c56e89e7813fd8e26f33dc47f87e15 # v7.1.5
|
||||
uses: cypress-io/github-action@f790eee7a50d9505912f50c2095510be7de06aa7 # v6.10.9
|
||||
with:
|
||||
command: pnpm devtools:test:e2e
|
||||
start: pnpm bazel run //devtools/src:devserver
|
||||
@@ -69,11 +67,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -85,11 +83,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -102,11 +100,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -121,11 +119,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -138,11 +136,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
|
||||
@@ -154,11 +152,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
|
||||
- name: Install node modules
|
||||
@@ -208,11 +206,11 @@ jobs:
|
||||
runs-on: ubuntu-latest-8core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Build adev
|
||||
|
||||
@@ -3,36 +3,23 @@ name: DevInfra
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
issues:
|
||||
types: [opened, reopened]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
pull_request_labels:
|
||||
if: github.event_name == 'pull_request_target'
|
||||
labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: angular/dev-infra/github-actions/labeling/pull-request@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- uses: angular/dev-infra/github-actions/pull-request-labeling@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
labels: '{"requires: TGP": ["packages/core/primitives/**/{*,.*}"]}'
|
||||
post_approval_changes:
|
||||
if: github.event_name == 'pull_request_target'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
issue_labels:
|
||||
if: github.event_name == 'issues'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/labeling/issue@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
google-generative-ai-key: ${{ secrets.GOOGLE_GENERATIVE_AI_KEY }}
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
run-tests-guide-url: http://go/angular-g3sync-start
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -13,15 +13,15 @@ jobs:
|
||||
JOBS: 2
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/saucelabs@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Set up Sauce Tunnel Daemon
|
||||
run: pnpm bazel run //tools/saucelabs-daemon/background-service -- $JOBS &
|
||||
env:
|
||||
|
||||
@@ -9,6 +9,6 @@ jobs:
|
||||
status:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
workflows: ${{ steps.workflows.outputs.workflows }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- id: workflows
|
||||
@@ -36,9 +36,9 @@ jobs:
|
||||
workflow: ${{ fromJSON(needs.list.outputs.workflows) }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
# We utilize the google-github-actions/auth action to allow us to get an active credential using workflow
|
||||
|
||||
+21
-23
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Check code lint
|
||||
@@ -32,14 +32,12 @@ jobs:
|
||||
run: pnpm ng-dev ngbot verify
|
||||
- name: Confirm code builds with typescript as expected
|
||||
run: pnpm check-tooling-setup
|
||||
- name: Validate agent skills
|
||||
run: pnpm ng-dev ai skills validate
|
||||
- name: Check commit message
|
||||
run: pnpm ng-dev commit-message validate-range ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
|
||||
- name: Check code format
|
||||
run: pnpm ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
|
||||
- name: Check Package Licenses
|
||||
uses: angular/dev-infra/github-actions/linting/licenses@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/linting/licenses@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
allow-dependencies-licenses: 'pkg:npm/google-protobuf@'
|
||||
|
||||
@@ -47,13 +45,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
with:
|
||||
disable-package-manager-cache: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
@@ -61,7 +59,7 @@ jobs:
|
||||
- name: Test build
|
||||
run: pnpm devtools:build:chrome
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@bc22e01685c56e89e7813fd8e26f33dc47f87e15 # v7.1.5
|
||||
uses: cypress-io/github-action@f790eee7a50d9505912f50c2095510be7de06aa7 # v6.10.9
|
||||
with:
|
||||
command: pnpm devtools:test:e2e
|
||||
start: pnpm bazel run //devtools/src:devserver
|
||||
@@ -73,11 +71,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run CI tests for framework
|
||||
@@ -97,11 +95,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run integration CI tests for framework
|
||||
@@ -112,11 +110,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run tests
|
||||
@@ -129,11 +127,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Run tests
|
||||
@@ -144,11 +142,11 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@e4dcda13e469f50a6bd92667e2ded8b98173bf2c
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@3bec1182014f8cd3201bfc7d2bc6121658b9e0cd
|
||||
- name: Install node modules
|
||||
run: pnpm install --frozen-lockfile
|
||||
- run: |
|
||||
|
||||
@@ -47,6 +47,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: 'Upload to code-scanning'
|
||||
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
|
||||
uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@ export const github = {
|
||||
name: 'angular',
|
||||
mainBranchName: 'main',
|
||||
mergeMode: 'caretaker-only',
|
||||
requireReleaseModeForRelease: false,
|
||||
requireReleaseModeForRelease: true,
|
||||
};
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
"packages/docs/**",
|
||||
"packages/elements/schematics/**",
|
||||
"packages/examples/**",
|
||||
"packages/forms/signals/src/api/rules/validation/standard_schema.ts",
|
||||
"packages/localize/**",
|
||||
"packages/private/**",
|
||||
"packages/service-worker/**",
|
||||
|
||||
+1
-7
@@ -30,16 +30,10 @@ vscode-ng-language-service/syntaxes/test/data/*.html
|
||||
# Ignore goldens MD files
|
||||
goldens/**/*.api.md
|
||||
|
||||
# Ignore golden symbol json files
|
||||
packages/**/*.golden_symbols.json
|
||||
|
||||
# adev generated files
|
||||
adev/src/content/aria/**/*.json
|
||||
adev/src/content/cli/**/*.json
|
||||
adev/src/content/cdk/**/*.json
|
||||
|
||||
# Antigravity rules
|
||||
.agent/rules/agents.md
|
||||
|
||||
CHANGELOG.md
|
||||
CHANGELOG_ARCHIVE.md
|
||||
CHANGELOG_ARCHIVE.md
|
||||
+23
-28
@@ -106,6 +106,7 @@ groups:
|
||||
- thePunderWoman
|
||||
- kirjs
|
||||
- JoostK
|
||||
- mmalerba
|
||||
- ~amishne
|
||||
- ~leonsenft
|
||||
- ~mattrbeck
|
||||
@@ -150,8 +151,10 @@ groups:
|
||||
- crisbeto
|
||||
- devversion
|
||||
- kirjs
|
||||
- ~jelbourn
|
||||
- thePunderWoman
|
||||
- ~pkozlowski-opensource
|
||||
- mmalerba
|
||||
- JeanMeche
|
||||
- ~amishne
|
||||
- ~leonsenft
|
||||
@@ -178,9 +181,9 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~alxhub
|
||||
- jelbourn
|
||||
- josephperrott
|
||||
- ~pkozlowski-opensource
|
||||
- alan-agius4
|
||||
reviews:
|
||||
request: -1 # request reviews from everyone
|
||||
required: 2 # require at least 2 approvals
|
||||
@@ -199,6 +202,7 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- ~JiaLiPassion
|
||||
- ~jelbourn
|
||||
- ~alxhub
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
@@ -207,6 +211,7 @@ groups:
|
||||
- kirjs
|
||||
- thePunderWoman
|
||||
- ~pkozlowski-opensource
|
||||
- mmalerba
|
||||
- ~amishne
|
||||
- ~leonsenft
|
||||
- ~mattrbeck
|
||||
@@ -243,8 +248,6 @@ groups:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'adev/**/{*,.*}',
|
||||
'tools/manual_api_docs/blocks/*.md',
|
||||
'tools/manual_api_docs/elements/*.md',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -256,12 +259,14 @@ groups:
|
||||
- crisbeto
|
||||
- kirjs
|
||||
- JeanMeche
|
||||
- jelbourn
|
||||
- thePunderWoman
|
||||
- devversion
|
||||
- josephperrott
|
||||
- ~pkozlowski-opensource
|
||||
- ~mgechev
|
||||
- MarkTechson
|
||||
- mmalerba
|
||||
- ~hawkgs
|
||||
- ~amishne
|
||||
- ~leonsenft
|
||||
@@ -297,13 +302,8 @@ groups:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files
|
||||
.exclude('.pullapprove.yml')
|
||||
.exclude('tools/manual_api_docs/blocks/*.md')
|
||||
.exclude('tools/manual_api_docs/elements/*.md'),
|
||||
[
|
||||
contains_any_globs(files.exclude('.pullapprove.yml'), [
|
||||
'{*,.*}',
|
||||
'.agent/**/{*,.*}',
|
||||
'.devcontainer/**/{*,.*}',
|
||||
'.github/**/{*,.*}',
|
||||
'.husky/**/{*,.*}',
|
||||
@@ -340,7 +340,6 @@ groups:
|
||||
- author not in ["angular-robot"]
|
||||
reviewers:
|
||||
users:
|
||||
- alan-agius4
|
||||
- devversion
|
||||
- josephperrott
|
||||
|
||||
@@ -375,9 +374,11 @@ groups:
|
||||
- AndrewKushnir
|
||||
- ~alxhub
|
||||
- atscott
|
||||
- ~jelbourn
|
||||
- thePunderWoman
|
||||
- ~pkozlowski-opensource
|
||||
- kirjs
|
||||
- mmalerba
|
||||
- crisbeto
|
||||
- devversion
|
||||
- JeanMeche
|
||||
@@ -411,8 +412,10 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- kirjs
|
||||
- ~jelbourn
|
||||
- thePunderWoman
|
||||
- ~pkozlowski-opensource
|
||||
- mmalerba
|
||||
- ~amishne
|
||||
- ~leonsenft
|
||||
- ~mattrbeck
|
||||
@@ -421,24 +424,6 @@ groups:
|
||||
required: 1 # Require that 1 person approve
|
||||
reviewed_for: required
|
||||
|
||||
# =========================================================
|
||||
# Agent Skills
|
||||
# =========================================================
|
||||
agent-skills:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'skills/{*,.*}',
|
||||
'skills/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- marktechson
|
||||
- kirjs
|
||||
- ~JeanMeche
|
||||
- ~dgp1130
|
||||
|
||||
####################################################################################
|
||||
# Special Cases
|
||||
####################################################################################
|
||||
@@ -459,6 +444,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- andrewseguin
|
||||
- dgp1130
|
||||
- ~jelbourn
|
||||
- thePunderWoman
|
||||
- josephperrott
|
||||
|
||||
@@ -481,6 +467,10 @@ groups:
|
||||
- thePunderWoman # Jessica Janiuk
|
||||
- AndrewKushnir # Andrew Kushnir
|
||||
- atscott # Andrew Scott
|
||||
labels:
|
||||
pending: 'requires: TGP'
|
||||
approved: 'requires: TGP'
|
||||
rejected: 'requires: TGP'
|
||||
|
||||
# External team required reviews
|
||||
primitives-shared:
|
||||
@@ -498,6 +488,10 @@ groups:
|
||||
- tbondwilkinson # Tom Wilkinson
|
||||
- rahatarmanahmed # Rahat Ahmed
|
||||
- ENAML # Ethan Cline
|
||||
labels:
|
||||
pending: 'requires: TGP'
|
||||
approved: 'requires: TGP'
|
||||
rejected: 'requires: TGP'
|
||||
|
||||
####################################################################################
|
||||
# Override managed result groups
|
||||
@@ -520,6 +514,7 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- alxhub
|
||||
- jelbourn
|
||||
- josephperrott
|
||||
reviews:
|
||||
request: 0
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
---
|
||||
trigger: always_on
|
||||
---
|
||||
|
||||
This is the source code for the Angular framework. This guide outlines standard practices for AI agents working in this repository.
|
||||
|
||||
## Environment
|
||||
|
||||
- Use `pnpm` for package management.
|
||||
- Use `pnpm bazel test //target` to run tests.
|
||||
- Use `pnpm bazel test //target` to run tests. Do not use `ng test`, or just `bazel`
|
||||
|
||||
## Key Documentation
|
||||
|
||||
@@ -15,20 +11,7 @@ This is the source code for the Angular framework. This guide outlines standard
|
||||
- [Coding Standards](contributing-docs/coding-standards.md): style guide for TypeScript and other files.
|
||||
- [Commit Guidelines](contributing-docs/commit-message-guidelines.md): format for commit messages and PR titles.
|
||||
|
||||
## Testing
|
||||
|
||||
- **Zoneless & Async-First:** Assume a zoneless environment where state changes schedule updates asynchronously.
|
||||
- **Do NOT** use `fixture.detectChanges()` to manually trigger updates.
|
||||
- **ALWAYS** use the "Act, Wait, Assert" pattern:
|
||||
1. **Act:** Update state or perform an action.
|
||||
2. **Wait:** `await fixture.whenStable()` to allow the framework to process the scheduled update.
|
||||
3. **Assert:** Verify the output.
|
||||
- To keep tests fast, minimize the need for waiting:
|
||||
- Use `useAutoTick()` (from `packages/private/testing/src/utils.ts`) to fast-forward time via the mock clock.
|
||||
- When waiting is necessary, use real async tests (`it('...', async () => { ... })`) along with:
|
||||
- `await timeout(ms)` (from `packages/private/testing/src/utils.ts`) to wait a specific number of milliseconds.
|
||||
- `await fixture.whenStable()` to wait for framework stability.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
- Use the `gh` CLI (GitHub CLI) for creating and managing pull requests.
|
||||
- Avoid using browser tools for PR operations when possible to maintain workflow efficiency.
|
||||
|
||||
-162
@@ -1,151 +1,3 @@
|
||||
<a name="21.2.3"></a>
|
||||
# 21.2.3 (2026-03-11)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [62a97f7e4b](https://github.com/angular/angular/commit/62a97f7e4b896b4b03a1ef25764db387ffecebe1) | fix | ensure definitions compile |
|
||||
| [21b1c3b2ee](https://github.com/angular/angular/commit/21b1c3b2ee2c8423782b111b93bd60eb6b453259) | fix | include signal debug names in their `toString()` representation |
|
||||
| [224e60ecb1](https://github.com/angular/angular/commit/224e60ecb1b90115baa702f1c06edc1d64d86187) | fix | sanitize translated attribute bindings with interpolations |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.2"></a>
|
||||
# 21.2.2 (2026-03-09)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [1df1697c6e](https://github.com/angular/angular/commit/1df1697c6e3a6b1d302f7692b495146943faa12f) | fix | prevent mutation of children array in RecursiveVisitor |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c822bf8e76](https://github.com/angular/angular/commit/c822bf8e76611afde332b6625f5e7bae2fe9c3f3) | fix | always parenthesize object literals in TCB |
|
||||
| [05d022d5e6](https://github.com/angular/angular/commit/05d022d5e61cca7ac90d5b2b2ba3fc738b364ad9) | fix | ignore generated ngDevMode signal branch for code coverage |
|
||||
### forms
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [670d1660c4](https://github.com/angular/angular/commit/670d1660c40504e3f55e094c3ebbcccad14163f3) | feat | add 'blur' option to debounce rule |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.1"></a>
|
||||
# 21.2.1 (2026-03-04)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e2e9a9a531](https://github.com/angular/angular/commit/e2e9a9a531c9e9a69701e549f28354cc5d5edd77) | fix | adds transfer cache to httpResource to fix hydration |
|
||||
| [b4ec3cc4e4](https://github.com/angular/angular/commit/b4ec3cc4e41f2948ad0830eb14aa05d14fa3a9ed) | fix | prevent child animation elements from being orphaned |
|
||||
| [e923d88398](https://github.com/angular/angular/commit/e923d8839868c79989502ab3503e13d93c78516a) | fix | Prevent removal of elements during drag and drop |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [277ade97ac](https://github.com/angular/angular/commit/277ade97ac2a3a7f2a5b513acaa93e7663cdc55f) | fix | correctly cache blob responses in transfer cache ([#67002](https://github.com/angular/angular/pull/67002)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.2.0"></a>
|
||||
# 21.2.0 (2026-02-25)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [18003a33bb](https://github.com/angular/angular/commit/18003a33bb0d6bb09def8a0e5939fa24069696eb) | feat | add an 'outlet' injector option for ngTemplateOutlet |
|
||||
| [8bbe6dc46c](https://github.com/angular/angular/commit/8bbe6dc46c9dc13bafa81a60c7613b84b5ca3761) | feat | Add Location strategies to manage trailing slash on write |
|
||||
| [51cc914807](https://github.com/angular/angular/commit/51cc91480761b7275c15b5600381207f8ca00ee5) | feat | support height in ImageLoaderConfig and built-in loaders |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [72534e2a34](https://github.com/angular/angular/commit/72534e2a3458df4e1bb097973872f00bbb92be42) | feat | Add support for the `instanceof` binary operator |
|
||||
| [95b3f37d4a](https://github.com/angular/angular/commit/95b3f37d4a7d9a38f616d56df746dfcda3c2139b) | feat | Exhaustive checks for switch blocks |
|
||||
| [04ba09a8d9](https://github.com/angular/angular/commit/04ba09a8d9454013bebdd643eacb737642161952) | feat | support `AstVisitor.visitEmptyExpr()` |
|
||||
| [ce80136e7b](https://github.com/angular/angular/commit/ce80136e7b9f0024d49fce835cffa024c4505855) | fix | optimize away unnecessary restore/reset view calls |
|
||||
| [3242a61bae](https://github.com/angular/angular/commit/3242a61bae02253d13abb510b666376c665e61ac) | fix | variable counter visiting some expressions twice |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [473dd3e1cb](https://github.com/angular/angular/commit/473dd3e1cbd4fe3fa88ae4d5358eee35c11acb1b) | fix | attach source spans to object literal keys in TCB |
|
||||
| [a904d9f77b](https://github.com/angular/angular/commit/a904d9f77b56feab407f75f8d0527fa512d5dafb) | fix | support nested component declaration |
|
||||
| [2ea6dfc6c9](https://github.com/angular/angular/commit/2ea6dfc6c9ca11e96a2654510c980419899f8d04) | fix | update diagnostic to flag no-op arrow functions in listeners |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8d5210c9fe](https://github.com/angular/angular/commit/8d5210c9fedd8abdd810d7a89ec7ee9a1234f5c1) | feat | add ChangeDetectionStrategy.Eager alias for Default |
|
||||
| [92d2498910](https://github.com/angular/angular/commit/92d2498910caed06c182b67e39726e1441418698) | feat | add host node to DeferBlockData ([#66546](https://github.com/angular/angular/pull/66546)) |
|
||||
| [ea2016a6dc](https://github.com/angular/angular/commit/ea2016a6dce58f95ecab7c773d5dcde274354e1a) | feat | add support for nested animations |
|
||||
| [81cabc1477](https://github.com/angular/angular/commit/81cabc14777a3b4966c29d60e1505aca8c29b71c) | feat | add support for TypeScript 6 |
|
||||
| [1ba9b7ac50](https://github.com/angular/angular/commit/1ba9b7ac5001b315cc9df78c518964dbf479d647) | feat | resource composition via snapshots |
|
||||
| [d9923b72a2](https://github.com/angular/angular/commit/d9923b72a20972ba6bf728d78f1afac6936ade18) | feat | support arrow functions in expressions |
|
||||
| [a7e8abbb7e](https://github.com/angular/angular/commit/a7e8abbb7e738ba338c3f50c76934c99925954e5) | fix | correctly handle SkipSelf when resolving from embedded view injector |
|
||||
| [0806ee3826](https://github.com/angular/angular/commit/0806ee38269b664f535e10d4d501b88370d3b44c) | fix | prevent animated element duplication with dynamic components in zoneless mode |
|
||||
| [ed78fa05c7](https://github.com/angular/angular/commit/ed78fa05c710ebafb355ae00a85b190a118b6cc4) | fix | Remove note to skip arrow functions in best practices |
|
||||
### forms
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [f56bb07d83](https://github.com/angular/angular/commit/f56bb07d83a015b0ac12e74fdb0cf1550ff36b97) | feat | add field param to submit action and onInvalid |
|
||||
| [ba009b6031](https://github.com/angular/angular/commit/ba009b603119299a03f9d844f93882d42d47d150) | feat | add form directive |
|
||||
| [22afbb2f36](https://github.com/angular/angular/commit/22afbb2f36be89c2ae575df343571a918dec5985) | feat | add parsing support to native inputs ([#66917](https://github.com/angular/angular/pull/66917)) |
|
||||
| [95c386469c](https://github.com/angular/angular/commit/95c386469c7a2f09dd731601c2061bdb10d25717) | feat | Add passing focus options to form field |
|
||||
| [95ecce8334](https://github.com/angular/angular/commit/95ecce8334299defe55fb2b74264e5258ffd137c) | feat | allow setting submit options at form-level |
|
||||
| [ebae211add](https://github.com/angular/angular/commit/ebae211add37700858adeb8fc5d87bf503a59721) | feat | introduce parse errors in signal forms |
|
||||
| [3937afc316](https://github.com/angular/angular/commit/3937afc3167ce409eebb06d91d5fb122eea4e33d) | feat | introduce SignalFormControl for Reactive Forms compatibility |
|
||||
| [30f0914754](https://github.com/angular/angular/commit/30f09147545b67185f93efb9796e37c1db76733a) | feat | support binding null to number input ([#66917](https://github.com/angular/angular/pull/66917)) |
|
||||
| [dd208ca259](https://github.com/angular/angular/commit/dd208ca2595258fcd1e289374f812ce0b56c7011) | feat | update submit function to accept options object |
|
||||
| [27397b3f4f](https://github.com/angular/angular/commit/27397b3f4f3182ce00d6e2f8690285c316e2a274) | fix | clear parse errors when model updates ([#66917](https://github.com/angular/angular/pull/66917)) |
|
||||
| [63d8005703](https://github.com/angular/angular/commit/63d80057039928b3e878b59c1fe6b93ef1c6b701) | fix | preserve custom-control focus context in signal forms |
|
||||
| [631f60d1f9](https://github.com/angular/angular/commit/631f60d1f9be72cb68330308a6ff18cc195babb8) | fix | preserve parse errors when parse returns value |
|
||||
| [adfb83146b](https://github.com/angular/angular/commit/adfb83146b0c149734f43961563b389e00cc1d85) | fix | simplify design of parse errors |
|
||||
| [fb05fc86d0](https://github.com/angular/angular/commit/fb05fc86d0f12ffafd94c7c1420118d8a79f7e59) | fix | sort error summary by DOM order |
|
||||
| [567f292e8e](https://github.com/angular/angular/commit/567f292e8e0f9d2b5ddebadfa1c6d6dd6c456f39) | fix | support custom controls as host directives |
|
||||
| [bdfb60f3e3](https://github.com/angular/angular/commit/bdfb60f3e33065e047183dc1890c36e527e2b304) | fix | use consistent error format returned from parse |
|
||||
| [d75046bc09](https://github.com/angular/angular/commit/d75046bc091699bbadcb5f2032be627e983ee6fa) | fix | warn when showing hidden field state |
|
||||
### language-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [ebc90c26f5](https://github.com/angular/angular/commit/ebc90c26f5ff1ba1e0ca9b775a44e301ebfb9473) | feat | Add completions and hover info for inline styles |
|
||||
| [26fd0839c3](https://github.com/angular/angular/commit/26fd0839c32d2ebeaa5e3ecc10ed70ab9ca17749) | feat | Add folding range support for inline styles |
|
||||
| [573aadef7e](https://github.com/angular/angular/commit/573aadef7eb8b6b5e83b82a16f95d2a556f27c01) | feat | Add quick info for inline styles |
|
||||
| [6fb39d9b62](https://github.com/angular/angular/commit/6fb39d9b62cbb634e95ec00fe5ef85d84da3bdbd) | feat | Support client-side file watching via `onDidChangeWatchedFiles` |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [496967e7b1](https://github.com/angular/angular/commit/496967e7b13dfe1ebdde69724cd62880914beb60) | feat | add JSON schema for angularCompilerOptions |
|
||||
| [8c21866f49](https://github.com/angular/angular/commit/8c21866f49ff74344551395ae0a5df1841d54c0d) | feat | add linked editing ranges for HTML tag synchronization |
|
||||
| [d2137928e8](https://github.com/angular/angular/commit/d2137928e8f075527016a3c011dd8efc4d4e1ebd) | perf | use lightweight project warmup for Angular analysis |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b51bab583d](https://github.com/angular/angular/commit/b51bab583d84e38f16dea489e4119edc34e2a491) | feat | Add partial ActivatedRouteSnapshot information to `canMatch` params |
|
||||
| [cf9620f7d0](https://github.com/angular/angular/commit/cf9620f7d072897f13b7f281b7bca6f51f69cfd0) | feat | Make match options optional in isActive |
|
||||
| [907a94dcec](https://github.com/angular/angular/commit/907a94dcec2926a5c7d0c4d36249bd62e31a2ae3) | feat | Update `IsActiveMatchOptions` APIs to accept a Partial |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.1.5"></a>
|
||||
# 21.1.5 (2026-02-18)
|
||||
No user facing changes in this release
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.1.4"></a>
|
||||
# 21.1.4 (2026-02-11)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [caab23dfe6](https://github.com/angular/angular/commit/caab23dfe6acf06c3b859af091f5e078b08f1c4c) | fix | add geolocation element to schema |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [2b99eaa019](https://github.com/angular/angular/commit/2b99eaa019b5551a2e2fcf9ff8cd0a796e1e857b) | fix | capture animation dependencies eagerly to avoid destroyed injector |
|
||||
| [d6aeac504c](https://github.com/angular/angular/commit/d6aeac504c6181f15e5d8afdca3d9c3e3b32652c) | fix | Fix flakey test due to document injection |
|
||||
### forms
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0d1acd0165](https://github.com/angular/angular/commit/0d1acd0165511b57ce853f29486d9b92d0215959) | feat | support signal-based schemas in validateStandardSchema |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [3905015ccc](https://github.com/angular/angular/commit/3905015ccc53399a606dd8e4f3c4d0cce628a08e) | fix | correctly parse ArrayBuffer and Blob in transfer cache |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.1.3"></a>
|
||||
# 21.1.3 (2026-02-04)
|
||||
### core
|
||||
@@ -256,20 +108,6 @@ No user facing changes in this release
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.0.9"></a>
|
||||
# 21.0.9 (2026-01-14)
|
||||
### forms
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [82d556a8fb](https://github.com/angular/angular/commit/82d556a8fb38cd2024e3d098c55254305ba12b6b) | fix | Ensure the control instruction comes after the other bindings |
|
||||
| [0055f3cc79](https://github.com/angular/angular/commit/0055f3cc79f387b8dec6ce5e1a33fad5486f9341) | fix | Rename signal form [field] to [formField] |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e4bfa5c9e7](https://github.com/angular/angular/commit/e4bfa5c9e7feec48d3c4e9425a21a2ccf6532bdb) | fix | prevent duplicate imports in common-to-standalone migration |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="21.0.8"></a>
|
||||
# 21.0.8 (2026-01-08)
|
||||
### core
|
||||
|
||||
+21
-20
@@ -6,26 +6,26 @@ module(
|
||||
|
||||
bazel_dep(name = "rules_pkg", version = "1.2.0")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.7.3")
|
||||
bazel_dep(name = "aspect_rules_ts", version = "3.8.5")
|
||||
bazel_dep(name = "aspect_rules_ts", version = "3.8.3")
|
||||
bazel_dep(name = "aspect_rules_js", version = "2.9.2")
|
||||
bazel_dep(name = "aspect_rules_esbuild", version = "0.25.0")
|
||||
bazel_dep(name = "aspect_rules_jasmine", version = "2.0.4")
|
||||
bazel_dep(name = "aspect_rules_jasmine", version = "2.0.2")
|
||||
bazel_dep(name = "aspect_rules_rollup", version = "2.0.1")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.9.0")
|
||||
bazel_dep(name = "aspect_bazel_lib", version = "2.22.5")
|
||||
bazel_dep(name = "tar.bzl", version = "0.9.0")
|
||||
bazel_dep(name = "yq.bzl", version = "0.3.5")
|
||||
bazel_dep(name = "tar.bzl", version = "0.8.1")
|
||||
bazel_dep(name = "yq.bzl", version = "0.3.4")
|
||||
bazel_dep(name = "rules_angular")
|
||||
git_override(
|
||||
module_name = "rules_angular",
|
||||
commit = "d746c4f75e42cffe389d1ab077f4639be2bc78d1",
|
||||
remote = "https://github.com/angular/rules_angular.git",
|
||||
commit = "e975faa54a52caa45ff932ec806292ce0988d8d4",
|
||||
remote = "https://github.com/devversion/rules_angular.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "devinfra")
|
||||
git_override(
|
||||
module_name = "devinfra",
|
||||
commit = "e4dcda13e469f50a6bd92667e2ded8b98173bf2c",
|
||||
commit = "3bec1182014f8cd3201bfc7d2bc6121658b9e0cd",
|
||||
remote = "https://github.com/angular/dev-infra.git",
|
||||
)
|
||||
|
||||
@@ -33,14 +33,14 @@ bazel_dep(name = "rules_sass")
|
||||
git_override(
|
||||
module_name = "rules_sass",
|
||||
commit = "1184a80751a21af8348f308abc5b38a41f26850e",
|
||||
remote = "https://github.com/angular/rules_sass.git",
|
||||
remote = "https://github.com/devversion/rules_sass.git",
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_browsers")
|
||||
git_override(
|
||||
module_name = "rules_browsers",
|
||||
commit = "8231142fc5516323b040883bf774ba8362645387",
|
||||
remote = "https://github.com/angular/rules_browsers.git",
|
||||
commit = "5f0e50d17d15c70e6ab5546f1659338ae94c4072",
|
||||
remote = "https://github.com/devversion/rules_browsers.git",
|
||||
)
|
||||
|
||||
yq = use_extension("@yq.bzl//yq:extensions.bzl", "yq")
|
||||
@@ -49,15 +49,15 @@ use_repo(yq, "yq_toolchains")
|
||||
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
|
||||
node.toolchain(
|
||||
node_repositories = {
|
||||
"22.22.1-darwin_arm64": ("node-v22.22.1-darwin-arm64.tar.gz", "node-v22.22.1-darwin-arm64", "679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"),
|
||||
"22.22.1-darwin_amd64": ("node-v22.22.1-darwin-x64.tar.gz", "node-v22.22.1-darwin-x64", "07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"),
|
||||
"22.22.1-linux_arm64": ("node-v22.22.1-linux-arm64.tar.xz", "node-v22.22.1-linux-arm64", "0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"),
|
||||
"22.22.1-linux_ppc64le": ("node-v22.22.1-linux-ppc64le.tar.xz", "node-v22.22.1-linux-ppc64le", "a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"),
|
||||
"22.22.1-linux_s390x": ("node-v22.22.1-linux-s390x.tar.xz", "node-v22.22.1-linux-s390x", "e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"),
|
||||
"22.22.1-linux_amd64": ("node-v22.22.1-linux-x64.tar.xz", "node-v22.22.1-linux-x64", "9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"),
|
||||
"22.22.1-windows_amd64": ("node-v22.22.1-win-x64.zip", "node-v22.22.1-win-x64", "877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"),
|
||||
"22.22.0-darwin_arm64": ("node-v22.22.0-darwin-arm64.tar.gz", "node-v22.22.0-darwin-arm64", "5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"),
|
||||
"22.22.0-darwin_amd64": ("node-v22.22.0-darwin-x64.tar.gz", "node-v22.22.0-darwin-x64", "5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"),
|
||||
"22.22.0-linux_arm64": ("node-v22.22.0-linux-arm64.tar.xz", "node-v22.22.0-linux-arm64", "1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"),
|
||||
"22.22.0-linux_ppc64le": ("node-v22.22.0-linux-ppc64le.tar.xz", "node-v22.22.0-linux-ppc64le", "d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"),
|
||||
"22.22.0-linux_s390x": ("node-v22.22.0-linux-s390x.tar.xz", "node-v22.22.0-linux-s390x", "5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"),
|
||||
"22.22.0-linux_amd64": ("node-v22.22.0-linux-x64.tar.xz", "node-v22.22.0-linux-x64", "9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"),
|
||||
"22.22.0-windows_amd64": ("node-v22.22.0-win-x64.zip", "node-v22.22.0-win-x64", "c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"),
|
||||
},
|
||||
node_version = "22.22.1",
|
||||
node_version = "22.22.0",
|
||||
)
|
||||
use_repo(node, "nodejs_toolchains")
|
||||
use_repo(node, "nodejs_darwin_amd64")
|
||||
@@ -71,8 +71,8 @@ use_repo(node, "nodejs_windows_amd64")
|
||||
pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm")
|
||||
pnpm.pnpm(
|
||||
name = "pnpm",
|
||||
pnpm_version = "10.32.0",
|
||||
pnpm_version_integrity = "sha512-myY0uz/tVgHDNjPy2SWT9QYnCjljuMUdKy1qgo2mFc5One6++WFMzrvBOsjTwPnJzM61g8achXhDb6R327INcA==",
|
||||
pnpm_version = "10.28.2",
|
||||
pnpm_version_integrity = "sha512-QYcvA3rSL3NI47Heu69+hnz9RI8nJtnPdMCPGVB8MdLI56EVJbmD/rwt9kC1Q43uYCPrsfhO1DzC1lTSvDJiZA==",
|
||||
)
|
||||
use_repo(pnpm, "pnpm")
|
||||
|
||||
@@ -83,6 +83,7 @@ npm.npm_translate_lock(
|
||||
"//:.pnpmfile.cjs",
|
||||
"//:package.json",
|
||||
"//:pnpm-workspace.yaml",
|
||||
"//:tools/pnpm-patches/dagre-d3-es+7.0.11.patch",
|
||||
"//adev:package.json",
|
||||
"//adev/shared-docs:package.json",
|
||||
"//adev/shared-docs/pipeline/api-gen:package.json",
|
||||
|
||||
Generated
+286
-288
@@ -22,8 +22,8 @@
|
||||
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.9.3/MODULE.bazel": "66baf724dbae7aff4787bf2245cc188d50cb08e07789769730151c0943587c14",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.0/MODULE.bazel": "5fef5ec709c837312823f9bcf0f276661e2cb48ad52f17c4e01176bbf1e9bf58",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.0/source.json": "5e42968c6d23ab8bd95c02634b16864d866334347827cb6a8425b86c11cc4363",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.4/MODULE.bazel": "fbb819eb8b7e5d7f67fdd38f7cecb413e287594cd666ce192c72c8828527775a",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.4/source.json": "81ffb708333cd98ec3c0b4cc004f4d5cf92a16914b5196a2892c45141bba7cff",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.2/MODULE.bazel": "45f054400ff242c4433f6d7f20f6123a9a72739cb7a1f44247d738db1644f46c",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.2/source.json": "3ed399a5654259a822448f9cdbf21f6c738f16ccd7f89249c7507e374cbdd1e3",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_js/2.0.0/MODULE.bazel": "b45b507574aa60a92796e3e13c195cd5744b3b8aff516a9c0cb5ae6a048161c5",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_js/2.4.2/MODULE.bazel": "0d01db38b96d25df7ed952a5e96eac4b3802723d146961974bf020f6dd07591d",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_js/2.6.2/MODULE.bazel": "ed2a871f4ab8fbde0cab67c425745069d84ea64b64313fa1a2954017326511f5",
|
||||
@@ -33,8 +33,8 @@
|
||||
"https://bcr.bazel.build/modules/aspect_rules_rollup/2.0.1/source.json": "2fe8ac1ccb4de74bf884761e070010280b272d94e3997205b361b91c75409726",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.6.3/MODULE.bazel": "d09db394970f076176ce7bab5b5fa7f0d560fd4f30b8432ea5e2c2570505b130",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.7.0/MODULE.bazel": "5aace216caf88638950ef061245d23c36f57c8359e56e97f02a36f70bb09c50f",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.5/MODULE.bazel": "bcf8f0b6b9375f0f74451e2f70671efae9bb366acef8fdc04675305eaf137f06",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.5/source.json": "fa35e43f6359f654e4b70ce55efdf280d0b06c0b3ef9fc0b06ba52327a0e6311",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.3/MODULE.bazel": "a26c28ebcd0c0d50ab0708ac21fa48bd2dced3a4dad4c31a2fa48588b42ad762",
|
||||
"https://bcr.bazel.build/modules/aspect_rules_ts/3.8.3/source.json": "d17304791281168c42c5532b4b9e01dfb4bdb42d7bf784597b75f401211efc63",
|
||||
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.3/MODULE.bazel": "20f53b145f40957a51077ae90b37b7ce83582a1daf9350349f0f86179e19dd0d",
|
||||
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.6/MODULE.bazel": "cafb8781ad591bc57cc765dca5fefab08cf9f65af363d162b79d49205c7f8af7",
|
||||
"https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.8/MODULE.bazel": "aa975a83e72bcaac62ee61ab12b788ea324a1d05c4aab28aadb202f647881679",
|
||||
@@ -77,8 +77,7 @@
|
||||
"https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
|
||||
"https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
|
||||
"https://bcr.bazel.build/modules/gawk/5.3.2.bcr.1/MODULE.bazel": "cdf8cbe5ee750db04b78878c9633cc76e80dcf4416cbe982ac3a9222f80713c8",
|
||||
"https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/MODULE.bazel": "f1b7bb2dd53e8f2ef984b39485ec8a44e9076dda5c4b8efd2fb4c6a6e856a31d",
|
||||
"https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/source.json": "ebe931bfe362e4b41e59ee00a528db6074157ff2ced92eb9e970acab2e1089c9",
|
||||
"https://bcr.bazel.build/modules/gawk/5.3.2.bcr.1/source.json": "fa7b512dfcb5eafd90ce3959cf42a2a6fe96144ebbb4b3b3928054895f2afac2",
|
||||
"https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb",
|
||||
"https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6",
|
||||
@@ -127,7 +126,6 @@
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.2.16/MODULE.bazel": "9242fa89f950c6ef7702801ab53922e99c69b02310c39fb6e62b2bd30df2a1d4",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.2.16/source.json": "d03d5cde49376d87e14ec14b666c56075e5e3926930327fd5d0484a1ff2ac1cc",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.2.4/MODULE.bazel": "1ff1223dfd24f3ecf8f028446d4a27608aa43c3f41e346d22838a4223980b8cc",
|
||||
"https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
|
||||
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
|
||||
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e",
|
||||
@@ -200,14 +198,14 @@
|
||||
"https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.2.1/MODULE.bazel": "52d1c00a80a8cc67acbd01649e83d8dd6a9dc426a6c0b754a04fe8c219c76468",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.5.1/MODULE.bazel": "7c2eb3dcfc53b0f3d6f9acdfd911ca803eaf92aadf54f8ca6e4c1f3aee288351",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.9.0/MODULE.bazel": "452a22d7f02b1c9d7a22ab25edf20f46f3e1101f0f67dc4bfbf9a474ddf02445",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.9.0/source.json": "c732760a374831a2cf5b08839e4be75017196b4d796a5aa55235272ee17cd839",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.8.1/MODULE.bazel": "6ffe8907ed4c555bc94bd35a5a01411cc4470c6dace84f9cf487815409e077d1",
|
||||
"https://bcr.bazel.build/modules/tar.bzl/0.8.1/source.json": "835f83b482facf6205ad8708cf2b2f6524d1d7b1075a90fe9bb540da761d6d2e",
|
||||
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.1.1/MODULE.bazel": "9039681f9bcb8958ee2c87ffc74bdafba9f4369096a2b5634b88abc0eaefa072",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.2.0/MODULE.bazel": "6f3a675677db8885be4d607fde14cc51829715e3a879fb016eb9bf336786ce6d",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.2/MODULE.bazel": "0384efa70e8033d842ea73aa4b7199fa099709e236a7264345c03937166670b6",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.5/MODULE.bazel": "130c603e54be717bdf84100210f06598a0d2b4b4e01888fb01b70f50f41767ec",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.5/source.json": "1ae7bdc03cb26aaa8bd2bceadf65e90d90f0b2d03008ba9a0564da2e21396c39",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.4/MODULE.bazel": "d3a270662f5d766cd7229732d65a5a5bc485240c3007343dd279edfb60c9ae27",
|
||||
"https://bcr.bazel.build/modules/yq.bzl/0.3.4/source.json": "786dafdc2843722da3416e4343ee1a05237227f068590779a6e8496a2064c0f9",
|
||||
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806",
|
||||
@@ -217,7 +215,7 @@
|
||||
"moduleExtensions": {
|
||||
"@@aspect_rules_esbuild+//esbuild:extensions.bzl%esbuild": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "fzdwsWU1Px4bYL57Cw1rvU/mgOqB7f0AF51JxT5kAs8=",
|
||||
"bzlTransitiveDigest": "c4i5gawrp4Au9UMb55EzQCePYwkrFqD9tFBN7GdHG5g=",
|
||||
"usagesDigest": "ToTaCONCN/E05krnHXLM1kpV1zrHNxHrGpUip973II4=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
@@ -418,8 +416,8 @@
|
||||
},
|
||||
"@@aspect_rules_js+//npm:extensions.bzl%pnpm": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "9Zmqluz9ltvCoc6pskOslTkQpkH6CIINjWVkgam9aa4=",
|
||||
"usagesDigest": "pLuUB7Fmb40xWdK1ynAXIWXeucWkJ0R9x2nDjqKhbq4=",
|
||||
"bzlTransitiveDigest": "HC+l+mTivq1p/KbcVQ+iV5QwYR+oKESJh827FY68SH8=",
|
||||
"usagesDigest": "vXOmvUr0fqA3q7dqX4ag6bG81ZACRs8u7NWugFlQ2j8=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -428,11 +426,11 @@
|
||||
"repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_rule",
|
||||
"attributes": {
|
||||
"package": "pnpm",
|
||||
"version": "10.32.0",
|
||||
"version": "10.28.2",
|
||||
"root_package": "",
|
||||
"link_workspace": "",
|
||||
"link_packages": {},
|
||||
"integrity": "sha512-myY0uz/tVgHDNjPy2SWT9QYnCjljuMUdKy1qgo2mFc5One6++WFMzrvBOsjTwPnJzM61g8achXhDb6R327INcA==",
|
||||
"integrity": "sha512-QYcvA3rSL3NI47Heu69+hnz9RI8nJtnPdMCPGVB8MdLI56EVJbmD/rwt9kC1Q43uYCPrsfhO1DzC1lTSvDJiZA==",
|
||||
"url": "",
|
||||
"commit": "",
|
||||
"patch_args": [
|
||||
@@ -455,7 +453,7 @@
|
||||
"repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_links",
|
||||
"attributes": {
|
||||
"package": "pnpm",
|
||||
"version": "10.32.0",
|
||||
"version": "10.28.2",
|
||||
"dev": false,
|
||||
"root_package": "",
|
||||
"link_packages": {},
|
||||
@@ -572,10 +570,10 @@
|
||||
},
|
||||
"@@aspect_rules_ts+//ts:extensions.bzl%ext": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "6NyLUdrb79stFKm8oWIBK2q65cT5Upbr8IR2Qwsywu8=",
|
||||
"usagesDigest": "ZXlhH7TrNEERA0ibuRRxAjYv2fVuXoFGNd3v+0UK1/g=",
|
||||
"bzlTransitiveDigest": "gyALvLdd/1AuLPFXhzNeabk2DMLHf32oxn8qKfEK8UA=",
|
||||
"usagesDigest": "BIPOUwqzuuYqLOw/0p3h5GwHIDeBVXvNcxNoG5YlsHQ=",
|
||||
"recordedFileInputs": {
|
||||
"@@rules_browsers+//package.json": "772d873d450a539e2133635aeb5e63744cf1cec86e6b37aeecd9267a147fb0d7"
|
||||
"@@rules_browsers+//package.json": "84dc1ba9b1c667a25894e97218bd8f247d54f24bb694efb397a881be3c06a4c5"
|
||||
},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -639,7 +637,7 @@
|
||||
"@@aspect_tools_telemetry+//:extension.bzl%telemetry": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "cl5A2O84vDL6Tt+Qga8FCj1DUDGqn+e7ly5rZ+4xvcc=",
|
||||
"usagesDigest": "fkarigrHiiNAt/BwClRuO51QOEo6226baK6LoK/IWdU=",
|
||||
"usagesDigest": "m4Fa2faQCHxeGwDkOwASSCEydzPyBW44x/rz9KgbgJQ=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -648,10 +646,10 @@
|
||||
"repoRuleId": "@@aspect_tools_telemetry+//:extension.bzl%tel_repository",
|
||||
"attributes": {
|
||||
"deps": {
|
||||
"aspect_rules_ts": "3.8.5",
|
||||
"aspect_rules_ts": "3.8.3",
|
||||
"aspect_rules_js": "2.9.2",
|
||||
"aspect_rules_esbuild": "0.25.0",
|
||||
"aspect_rules_jasmine": "2.0.4",
|
||||
"aspect_rules_jasmine": "2.0.2",
|
||||
"aspect_tools_telemetry": "0.3.3"
|
||||
}
|
||||
}
|
||||
@@ -673,7 +671,7 @@
|
||||
},
|
||||
"@@pybind11_bazel+//:python_configure.bzl%extension": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "D2/qWHU6yQFwRG7Bb+caqrYMha5avsASao2vERrxK24=",
|
||||
"bzlTransitiveDigest": "c9ZWWeXeu6bctL4/SsY2otFWyeFN0JJ20+ymGyJZtWk=",
|
||||
"usagesDigest": "fycyB39YnXIJkfWCIXLUKJMZzANcuLy9ZE73hRucjFk=",
|
||||
"recordedFileInputs": {
|
||||
"@@pybind11_bazel+//MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e"
|
||||
@@ -733,8 +731,8 @@
|
||||
},
|
||||
"@@rules_browsers+//browsers:extensions.bzl%browsers": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "Bm6fiKpWy96aLohOlLCP36ARVxRLZm/R+smhsb2HzmI=",
|
||||
"usagesDigest": "FmXYJVoVJlnfUU8x8gObSvu4qWcco/9Faw61aC/wBF0=",
|
||||
"bzlTransitiveDigest": "agkaLQ8wE1r/5IX6pkERzFxI/z0M42Em+ICNO6TXsVo=",
|
||||
"usagesDigest": "FS7q5WaIwg3KirS3njhuPFkTIBYvDaTInVGrlzu0XL8=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -742,9 +740,9 @@
|
||||
"rules_browsers_chrome_linux": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "1ac33f89306327af43be159c03ca4a26486de0858f42fe52394acdef50364143",
|
||||
"sha256": "0a2ff0fc9eb5958b7b420f20e3968f424be7423fef89739e71565a48aa073a57",
|
||||
"urls": [
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/linux64/chrome-headless-shell-linux64.zip"
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/linux64/chrome-headless-shell-linux64.zip"
|
||||
],
|
||||
"named_files": {
|
||||
"CHROME-HEADLESS-SHELL": "chrome-headless-shell-linux64/chrome-headless-shell"
|
||||
@@ -760,9 +758,9 @@
|
||||
"rules_browsers_chrome_mac": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "169ff49c465cfda52931395e61861e146dfc5013e92c01ca792db5acea858d0b",
|
||||
"sha256": "e6076b1201d86f74c5eab982a239d5af83e66b1aa4d780bcb792698790e01d87",
|
||||
"urls": [
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/mac-x64/chrome-headless-shell-mac-x64.zip"
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/mac-x64/chrome-headless-shell-mac-x64.zip"
|
||||
],
|
||||
"named_files": {
|
||||
"CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-x64/chrome-headless-shell"
|
||||
@@ -778,9 +776,9 @@
|
||||
"rules_browsers_chrome_mac_arm": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "aeaaaaa4d68193a21bed04c44ddeb1230232707b4ea1d845a92925787509cd8e",
|
||||
"sha256": "b74dbcf5543d916b02d0a133e2e7c6a4de251f06733f72c2c15ea8c42213f63b",
|
||||
"urls": [
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/mac-arm64/chrome-headless-shell-mac-arm64.zip"
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/mac-arm64/chrome-headless-shell-mac-arm64.zip"
|
||||
],
|
||||
"named_files": {
|
||||
"CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-arm64/chrome-headless-shell"
|
||||
@@ -796,9 +794,9 @@
|
||||
"rules_browsers_chrome_win64": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "4d6d79bcbcb22084df6e3a3d3a2caff67d6c0fa488d63f0c7ec1526f9553db8c",
|
||||
"sha256": "df1e612dc3b1615e182a1f11821052995913c39df37caa52699de21a68d030d2",
|
||||
"urls": [
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/win64/chrome-headless-shell-win64.zip"
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/win64/chrome-headless-shell-win64.zip"
|
||||
],
|
||||
"named_files": {
|
||||
"CHROME-HEADLESS-SHELL": "chrome-headless-shell-win64/chrome-headless-shell.exe"
|
||||
@@ -814,9 +812,9 @@
|
||||
"rules_browsers_chromedriver_linux": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "0607ccf6810a07ae08cac6443beac8b23f88dd53c7f1e0299e22d65f7cd2d020",
|
||||
"sha256": "69c504306399d979a2766fea603c3fb9d3d87d46c75bddc9f2a049b4f636d57c",
|
||||
"urls": [
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/linux64/chromedriver-linux64.zip"
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/linux64/chromedriver-linux64.zip"
|
||||
],
|
||||
"named_files": {
|
||||
"CHROMEDRIVER": "chromedriver-linux64/chromedriver"
|
||||
@@ -830,9 +828,9 @@
|
||||
"rules_browsers_chromedriver_mac": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "0f512a9dd683ed4c41e609d8d02c07807497dbad3ab2f95f0d583486be7b8cff",
|
||||
"sha256": "5fc9d6f594fc5f2568a15145f25116dd8e9c9a60baa8da4bb21a17650fb00e7e",
|
||||
"urls": [
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/mac-x64/chromedriver-mac-x64.zip"
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/mac-x64/chromedriver-mac-x64.zip"
|
||||
],
|
||||
"named_files": {
|
||||
"CHROMEDRIVER": "chromedriver-mac-x64/chromedriver"
|
||||
@@ -846,9 +844,9 @@
|
||||
"rules_browsers_chromedriver_mac_arm": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "7d6fc6d17de1733eb6739d1ea16d085c8df1568bcf9fa0d130c2784b27f38268",
|
||||
"sha256": "14e92294c2c3639ca4e7d27e850588b619d698e2f8905cee368f07db2e1bf1e9",
|
||||
"urls": [
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/mac-arm64/chromedriver-mac-arm64.zip"
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/mac-arm64/chromedriver-mac-arm64.zip"
|
||||
],
|
||||
"named_files": {
|
||||
"CHROMEDRIVER": "chromedriver-mac-arm64/chromedriver"
|
||||
@@ -862,9 +860,9 @@
|
||||
"rules_browsers_chromedriver_win64": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "f4e9fb7bbf692fde7979b24e8d737b3cef4baafbc7a370e5d0abc4a8450fd830",
|
||||
"sha256": "cf641d2e176db95bcc158cd90eafd347ad4928fa0458a5f3bfd56c6d983e70db",
|
||||
"urls": [
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/147.0.7687.0/win64/chromedriver-win64.zip"
|
||||
"https://storage.googleapis.com/chrome-for-testing-public/145.0.7586.0/win64/chromedriver-win64.zip"
|
||||
],
|
||||
"named_files": {
|
||||
"CHROMEDRIVER": "chromedriver-win64/chromedriver.exe"
|
||||
@@ -878,9 +876,9 @@
|
||||
"rules_browsers_firefox_linux": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "f055b9c0d7346a10d22edc7f10e08679af2ea495367381ab2be9cab3ec6add97",
|
||||
"sha256": "8d56f479cc398a537a60a3fa20dca92d8a41925113d3a67f534881a4e4d7e344",
|
||||
"urls": [
|
||||
"https://archive.mozilla.org/pub/firefox/releases/147.0/linux-x86_64/en-US/firefox-147.0.tar.xz"
|
||||
"https://archive.mozilla.org/pub/firefox/releases/146.0/linux-x86_64/en-US/firefox-146.0.tar.xz"
|
||||
],
|
||||
"named_files": {
|
||||
"FIREFOX": "firefox/firefox"
|
||||
@@ -894,9 +892,9 @@
|
||||
"rules_browsers_firefox_mac": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "48485e2068bc726e2f30cf5855fc2da1fc75c1272bc243a5394f428ffae3ba35",
|
||||
"sha256": "4b1645313887972d466cd82166ea571485c2c40a167f84624e3f3ca739993cc9",
|
||||
"urls": [
|
||||
"https://archive.mozilla.org/pub/firefox/releases/147.0/mac/en-US/Firefox%20147.0.dmg"
|
||||
"https://archive.mozilla.org/pub/firefox/releases/146.0/mac/en-US/Firefox%20146.0.dmg"
|
||||
],
|
||||
"named_files": {
|
||||
"FIREFOX": "Firefox.app/Contents/MacOS/firefox"
|
||||
@@ -910,9 +908,9 @@
|
||||
"rules_browsers_firefox_mac_arm": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "48485e2068bc726e2f30cf5855fc2da1fc75c1272bc243a5394f428ffae3ba35",
|
||||
"sha256": "4b1645313887972d466cd82166ea571485c2c40a167f84624e3f3ca739993cc9",
|
||||
"urls": [
|
||||
"https://archive.mozilla.org/pub/firefox/releases/147.0/mac/en-US/Firefox%20147.0.dmg"
|
||||
"https://archive.mozilla.org/pub/firefox/releases/146.0/mac/en-US/Firefox%20146.0.dmg"
|
||||
],
|
||||
"named_files": {
|
||||
"FIREFOX": "Firefox.app/Contents/MacOS/firefox"
|
||||
@@ -926,9 +924,9 @@
|
||||
"rules_browsers_firefox_win64": {
|
||||
"repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo",
|
||||
"attributes": {
|
||||
"sha256": "36ff9e150875aa48a0af9eec3eb67f66dddd8efac5c743265371a72ae3e796c4",
|
||||
"sha256": "216870c89648f32450cfefb5cec417fcd66d480d5dc83f894bf99f5fd7f38dbb",
|
||||
"urls": [
|
||||
"https://archive.mozilla.org/pub/firefox/releases/147.0/win64/en-US/Firefox%20Setup%20147.0.exe"
|
||||
"https://archive.mozilla.org/pub/firefox/releases/146.0/win64/en-US/Firefox%20Setup%20146.0.exe"
|
||||
],
|
||||
"named_files": {
|
||||
"FIREFOX": "core/firefox.exe"
|
||||
@@ -945,7 +943,7 @@
|
||||
},
|
||||
"@@rules_fuzzing+//fuzzing/private:extensions.bzl%non_module_dependencies": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "4LouzhF/yT117s7peGnNs9ROomiJXC6Zl5R0oI21jho=",
|
||||
"bzlTransitiveDigest": "WHRlQQnxW7e7XMRBhq7SARkDarLDOAbg6iLaJpk5QYM=",
|
||||
"usagesDigest": "wy6ISK6UOcBEjj/mvJ/S3WeXoO67X+1llb9yPyFtPgc=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
@@ -1028,7 +1026,7 @@
|
||||
},
|
||||
"@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "nvW/NrBXlAmiQw99EMGKkLaD2KbNp2mQDlxdfpr+0Ls=",
|
||||
"bzlTransitiveDigest": "rL/34P1aFDq2GqVC2zCFgQ8nTuOC6ziogocpvG50Qz8=",
|
||||
"usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
@@ -1093,7 +1091,7 @@
|
||||
"@@rules_nodejs+//nodejs:extensions.bzl%node": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "4pUxCNc22K4I+6+4Nxu52Hur12tFRfa1JMsN5mdDv60=",
|
||||
"usagesDigest": "pjXeuItYQffkhMcQv+aU/G0SB0QAmyOC9W7iq63eW08=",
|
||||
"usagesDigest": "yiylduJft13ULV5TUSGMYtVEKVnH/fJkG3SYNNrzFsQ=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
@@ -1103,46 +1101,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.0-darwin_arm64": [
|
||||
"node-v22.22.0-darwin-arm64.tar.gz",
|
||||
"node-v22.22.0-darwin-arm64",
|
||||
"5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.0-darwin_amd64": [
|
||||
"node-v22.22.0-darwin-x64.tar.gz",
|
||||
"node-v22.22.0-darwin-x64",
|
||||
"5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.0-linux_arm64": [
|
||||
"node-v22.22.0-linux-arm64.tar.xz",
|
||||
"node-v22.22.0-linux-arm64",
|
||||
"1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.0-linux_ppc64le": [
|
||||
"node-v22.22.0-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.0-linux-ppc64le",
|
||||
"d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.0-linux_s390x": [
|
||||
"node-v22.22.0-linux-s390x.tar.xz",
|
||||
"node-v22.22.0-linux-s390x",
|
||||
"5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.0-linux_amd64": [
|
||||
"node-v22.22.0-linux-x64.tar.xz",
|
||||
"node-v22.22.0-linux-x64",
|
||||
"9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.0-windows_amd64": [
|
||||
"node-v22.22.0-win-x64.zip",
|
||||
"node-v22.22.0-win-x64",
|
||||
"c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.0",
|
||||
"include_headers": false,
|
||||
"platform": "linux_amd64"
|
||||
}
|
||||
@@ -1152,46 +1150,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.0-darwin_arm64": [
|
||||
"node-v22.22.0-darwin-arm64.tar.gz",
|
||||
"node-v22.22.0-darwin-arm64",
|
||||
"5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.0-darwin_amd64": [
|
||||
"node-v22.22.0-darwin-x64.tar.gz",
|
||||
"node-v22.22.0-darwin-x64",
|
||||
"5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.0-linux_arm64": [
|
||||
"node-v22.22.0-linux-arm64.tar.xz",
|
||||
"node-v22.22.0-linux-arm64",
|
||||
"1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.0-linux_ppc64le": [
|
||||
"node-v22.22.0-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.0-linux-ppc64le",
|
||||
"d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.0-linux_s390x": [
|
||||
"node-v22.22.0-linux-s390x.tar.xz",
|
||||
"node-v22.22.0-linux-s390x",
|
||||
"5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.0-linux_amd64": [
|
||||
"node-v22.22.0-linux-x64.tar.xz",
|
||||
"node-v22.22.0-linux-x64",
|
||||
"9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.0-windows_amd64": [
|
||||
"node-v22.22.0-win-x64.zip",
|
||||
"node-v22.22.0-win-x64",
|
||||
"c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.0",
|
||||
"include_headers": false,
|
||||
"platform": "linux_arm64"
|
||||
}
|
||||
@@ -1201,46 +1199,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.0-darwin_arm64": [
|
||||
"node-v22.22.0-darwin-arm64.tar.gz",
|
||||
"node-v22.22.0-darwin-arm64",
|
||||
"5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.0-darwin_amd64": [
|
||||
"node-v22.22.0-darwin-x64.tar.gz",
|
||||
"node-v22.22.0-darwin-x64",
|
||||
"5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.0-linux_arm64": [
|
||||
"node-v22.22.0-linux-arm64.tar.xz",
|
||||
"node-v22.22.0-linux-arm64",
|
||||
"1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.0-linux_ppc64le": [
|
||||
"node-v22.22.0-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.0-linux-ppc64le",
|
||||
"d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.0-linux_s390x": [
|
||||
"node-v22.22.0-linux-s390x.tar.xz",
|
||||
"node-v22.22.0-linux-s390x",
|
||||
"5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.0-linux_amd64": [
|
||||
"node-v22.22.0-linux-x64.tar.xz",
|
||||
"node-v22.22.0-linux-x64",
|
||||
"9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.0-windows_amd64": [
|
||||
"node-v22.22.0-win-x64.zip",
|
||||
"node-v22.22.0-win-x64",
|
||||
"c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.0",
|
||||
"include_headers": false,
|
||||
"platform": "linux_s390x"
|
||||
}
|
||||
@@ -1250,46 +1248,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.0-darwin_arm64": [
|
||||
"node-v22.22.0-darwin-arm64.tar.gz",
|
||||
"node-v22.22.0-darwin-arm64",
|
||||
"5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.0-darwin_amd64": [
|
||||
"node-v22.22.0-darwin-x64.tar.gz",
|
||||
"node-v22.22.0-darwin-x64",
|
||||
"5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.0-linux_arm64": [
|
||||
"node-v22.22.0-linux-arm64.tar.xz",
|
||||
"node-v22.22.0-linux-arm64",
|
||||
"1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.0-linux_ppc64le": [
|
||||
"node-v22.22.0-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.0-linux-ppc64le",
|
||||
"d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.0-linux_s390x": [
|
||||
"node-v22.22.0-linux-s390x.tar.xz",
|
||||
"node-v22.22.0-linux-s390x",
|
||||
"5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.0-linux_amd64": [
|
||||
"node-v22.22.0-linux-x64.tar.xz",
|
||||
"node-v22.22.0-linux-x64",
|
||||
"9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.0-windows_amd64": [
|
||||
"node-v22.22.0-win-x64.zip",
|
||||
"node-v22.22.0-win-x64",
|
||||
"c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.0",
|
||||
"include_headers": false,
|
||||
"platform": "linux_ppc64le"
|
||||
}
|
||||
@@ -1299,46 +1297,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.0-darwin_arm64": [
|
||||
"node-v22.22.0-darwin-arm64.tar.gz",
|
||||
"node-v22.22.0-darwin-arm64",
|
||||
"5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.0-darwin_amd64": [
|
||||
"node-v22.22.0-darwin-x64.tar.gz",
|
||||
"node-v22.22.0-darwin-x64",
|
||||
"5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.0-linux_arm64": [
|
||||
"node-v22.22.0-linux-arm64.tar.xz",
|
||||
"node-v22.22.0-linux-arm64",
|
||||
"1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.0-linux_ppc64le": [
|
||||
"node-v22.22.0-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.0-linux-ppc64le",
|
||||
"d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.0-linux_s390x": [
|
||||
"node-v22.22.0-linux-s390x.tar.xz",
|
||||
"node-v22.22.0-linux-s390x",
|
||||
"5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.0-linux_amd64": [
|
||||
"node-v22.22.0-linux-x64.tar.xz",
|
||||
"node-v22.22.0-linux-x64",
|
||||
"9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.0-windows_amd64": [
|
||||
"node-v22.22.0-win-x64.zip",
|
||||
"node-v22.22.0-win-x64",
|
||||
"c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.0",
|
||||
"include_headers": false,
|
||||
"platform": "darwin_amd64"
|
||||
}
|
||||
@@ -1348,46 +1346,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.0-darwin_arm64": [
|
||||
"node-v22.22.0-darwin-arm64.tar.gz",
|
||||
"node-v22.22.0-darwin-arm64",
|
||||
"5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.0-darwin_amd64": [
|
||||
"node-v22.22.0-darwin-x64.tar.gz",
|
||||
"node-v22.22.0-darwin-x64",
|
||||
"5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.0-linux_arm64": [
|
||||
"node-v22.22.0-linux-arm64.tar.xz",
|
||||
"node-v22.22.0-linux-arm64",
|
||||
"1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.0-linux_ppc64le": [
|
||||
"node-v22.22.0-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.0-linux-ppc64le",
|
||||
"d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.0-linux_s390x": [
|
||||
"node-v22.22.0-linux-s390x.tar.xz",
|
||||
"node-v22.22.0-linux-s390x",
|
||||
"5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.0-linux_amd64": [
|
||||
"node-v22.22.0-linux-x64.tar.xz",
|
||||
"node-v22.22.0-linux-x64",
|
||||
"9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.0-windows_amd64": [
|
||||
"node-v22.22.0-win-x64.zip",
|
||||
"node-v22.22.0-win-x64",
|
||||
"c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.0",
|
||||
"include_headers": false,
|
||||
"platform": "darwin_arm64"
|
||||
}
|
||||
@@ -1397,46 +1395,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.0-darwin_arm64": [
|
||||
"node-v22.22.0-darwin-arm64.tar.gz",
|
||||
"node-v22.22.0-darwin-arm64",
|
||||
"5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.0-darwin_amd64": [
|
||||
"node-v22.22.0-darwin-x64.tar.gz",
|
||||
"node-v22.22.0-darwin-x64",
|
||||
"5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.0-linux_arm64": [
|
||||
"node-v22.22.0-linux-arm64.tar.xz",
|
||||
"node-v22.22.0-linux-arm64",
|
||||
"1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.0-linux_ppc64le": [
|
||||
"node-v22.22.0-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.0-linux-ppc64le",
|
||||
"d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.0-linux_s390x": [
|
||||
"node-v22.22.0-linux-s390x.tar.xz",
|
||||
"node-v22.22.0-linux-s390x",
|
||||
"5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.0-linux_amd64": [
|
||||
"node-v22.22.0-linux-x64.tar.xz",
|
||||
"node-v22.22.0-linux-x64",
|
||||
"9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.0-windows_amd64": [
|
||||
"node-v22.22.0-win-x64.zip",
|
||||
"node-v22.22.0-win-x64",
|
||||
"c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.0",
|
||||
"include_headers": false,
|
||||
"platform": "windows_amd64"
|
||||
}
|
||||
@@ -1446,46 +1444,46 @@
|
||||
"attributes": {
|
||||
"node_download_auth": {},
|
||||
"node_repositories": {
|
||||
"22.22.1-darwin_arm64": [
|
||||
"node-v22.22.1-darwin-arm64.tar.gz",
|
||||
"node-v22.22.1-darwin-arm64",
|
||||
"679ad4966339e4ef4900f57996714864e4211b898825bb840c3086c419fbcef2"
|
||||
"22.22.0-darwin_arm64": [
|
||||
"node-v22.22.0-darwin-arm64.tar.gz",
|
||||
"node-v22.22.0-darwin-arm64",
|
||||
"5ed4db0fcf1eaf84d91ad12462631d73bf4576c1377e192d222e48026a902640"
|
||||
],
|
||||
"22.22.1-darwin_amd64": [
|
||||
"node-v22.22.1-darwin-x64.tar.gz",
|
||||
"node-v22.22.1-darwin-x64",
|
||||
"07b13722d558790fca20bb1ecf61bde24b7a4863111f7be77fc57251a407359a"
|
||||
"22.22.0-darwin_amd64": [
|
||||
"node-v22.22.0-darwin-x64.tar.gz",
|
||||
"node-v22.22.0-darwin-x64",
|
||||
"5ea50c9d6dea3dfa3abb66b2656f7a4e1c8cef23432b558d45fb538c7b5dedce"
|
||||
],
|
||||
"22.22.1-linux_arm64": [
|
||||
"node-v22.22.1-linux-arm64.tar.xz",
|
||||
"node-v22.22.1-linux-arm64",
|
||||
"0f3550d58d45e5d3cf7103d9e3f69937f09fe82fb5dd474c66a5d816fa58c9ee"
|
||||
"22.22.0-linux_arm64": [
|
||||
"node-v22.22.0-linux-arm64.tar.xz",
|
||||
"node-v22.22.0-linux-arm64",
|
||||
"1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f"
|
||||
],
|
||||
"22.22.1-linux_ppc64le": [
|
||||
"node-v22.22.1-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.1-linux-ppc64le",
|
||||
"a65a44cf0224505f052b90357b763dbc1ea9148f4f5f2284f0596cf2000f819b"
|
||||
"22.22.0-linux_ppc64le": [
|
||||
"node-v22.22.0-linux-ppc64le.tar.xz",
|
||||
"node-v22.22.0-linux-ppc64le",
|
||||
"d83b9957431cc18e1fc143a4b99f89cde7b8a18f53ef392231b4336afd058865"
|
||||
],
|
||||
"22.22.1-linux_s390x": [
|
||||
"node-v22.22.1-linux-s390x.tar.xz",
|
||||
"node-v22.22.1-linux-s390x",
|
||||
"e08b3a73d0bd840e008f589e4be4a2ef3d4a0c59015f4f20a04ed7fc968042a2"
|
||||
"22.22.0-linux_s390x": [
|
||||
"node-v22.22.0-linux-s390x.tar.xz",
|
||||
"node-v22.22.0-linux-s390x",
|
||||
"5aa0e520689448c4233e8d73f284e8e0634fdcd32b479735698494be5641f3e4"
|
||||
],
|
||||
"22.22.1-linux_amd64": [
|
||||
"node-v22.22.1-linux-x64.tar.xz",
|
||||
"node-v22.22.1-linux-x64",
|
||||
"9a6bc82f9b491279147219f6a18add1e18424dce90d41d2a5fcd69d4924ba3aa"
|
||||
"22.22.0-linux_amd64": [
|
||||
"node-v22.22.0-linux-x64.tar.xz",
|
||||
"node-v22.22.0-linux-x64",
|
||||
"9aa8e9d2298ab68c600bd6fb86a6c13bce11a4eca1ba9b39d79fa021755d7c37"
|
||||
],
|
||||
"22.22.1-windows_amd64": [
|
||||
"node-v22.22.1-win-x64.zip",
|
||||
"node-v22.22.1-win-x64",
|
||||
"877cb93829e14fffbbc7903e7d8037336c9a79f3ea43c5d0b8c2379b79da56de"
|
||||
"22.22.0-windows_amd64": [
|
||||
"node-v22.22.0-win-x64.zip",
|
||||
"node-v22.22.0-win-x64",
|
||||
"c97fa376d2becdc8863fcd3ca2dd9a83a9f3468ee7ccf7a6d076ec66a645c77a"
|
||||
]
|
||||
},
|
||||
"node_urls": [
|
||||
"https://nodejs.org/dist/v{version}/{filename}"
|
||||
],
|
||||
"node_version": "22.22.1",
|
||||
"node_version": "22.22.0",
|
||||
"include_headers": false,
|
||||
"platform": "windows_arm64"
|
||||
}
|
||||
@@ -1514,7 +1512,7 @@
|
||||
},
|
||||
"@@rules_python+//python/extensions:pip.bzl%pip": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "LFkevJ0u48WgTVCyU07LkRD8iYwsRUs2M7uSFHkQAW0=",
|
||||
"bzlTransitiveDigest": "d3ENjFH8qMwmOrkcb3c9JYqQ5hJ6owjfbSr24KY0Ugg=",
|
||||
"usagesDigest": "/9NP3RV6/DWuNdYAsIU/8UCgCX0TdPUJr0X6O+0lrtk=",
|
||||
"recordedFileInputs": {
|
||||
"@@protobuf+//python/requirements.txt": "983be60d3cec4b319dcab6d48aeb3f5b2f7c3350f26b3a9e97486c37967c73c5",
|
||||
@@ -4308,8 +4306,8 @@
|
||||
},
|
||||
"@@yq.bzl+//yq:extensions.bzl%yq": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "UfFMy8CWK4/dVo/tfaSAIYUiDGNAPes5eRllx9O9Q9Q=",
|
||||
"usagesDigest": "LPHUB1lzZAsPKLeNh6HnzS3+5eXDr8A5CKmoD+VBOA4=",
|
||||
"bzlTransitiveDigest": "tDqk+ntWTdxNAWPDjRY1uITgHbti2jcXR5ZdinltBs0=",
|
||||
"usagesDigest": "soFLPyR23RWNxgPKSnibWfWF51i2rx0N0Vs4WyvVNpE=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
|
||||
@@ -60,7 +60,6 @@ APPLICATION_DEPS = [
|
||||
":node_modules/@lezer/highlight",
|
||||
":node_modules/@lezer/javascript",
|
||||
":node_modules/@stackblitz/sdk",
|
||||
":node_modules/shiki",
|
||||
":node_modules/@typescript/vfs",
|
||||
":node_modules/@webcontainer/api",
|
||||
":node_modules/@xterm/addon-fit",
|
||||
@@ -92,30 +91,6 @@ APPLICATION_DEPS = [
|
||||
":node_modules/crelt",
|
||||
":node_modules/style-mod",
|
||||
":node_modules/w3c-keyname",
|
||||
#
|
||||
":node_modules/@shikijs/themes",
|
||||
":node_modules/@shikijs/langs",
|
||||
":node_modules/@shikijs/engine-oniguruma",
|
||||
":node_modules/@shikijs/core",
|
||||
":node_modules/@shikijs/engine-javascript",
|
||||
":node_modules/@shikijs/types",
|
||||
":node_modules/@shikijs/vscode-textmate",
|
||||
":node_modules/hast-util-to-html",
|
||||
# ":node_modules/oniguruma-to-es",
|
||||
":node_modules/ccount",
|
||||
":node_modules/comma-separated-tokens",
|
||||
":node_modules/hast-util-whitespace",
|
||||
":node_modules/html-void-elements",
|
||||
# ":node_modules/oniguruma-parser",
|
||||
":node_modules/property-information",
|
||||
# ":node_modules/regex-recursion",
|
||||
# ":node_modules/regex",
|
||||
":node_modules/space-separated-tokens",
|
||||
":node_modules/stringify-entities",
|
||||
":node_modules/zwitch",
|
||||
":node_modules/character-entities-html4",
|
||||
":node_modules/character-entities-legacy",
|
||||
# ":node_modules/regex-utilities",
|
||||
]
|
||||
|
||||
TEST_FILES = APPLICATION_FILES + glob(["src/app/**/*.spec.ts"])
|
||||
|
||||
+30
-48
@@ -1,25 +1,25 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.48.0",
|
||||
"@algolia/client-search": "5.48.0",
|
||||
"@algolia/requester-browser-xhr": "5.48.0",
|
||||
"@algolia/requester-node-http": "5.48.0",
|
||||
"@algolia/client-common": "5.46.2",
|
||||
"@algolia/client-search": "5.46.2",
|
||||
"@algolia/requester-browser-xhr": "5.46.2",
|
||||
"@algolia/requester-node-http": "5.46.2",
|
||||
"@angular/animations": "workspace:*",
|
||||
"@angular/aria": "21.2.0",
|
||||
"@angular/build": "21.2.0",
|
||||
"@angular/cdk": "21.2.0",
|
||||
"@angular/cli": "21.2.0",
|
||||
"@angular/aria": "21.1.3",
|
||||
"@angular/build": "21.1.2",
|
||||
"@angular/cdk": "21.1.3",
|
||||
"@angular/cli": "21.1.2",
|
||||
"@angular/common": "workspace:*",
|
||||
"@angular/compiler": "workspace:*",
|
||||
"@angular/compiler-cli": "workspace:*",
|
||||
"@angular/core": "workspace:*",
|
||||
"@angular/docs": "workspace:*",
|
||||
"@angular/forms": "workspace:*",
|
||||
"@angular/material": "21.2.0",
|
||||
"@angular/material": "21.1.3",
|
||||
"@angular/platform-browser": "workspace:*",
|
||||
"@angular/platform-server": "workspace:*",
|
||||
"@angular/router": "workspace:*",
|
||||
"@angular/ssr": "21.2.0",
|
||||
"@angular/ssr": "21.1.2",
|
||||
"@codemirror/autocomplete": "6.20.0",
|
||||
"@codemirror/commands": "6.10.1",
|
||||
"@codemirror/lang-angular": "0.1.4",
|
||||
@@ -28,75 +28,57 @@
|
||||
"@codemirror/lang-javascript": "6.2.4",
|
||||
"@codemirror/lang-sass": "6.0.2",
|
||||
"@codemirror/language": "6.12.1",
|
||||
"@codemirror/lint": "6.9.3",
|
||||
"@codemirror/search": "6.6.0",
|
||||
"@codemirror/state": "6.5.4",
|
||||
"@codemirror/view": "6.39.12",
|
||||
"@lezer/common": "1.5.1",
|
||||
"@codemirror/lint": "6.9.2",
|
||||
"@codemirror/search": "6.5.11",
|
||||
"@codemirror/state": "6.5.3",
|
||||
"@codemirror/view": "6.39.9",
|
||||
"@lezer/common": "1.5.0",
|
||||
"@lezer/css": "1.3.0",
|
||||
"@lezer/highlight": "1.2.3",
|
||||
"@lezer/html": "1.3.13",
|
||||
"@lezer/javascript": "1.5.4",
|
||||
"@lezer/lr": "1.4.8",
|
||||
"@lezer/lr": "1.4.7",
|
||||
"@lezer/sass": "1.1.0",
|
||||
"@marijn/find-cluster-break": "1.0.2",
|
||||
"@shikijs/core": "^3.21.0",
|
||||
"@shikijs/engine-javascript": "^3.21.0",
|
||||
"@shikijs/engine-oniguruma": "^3.21.0",
|
||||
"@shikijs/langs": "^3.21.0",
|
||||
"@shikijs/themes": "^3.21.0",
|
||||
"@shikijs/types": "^3.21.0",
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"@stackblitz/sdk": "1.11.0",
|
||||
"@types/dom-navigation": "1.0.6",
|
||||
"@types/jasmine": "6.0.0",
|
||||
"@types/jasmine": "5.1.13",
|
||||
"@types/jsdom": "27.0.0",
|
||||
"@types/node": "24.10.11",
|
||||
"@types/node": "24.10.4",
|
||||
"@typescript/vfs": "1.6.2",
|
||||
"@webcontainer/api": "1.6.1",
|
||||
"@xterm/addon-fit": "0.11.0",
|
||||
"@xterm/xterm": "6.0.0",
|
||||
"algoliasearch": "5.48.0",
|
||||
"algoliasearch": "5.46.2",
|
||||
"angular-split": "20.0.0",
|
||||
"ccount": "^2.0.1",
|
||||
"character-entities-html4": "^2.1.0",
|
||||
"character-entities-legacy": "^3.0.0",
|
||||
"comma-separated-tokens": "^2.0.3",
|
||||
"crelt": "1.0.6",
|
||||
"diff": "8.0.3",
|
||||
"diff": "8.0.2",
|
||||
"emoji-regex": "10.6.0",
|
||||
"fflate": "0.8.2",
|
||||
"hast-util-to-html": "^9.0.5",
|
||||
"hast-util-whitespace": "^3.0.0",
|
||||
"html-void-elements": "^3.0.0",
|
||||
"jsdom": "28.0.0",
|
||||
"jasmine-core": "6.1.0",
|
||||
"jasmine-core": "5.13.0",
|
||||
"jsdom": "27.4.0",
|
||||
"karma-chrome-launcher": "3.2.0",
|
||||
"karma-coverage": "2.2.1",
|
||||
"karma-jasmine": "5.1.0",
|
||||
"karma-jasmine-html-reporter": "2.2.0",
|
||||
"karma-jasmine-html-reporter": "2.1.0",
|
||||
"marked": "17.0.1",
|
||||
"mermaid": "11.12.2",
|
||||
"ngx-progressbar": "14.0.0",
|
||||
"open-in-idx": "0.1.1",
|
||||
"playwright-core": "1.58.1",
|
||||
"preact": "10.28.3",
|
||||
"preact-render-to-string": "6.6.6",
|
||||
"prettier": "3.8.1",
|
||||
"property-information": "^7.1.0",
|
||||
"playwright-core": "1.57.0",
|
||||
"preact": "10.28.2",
|
||||
"preact-render-to-string": "6.6.5",
|
||||
"prettier": "3.8.0",
|
||||
"rxjs": "7.8.2",
|
||||
"shiki": "3.22.0",
|
||||
"space-separated-tokens": "^2.0.2",
|
||||
"stringify-entities": "^4.0.4",
|
||||
"shiki": "3.21.0",
|
||||
"style-mod": "4.1.3",
|
||||
"tinyglobby": "0.2.15",
|
||||
"tslib": "2.8.1",
|
||||
"typescript": "5.9.3",
|
||||
"w3c-keyname": "2.2.8",
|
||||
"zwitch": "^2.0.4"
|
||||
"w3c-keyname": "2.2.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "10.4.24",
|
||||
"autoprefixer": "10.4.23",
|
||||
"karma": "~6.4.4",
|
||||
"postcss": "8.5.6",
|
||||
"tailwindcss": "3.4.19"
|
||||
|
||||
@@ -19,8 +19,7 @@ ts_project(
|
||||
tsconfig = {
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"moduleResolution": "node",
|
||||
"types": ["node"],
|
||||
"rootDir": ".",
|
||||
"skipLibCheck": True,
|
||||
@@ -29,7 +28,6 @@ ts_project(
|
||||
deps = [
|
||||
"//adev:node_modules/@angular/docs",
|
||||
"//adev:node_modules/@types/node",
|
||||
"//adev/shared-docs/pipeline/shared:heading",
|
||||
"//adev/src/app/routing/navigation-entries",
|
||||
"//adev/src/content/reference/errors:route-nav-items",
|
||||
"//adev/src/content/reference/extended-diagnostics:route-nav-items",
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ALL_ITEMS} from '../../src/app/routing/navigation-entries/index.js';
|
||||
import {getIdFromHeading} from '../../shared-docs/pipeline/shared/heading.mjs';
|
||||
import {ALL_ITEMS} from '../../src/app/routing/navigation-entries';
|
||||
import {NavigationItem} from '@angular/docs';
|
||||
import {writeFileSync, readFileSync} from 'fs';
|
||||
import {join, resolve} from 'path';
|
||||
@@ -73,3 +72,11 @@ function main() {
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
// TODO: refactor so this function is shared with the generation pipeline (adev/shared-docs/pipeline/shared/marked/transformations/heading.mts)
|
||||
function getIdFromHeading(heading: string): string {
|
||||
return heading
|
||||
.toLowerCase()
|
||||
.replace(/\s|\//g, '-') // replace spaces and slashes with dashes
|
||||
.replace(/[^\p{L}\d\-]/gu, ''); // only keep letters, digits & dashes
|
||||
}
|
||||
|
||||
@@ -137,14 +137,14 @@ dialog {
|
||||
.docs-search-results__start-typing,
|
||||
.docs-search-results__no-results {
|
||||
padding: 0.75rem;
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
}
|
||||
|
||||
.docs-search-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
padding: 1rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -95,6 +95,9 @@ export class SearchDialog {
|
||||
if (!this.dialog().nativeElement.open) {
|
||||
this.dialog().nativeElement.showModal?.();
|
||||
}
|
||||
// We want to select the pre-existing text on opening
|
||||
// In order to change the search input with minimal user interaction.
|
||||
this.searchForm().focusBoundControl();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@ import {IconComponent} from '../icon/icon.component';
|
||||
class: 'docs-form-element',
|
||||
},
|
||||
})
|
||||
export class TextField implements FormValueControl<string> {
|
||||
export class TextField implements FormValueControl<string | null> {
|
||||
readonly input = viewChild.required<ElementRef<HTMLInputElement>>('inputRef');
|
||||
readonly name = input<string>('');
|
||||
readonly value = model<string>('');
|
||||
readonly value = model<string | null>(null);
|
||||
readonly placeholder = input<string | null>(null);
|
||||
readonly disabled = model<boolean>(false);
|
||||
readonly hideIcon = input<boolean>(false);
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
height: fit-content;
|
||||
|
||||
docs-icon {
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fill="var(--quaternary-contrast)"
|
||||
fill="var(--gray-400)"
|
||||
d="M3.4 22 2 20.6 8.6 14H4v-2h8v8h-2v-4.6L3.4 22ZM12 12V4h2v4.6L20.6 2 22 3.4 15.4 10H20v2h-8Z"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
.docs-example-viewer-preview {
|
||||
.docs-dark-mode & {
|
||||
color: var(--primary-contrast);
|
||||
background: var(--primary-constrast);
|
||||
background: var(--gray-900);
|
||||
}
|
||||
@media screen and (prefers-color-scheme: dark) {
|
||||
color: var(--primary-contrast);
|
||||
background: var(--primary-constrast);
|
||||
background: var(--gray-900);
|
||||
}
|
||||
.docs-light-mode & {
|
||||
background: var(--page-background);
|
||||
@@ -70,7 +70,7 @@
|
||||
cursor: pointer;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
|
||||
path {
|
||||
transition: fill 0.3s ease;
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
"name": "@angular/docs",
|
||||
"version": "0.0.0-PLACEHOLDER",
|
||||
"peerDependencies": {
|
||||
"@angular/cdk": "^21.2.0-next",
|
||||
"@angular/common": "^21.2.0-next",
|
||||
"@angular/core": "^21.2.0-next",
|
||||
"@angular/forms": "^21.2.0-next",
|
||||
"@angular/material": "^21.2.0-next",
|
||||
"@angular/platform-browser": "^21.2.0-next",
|
||||
"@angular/router": "^21.2.0-next",
|
||||
"@angular/ssr": "^21.2.0-next",
|
||||
"@angular/cdk": "^21.1.0-next",
|
||||
"@angular/common": "^21.1.0-next",
|
||||
"@angular/core": "^21.1.0-next",
|
||||
"@angular/forms": "^21.1.0-next",
|
||||
"@angular/material": "^21.1.0-next",
|
||||
"@angular/platform-browser": "^21.1.0-next",
|
||||
"@angular/router": "^21.1.0-next",
|
||||
"@angular/ssr": "^21.1.0-next",
|
||||
"algoliasearch": "^5.0.0",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
@@ -18,7 +18,7 @@
|
||||
"diff": "~8.0.0",
|
||||
"emoji-regex": "~10.6.0",
|
||||
"fflate": "^0.8.2",
|
||||
"jsdom": "~28.0.0",
|
||||
"jsdom": "~27.4.0",
|
||||
"marked": "~17.0.0",
|
||||
"mermaid": "^11.0.0",
|
||||
"shiki": "^3.0.0",
|
||||
|
||||
@@ -10,15 +10,6 @@ ts_project(
|
||||
],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "heading",
|
||||
srcs = ["heading.mts"],
|
||||
visibility = [
|
||||
"//adev/scripts/routes:__subpackages__",
|
||||
"//adev/shared-docs/pipeline:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "shiki",
|
||||
srcs = ["shiki.mts"],
|
||||
@@ -45,17 +36,3 @@ zoneless_jasmine_test(
|
||||
name = "linking_test",
|
||||
data = [":linking_test_lib"],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "heading_test_lib",
|
||||
testonly = True,
|
||||
srcs = ["test/heading.spec.mts"],
|
||||
deps = [
|
||||
":heading",
|
||||
],
|
||||
)
|
||||
|
||||
zoneless_jasmine_test(
|
||||
name = "heading_test",
|
||||
data = [":heading_test_lib"],
|
||||
)
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/*!
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extracts the ID from a heading text.
|
||||
* Supports custom ID syntax: `## My Heading {#custom-id}`
|
||||
*/
|
||||
export function getIdFromHeading(heading: string): string {
|
||||
// extract the extended markdown heading id
|
||||
// ex: ## MyHeading {# myId}
|
||||
// This is recommended in case we end up having duplicate Ids but we still want the same heading text.
|
||||
// We don't want to make Id generation stateful/too complex to handle duplicates automatically.
|
||||
const customIdRegex = /{#\s*([\w-]+)\s*}/g;
|
||||
const customId = customIdRegex.exec(heading)?.[1];
|
||||
|
||||
if (customId) {
|
||||
return customId;
|
||||
}
|
||||
|
||||
return heading
|
||||
.toLowerCase()
|
||||
.replace(/\s|\//g, '-') // replace spaces and slashes with dashes
|
||||
.replace(/[^\p{L}\d\-]/gu, ''); // only keep letters, digits & dashes
|
||||
}
|
||||
@@ -30,8 +30,6 @@ const LINK_EXEMPT = new Set([
|
||||
'Event',
|
||||
'form',
|
||||
'type',
|
||||
'Host',
|
||||
'filter',
|
||||
]);
|
||||
|
||||
export function shouldLinkSymbol(symbol: string): boolean {
|
||||
|
||||
@@ -18,7 +18,6 @@ ts_project(
|
||||
"//adev:node_modules/mermaid",
|
||||
"//adev:node_modules/playwright-core",
|
||||
"//adev:node_modules/shiki",
|
||||
"//adev/shared-docs/pipeline/shared:heading",
|
||||
"//adev/shared-docs/pipeline/shared:linking",
|
||||
"//adev/shared-docs/pipeline/shared:shiki",
|
||||
"//adev/shared-docs/pipeline/shared/regions",
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ interface DocsCardContainerToken extends Tokens.Generic {
|
||||
// Capture group 1: all attributes on the opening tag
|
||||
// Capture group 2: all content between the open and close tags
|
||||
const cardContainerRule =
|
||||
/^\s*<docs-card-container(?:\s([^>]*))?>((?:.(?!\/docs-card-container))*)<\/docs-card-container>/s;
|
||||
/^[^<]*<docs-card-container(?:\s([^>]*))?>((?:.(?!\/docs-card-container))*)<\/docs-card-container>/s;
|
||||
const headerTitleRule = /headerTitle="([^"]*)"/;
|
||||
const headerImgSrcRule = /headerImgSrc="([^"]*)"/;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ interface DocsCardToken extends Tokens.Generic {
|
||||
|
||||
// Capture group 1: all attributes on the opening tag
|
||||
// Capture group 2: all content between the open and close tags
|
||||
const cardRule = /^\s*<docs-card(?:\s([^>]*))?>((?:.(?!\/docs-card))*)<\/docs-card>/s;
|
||||
const cardRule = /^[^<]*<docs-card(?:\s([^>]*))?>((?:.(?!\/docs-card))*)<\/docs-card>/s;
|
||||
|
||||
const titleRule = /title="([^"]*)"/;
|
||||
const linkRule = /link="([^"]*)"/;
|
||||
|
||||
@@ -41,7 +41,6 @@ export const docsCodeBlockExtension = {
|
||||
const headerRule = /header\s*:\s*(['"`])([^'"`]+)\1/; // The 2nd capture matters here
|
||||
const highlightRule = /highlight\s*:\s*(.*)([^,])/;
|
||||
const hideCopyRule = /hideCopy/;
|
||||
const hideDollarRule = /hideDollar/;
|
||||
const preferRule = /\b(prefer|avoid)\b/;
|
||||
const linenumsRule = /linenums/;
|
||||
|
||||
@@ -53,7 +52,6 @@ export const docsCodeBlockExtension = {
|
||||
header: headerRule.exec(metadataStr)?.[2],
|
||||
highlight: highlightRule.exec(metadataStr)?.[1],
|
||||
hideCopy: hideCopyRule.test(metadataStr),
|
||||
hideDollar: hideDollarRule.test(metadataStr),
|
||||
style: preferRule.exec(metadataStr)?.[1] as 'prefer' | 'avoid' | undefined,
|
||||
linenums: linenumsRule.test(metadataStr),
|
||||
};
|
||||
|
||||
@@ -32,7 +32,6 @@ const visibleLinesRule = /visibleLines="([^"]*)"/;
|
||||
const regionRule = /region="([^"]*)"/;
|
||||
const previewRule = /preview/;
|
||||
const hideCodeRule = /hideCode/;
|
||||
const hideDollarRule = /hideDollar/;
|
||||
const preferRule = /\b(prefer|avoid)\b/;
|
||||
|
||||
export const docsCodeExtension = {
|
||||
@@ -53,9 +52,8 @@ export const docsCodeExtension = {
|
||||
const language = languageRule.exec(attr);
|
||||
const visibleLines = visibleLinesRule.exec(attr);
|
||||
const region = regionRule.exec(attr);
|
||||
const preview = previewRule.test(attr);
|
||||
const hideCode = hideCodeRule.test(attr);
|
||||
const hideDollar = hideDollarRule.test(attr);
|
||||
const preview = previewRule.exec(attr) ? true : false;
|
||||
const hideCode = hideCodeRule.exec(attr) ? true : false;
|
||||
const classes = classRule.exec(attr);
|
||||
const style = preferRule.exec(attr);
|
||||
|
||||
@@ -80,7 +78,6 @@ export const docsCodeExtension = {
|
||||
region: region?.[1],
|
||||
preview: preview,
|
||||
hideCode,
|
||||
hideDollar,
|
||||
style: style?.[1] as 'prefer' | 'avoid' | undefined,
|
||||
classes: classes?.[1]?.split(' '),
|
||||
};
|
||||
|
||||
@@ -39,8 +39,6 @@ export interface CodeToken extends Tokens.Generic {
|
||||
highlight?: string;
|
||||
/** Whether to hide the copy button */
|
||||
hideCopy?: boolean;
|
||||
/** Whether to hide the dollar sign in the shell code */
|
||||
hideDollar?: boolean;
|
||||
|
||||
// additional classes for the element
|
||||
classes?: string[];
|
||||
@@ -134,10 +132,6 @@ function applyContainerAttributesAndClasses(el: Element, token: CodeToken) {
|
||||
if (token.hideCopy) {
|
||||
el.setAttribute('hideCopy', 'true');
|
||||
}
|
||||
if (token.hideDollar) {
|
||||
el.setAttribute('hideDollar', 'true');
|
||||
}
|
||||
|
||||
const language = token.language;
|
||||
|
||||
if (language === 'mermaid') {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {Token, Tokens, RendererThis, TokenizerThis} from 'marked';
|
||||
import {anchorTarget} from '../../helpers.mjs';
|
||||
import {anchorTarget, isExternalLink} from '../../helpers.mjs';
|
||||
import {AdevDocsRenderer} from '../../renderer.mjs';
|
||||
|
||||
interface DocsPillToken extends Tokens.Generic {
|
||||
@@ -70,7 +70,11 @@ export const docsPillExtension = {
|
||||
|
||||
return `
|
||||
<a class="docs-pill" href="${token.href}"${targetAttr}${downloadAttr}>
|
||||
${this.parser.parseInline(token.tokens)}
|
||||
${this.parser.parseInline(token.tokens)}${
|
||||
isExternalLink(token.href)
|
||||
? '<docs-icon class="docs-icon-small">open_in_new</docs-icon>'
|
||||
: ''
|
||||
}
|
||||
</a>
|
||||
`;
|
||||
},
|
||||
|
||||
+2
-37
@@ -1,39 +1,4 @@
|
||||
Introductory paragraph that should be preserved before any card containers.
|
||||
|
||||
## First Section
|
||||
|
||||
This section contains important information about the feature status.
|
||||
|
||||
### Available features
|
||||
|
||||
- Feature one
|
||||
- Feature two
|
||||
- Feature three
|
||||
|
||||
### In progress
|
||||
|
||||
The following items are currently being developed:
|
||||
|
||||
1. Item A with description
|
||||
2. Item B with description
|
||||
|
||||
<docs-card-container>
|
||||
<docs-card title="Card One"></docs-card>
|
||||
<docs-card title="Card Two"></docs-card>
|
||||
<docs-card></docs-card>
|
||||
<docs-card></docs-card>
|
||||
</docs-card-container>
|
||||
|
||||
### Additional context
|
||||
|
||||
More text after the first card container that should also be preserved.
|
||||
|
||||
## Second Section
|
||||
|
||||
Another paragraph before the second card container.
|
||||
|
||||
<docs-card-container>
|
||||
<docs-card title="Card Three"></docs-card>
|
||||
</docs-card-container>
|
||||
|
||||
## Final Section
|
||||
|
||||
Concluding remarks at the end of the document.
|
||||
|
||||
+4
-54
@@ -20,60 +20,10 @@ describe('markdown to html', () => {
|
||||
markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext));
|
||||
});
|
||||
|
||||
it('creates multiple card containers with correct card counts', () => {
|
||||
const containers = markdownDocument.querySelectorAll('.docs-card-grid');
|
||||
it('creates card containers containing multiple cards', () => {
|
||||
const containerEl = markdownDocument.querySelector('.docs-card-grid');
|
||||
|
||||
expect(containers.length).toBe(2);
|
||||
expect(containers[0].children.length).toBe(2);
|
||||
expect(containers[1].children.length).toBe(1);
|
||||
});
|
||||
|
||||
it('preserves all h2 section headings', () => {
|
||||
const h2Elements = markdownDocument.querySelectorAll('h2');
|
||||
|
||||
expect(h2Elements.length).toBe(3);
|
||||
expect(h2Elements[0].textContent).toContain('First Section');
|
||||
expect(h2Elements[1].textContent).toContain('Second Section');
|
||||
expect(h2Elements[2].textContent).toContain('Final Section');
|
||||
});
|
||||
|
||||
it('preserves all h3 subsection headings outside card containers', () => {
|
||||
// Card titles also render as h3, so we filter to only h3s not inside card containers
|
||||
const allH3s = Array.from(markdownDocument.querySelectorAll('h3'));
|
||||
const sectionH3s = allH3s.filter((h3) => !h3.closest('.docs-card-grid'));
|
||||
|
||||
expect(sectionH3s.length).toBe(3);
|
||||
expect(sectionH3s[0].textContent).toContain('Available features');
|
||||
expect(sectionH3s[1].textContent).toContain('In progress');
|
||||
expect(sectionH3s[2].textContent).toContain('Additional context');
|
||||
});
|
||||
|
||||
it('preserves unordered lists before card containers', () => {
|
||||
const ulElements = markdownDocument.querySelectorAll('ul');
|
||||
|
||||
expect(ulElements.length).toBeGreaterThanOrEqual(1);
|
||||
expect(ulElements[0].children.length).toBe(3);
|
||||
expect(ulElements[0].textContent).toContain('Feature one');
|
||||
});
|
||||
|
||||
it('preserves ordered lists before card containers', () => {
|
||||
const olElements = markdownDocument.querySelectorAll('ol');
|
||||
|
||||
expect(olElements.length).toBe(1);
|
||||
expect(olElements[0].children.length).toBe(2);
|
||||
expect(olElements[0].textContent).toContain('Item A');
|
||||
});
|
||||
|
||||
it('preserves paragraphs throughout the document', () => {
|
||||
const paragraphs = markdownDocument.querySelectorAll('p');
|
||||
|
||||
expect(paragraphs.length).toBeGreaterThanOrEqual(5);
|
||||
|
||||
const paragraphTexts = Array.from(paragraphs).map((p) => p.textContent);
|
||||
expect(paragraphTexts.some((t) => t?.includes('Introductory paragraph'))).toBeTrue();
|
||||
expect(paragraphTexts.some((t) => t?.includes('important information'))).toBeTrue();
|
||||
expect(paragraphTexts.some((t) => t?.includes('More text after'))).toBeTrue();
|
||||
expect(paragraphTexts.some((t) => t?.includes('Another paragraph'))).toBeTrue();
|
||||
expect(paragraphTexts.some((t) => t?.includes('Concluding remarks'))).toBeTrue();
|
||||
expect(containerEl!.children.length).toBe(2);
|
||||
expect(containerEl!.classList.contains('docs-card-grid')).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,7 +11,3 @@ this is a code block
|
||||
```
|
||||
code block without language
|
||||
```
|
||||
|
||||
```shell {hideDollar}
|
||||
echo "hello"
|
||||
```
|
||||
|
||||
+2
-7
@@ -27,10 +27,10 @@ describe('markdown to html', () => {
|
||||
expect(codeBlock?.textContent?.trim()).toBe('this is a code block');
|
||||
});
|
||||
|
||||
it('should parse all 4 code blocks', () => {
|
||||
it('should parse all 3 code blocks', () => {
|
||||
const codeBlocks = markdownDocument.querySelectorAll('.docs-code');
|
||||
|
||||
expect(codeBlocks.length).toBe(4);
|
||||
expect(codeBlocks.length).toBe(3);
|
||||
});
|
||||
|
||||
it('should deindent code blocks correctly', () => {
|
||||
@@ -42,9 +42,4 @@ describe('markdown to html', () => {
|
||||
const codeBlock = markdownDocument.querySelectorAll('.docs-code')[2];
|
||||
expect(codeBlock).toBeDefined();
|
||||
});
|
||||
|
||||
it('should parse the hideDollar attribute', () => {
|
||||
const codeBlock = markdownDocument.querySelectorAll('.docs-code')[3];
|
||||
expect(codeBlock.getAttribute('hideDollar')).toBe('true');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,5 +12,3 @@ const form = {
|
||||
state: ['']
|
||||
};
|
||||
</docs-code>
|
||||
|
||||
<docs-code hideDollar code="echo 'hello world'" />
|
||||
|
||||
@@ -52,9 +52,4 @@ describe('markdown to html', () => {
|
||||
const codeBlock = markdownDocument.querySelectorAll('code')[4];
|
||||
expect(codeBlock?.innerHTML).not.toContain('<a href="/api/animations/state">state</a>');
|
||||
});
|
||||
|
||||
it('should parse the hideDollar attribute', () => {
|
||||
const codeBlock = markdownDocument.querySelectorAll('.docs-code')[5];
|
||||
expect(codeBlock.getAttribute('hideDollar')).toBe('true');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,10 +25,11 @@ describe('markdown to html', () => {
|
||||
expect(samePageEl.textContent?.trim()).toBe('Same Page');
|
||||
});
|
||||
|
||||
it('should render external links with _blank target', () => {
|
||||
it('should render external links with _blank target and iconography', () => {
|
||||
const samePageEl = markdownDocument.querySelectorAll('a.docs-pill')[1];
|
||||
expect(samePageEl.getAttribute('target')).toBe('_blank');
|
||||
expect(samePageEl.textContent?.trim()).toBe('External Page');
|
||||
expect(samePageEl.textContent?.trim()).toContain('External Page');
|
||||
expect(samePageEl.querySelector('docs-icon')?.textContent).toBe('open_in_new');
|
||||
});
|
||||
|
||||
it('should render internal links that are relative paths', () => {
|
||||
|
||||
@@ -104,10 +104,6 @@ describe('markdown to html', () => {
|
||||
|
||||
expect(h2HeaderId).toBe('my-custom-id');
|
||||
expect(h2AnchorHref).toBe(`#${h2HeaderId}`);
|
||||
|
||||
// Verify that the custom ID syntax is removed from the displayed text
|
||||
expect(h2Anchor?.textContent?.trim()).toBe('My heading');
|
||||
expect(h2Anchor?.textContent).not.toContain('{#');
|
||||
});
|
||||
|
||||
it('should be able to parse heading with a valid tag in a code block', () => {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
import {Tokens} from 'marked';
|
||||
import {AdevDocsRenderer} from '../renderer.mjs';
|
||||
import {getIdFromHeading} from '../../heading.mjs';
|
||||
|
||||
export function headingRender(
|
||||
this: AdevDocsRenderer,
|
||||
@@ -26,11 +25,16 @@ export function headingRender(
|
||||
`;
|
||||
}
|
||||
|
||||
const link = getIdFromHeading(headingText);
|
||||
// extract the extended markdown heading id
|
||||
// ex: ## MyHeading {# myId}
|
||||
// This is recommended in case we end up having duplicate Ids but we still want the same heading text.
|
||||
// We don't want to make Id generation stateful/too complex to handle duplicates automatically.
|
||||
const customIdRegex = /{#\s*([\w-]+)\s*}/g;
|
||||
const customId = customIdRegex.exec(headingText)?.[1];
|
||||
|
||||
// Replace code backticks and remove custom ID syntax from the displayed label
|
||||
let label = parsedText.replace(/`(.*?)`/g, '<code>$1</code>');
|
||||
label = label.replace(/{#\s*[\w-]+\s*}/g, '').trim();
|
||||
const link = customId ?? getIdFromHeading(headingText);
|
||||
|
||||
const label = parsedText.replace(/`(.*?)`/g, '<code>$1</code>');
|
||||
const normalizedLabel = label.replace(/<\/?code>/g, '');
|
||||
|
||||
return `
|
||||
@@ -61,3 +65,10 @@ export function getPageTitle(text: string, filePath?: string): string {
|
||||
}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function getIdFromHeading(heading: string): string {
|
||||
return heading
|
||||
.toLowerCase()
|
||||
.replace(/\s|\//g, '-') // replace spaces and slashes with dashes
|
||||
.replace(/[^\p{L}\d\-]/gu, ''); // only keep letters, digits & dashes
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/*!
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {getIdFromHeading} from '../heading.mjs';
|
||||
|
||||
describe('getIdFromHeading', () => {
|
||||
it('should generate id from simple text', () => {
|
||||
expect(getIdFromHeading('My Heading')).toBe('my-heading');
|
||||
});
|
||||
|
||||
it('should generate id from text with special characters', () => {
|
||||
expect(getIdFromHeading('Step 2 - Add component')).toBe('step-2---add-component');
|
||||
});
|
||||
|
||||
it('should extract custom id when present', () => {
|
||||
expect(getIdFromHeading('My Heading {#custom-id}')).toBe('custom-id');
|
||||
});
|
||||
|
||||
it('should extract custom id ignoring surrounding spaces', () => {
|
||||
expect(getIdFromHeading('My Heading {# custom-id }')).toBe('custom-id');
|
||||
});
|
||||
|
||||
it('should prioritize custom id over text content', () => {
|
||||
expect(getIdFromHeading('Duplicate Heading {#unique-id}')).toBe('unique-id');
|
||||
});
|
||||
});
|
||||
@@ -5,19 +5,6 @@
|
||||
// as well as better human-readability
|
||||
// --> https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch
|
||||
|
||||
// Grays
|
||||
$gray-1000: oklch(16.93% 0.004 285.95); // #0f0f11
|
||||
$gray-900: oklch(19.37% 0.006 300.98); // #151417
|
||||
$gray-800: oklch(25.16% 0.008 308.11); // #232125
|
||||
$gray-700: oklch(36.98% 0.014 302.71); // #413e46
|
||||
$gray-600: oklch(44% 0.019 306.08); // #55505b
|
||||
$gray-500: oklch(54.84% 0.023 304.99); // #746e7c
|
||||
$gray-400: oklch(70.9% 0.015 304.04); // #a39fa9
|
||||
$gray-300: oklch(84.01% 0.009 308.34); // #ccc9cf
|
||||
$gray-200: oklch(91.75% 0.004 301.42); // #e4e3e6
|
||||
$gray-100: oklch(97.12% 0.002 325.59); // #f6f5f6
|
||||
$gray-50: oklch(98.81% 0 0); // #fbfbfb
|
||||
|
||||
@mixin root-definitions() {
|
||||
// PRIMITIVES
|
||||
// Colors
|
||||
@@ -60,6 +47,19 @@ $gray-50: oklch(98.81% 0 0); // #fbfbfb
|
||||
--symbolic-brown: oklch(49.06% 0.128 46.41); // #994411
|
||||
--symbolic-lime: oklch(70.33% 0.2078857836035299 135.66843631046476); // #5dba00
|
||||
|
||||
// Grays
|
||||
--gray-1000: oklch(16.93% 0.004 285.95); // #0f0f11
|
||||
--gray-900: oklch(19.37% 0.006 300.98); // #151417
|
||||
--gray-800: oklch(25.16% 0.008 308.11); // #232125
|
||||
--gray-700: oklch(36.98% 0.014 302.71); // #413e46
|
||||
--gray-600: oklch(44% 0.019 306.08); // #55505b
|
||||
--gray-500: oklch(54.84% 0.023 304.99); // #746e7c
|
||||
--gray-400: oklch(70.9% 0.015 304.04); // #a39fa9
|
||||
--gray-300: oklch(84.01% 0.009 308.34); // #ccc9cf
|
||||
--gray-200: oklch(91.75% 0.004 301.42); // #e4e3e6
|
||||
--gray-100: oklch(97.12% 0.002 325.59); // #f6f5f6
|
||||
--gray-50: oklch(98.81% 0 0); // #fbfbfb
|
||||
|
||||
// GRADIENTS
|
||||
--red-to-pink-horizontal-gradient: linear-gradient(
|
||||
90deg,
|
||||
@@ -124,7 +124,7 @@ $gray-50: oklch(98.81% 0 0); // #fbfbfb
|
||||
--pink-to-white-horizontal-gradient: linear-gradient(
|
||||
90deg,
|
||||
var(--vivid-pink) 0%,
|
||||
#{$gray-200} 60%
|
||||
var(--gray-200) 60%
|
||||
);
|
||||
|
||||
--light-pink-to-light-purple-horizontal-gradient: linear-gradient(
|
||||
@@ -166,7 +166,7 @@ $gray-50: oklch(98.81% 0 0); // #fbfbfb
|
||||
--black-to-gray-vertical-gradient: linear-gradient(
|
||||
0deg,
|
||||
var(--primary-contrast) 0%,
|
||||
#{$gray-400} 100%
|
||||
var(--gray-400) 100%
|
||||
);
|
||||
|
||||
--red-to-pink-vertical-gradient: linear-gradient(0deg, var(--hot-red) 0%, var(--vivid-pink) 100%);
|
||||
@@ -217,35 +217,35 @@ $gray-50: oklch(98.81% 0 0); // #fbfbfb
|
||||
// LIGHT MODE is default
|
||||
// contrast - light mode
|
||||
--full-contrast: black;
|
||||
--primary-contrast: #{$gray-900};
|
||||
--secondary-contrast: #{$gray-800};
|
||||
--tertiary-contrast: #{$gray-700};
|
||||
--quaternary-contrast: #{$gray-500};
|
||||
--quinary-contrast: #{$gray-300};
|
||||
--senary-contrast: #{$gray-200};
|
||||
--septenary-contrast: #{$gray-100};
|
||||
--octonary-contrast: #{$gray-50};
|
||||
--primary-contrast: var(--gray-900);
|
||||
--secondary-contrast: var(--gray-800);
|
||||
--tertiary-contrast: var(--gray-700);
|
||||
--quaternary-contrast: var(--gray-500);
|
||||
--quinary-contrast: var(--gray-300);
|
||||
--senary-contrast: var(--gray-200);
|
||||
--septenary-contrast: var(--gray-100);
|
||||
--octonary-contrast: var(--gray-50);
|
||||
--page-background: white;
|
||||
|
||||
// Home page
|
||||
// for the "unfilled" portion of the word that hasn't
|
||||
// been highlighted by the gradient
|
||||
--gray-unfilled: #{$gray-400};
|
||||
--webgl-page-background: var(var(--page-background)) --webgl-gray-unfilled: #{$gray-400};
|
||||
--gray-unfilled: var(--gray-400);
|
||||
--webgl-page-background: var(var(--page-background)) --webgl-gray-unfilled: var(--gray-400);
|
||||
}
|
||||
|
||||
@mixin dark-mode-definitions() {
|
||||
// Contrasts
|
||||
--full-contrast: white;
|
||||
--primary-contrast: #{$gray-50};
|
||||
--secondary-contrast: #{$gray-300};
|
||||
--tertiary-contrast: #{$gray-300};
|
||||
--quaternary-contrast: #{$gray-400};
|
||||
--quinary-contrast: #{$gray-500};
|
||||
--senary-contrast: #{$gray-700};
|
||||
--septenary-contrast: #{$gray-800};
|
||||
--octonary-contrast: #{$gray-900};
|
||||
--page-background: #{$gray-1000};
|
||||
--primary-contrast: var(--gray-50);
|
||||
--secondary-contrast: var(--gray-300);
|
||||
--tertiary-contrast: var(--gray-300);
|
||||
--quaternary-contrast: var(--gray-400);
|
||||
--quinary-contrast: var(--gray-500);
|
||||
--senary-contrast: var(--gray-700);
|
||||
--septenary-contrast: var(--gray-800);
|
||||
--octonary-contrast: var(--gray-900);
|
||||
--page-background: var(--gray-1000);
|
||||
|
||||
--bright-blue: color-mix(in srgb, oklch(51.01% 0.274 263.83), var(--full-contrast) 60%);
|
||||
--indigo-blue: color-mix(in srgb, oklch(51.64% 0.229 281.65), var(--full-contrast) 70%);
|
||||
@@ -260,7 +260,7 @@ $gray-50: oklch(98.81% 0 0); // #fbfbfb
|
||||
--orange-red: color-mix(in srgb, oklch(63.32% 0.24 31.68), var(--full-contrast) 60%);
|
||||
--super-green: color-mix(in srgb, oklch(79.12% 0.257 155.13), var(--full-contrast) 70%);
|
||||
--light-vivid-pink-to-light-electric-violet-horizontal-gradient:
|
||||
linear-gradient(hsl(from #{$gray-1000} h s l / 0.9), hsl(from #{$gray-1000} h s l / 0.9)),
|
||||
linear-gradient(hsl(from var(--gray-1000) h s l / 0.9), hsl(from var(--gray-1000) h s l / 0.9)),
|
||||
linear-gradient(
|
||||
hsl(from var(--full-contrast) h s l / 0.2),
|
||||
hsl(from var(--full-contrast) h s l / 0.2)
|
||||
@@ -319,9 +319,9 @@ $gray-50: oklch(98.81% 0 0); // #fbfbfb
|
||||
);
|
||||
|
||||
// Home page - dark mode
|
||||
--gray-unfilled: #{$gray-700};
|
||||
--webgl-page-background: #{$gray-1000};
|
||||
--webgl-gray-unfilled: #{$gray-700};
|
||||
--gray-unfilled: var(--gray-700);
|
||||
--webgl-page-background: var(--gray-1000);
|
||||
--webgl-gray-unfilled: var(--gray-700);
|
||||
|
||||
.docs-toggle {
|
||||
input {
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
}
|
||||
|
||||
.docs-reference-category {
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.4rem;
|
||||
|
||||
@@ -6,66 +6,68 @@
|
||||
border-radius: 0.25rem;
|
||||
margin: 1rem 0;
|
||||
|
||||
.docs-card-container-header {
|
||||
align-items: flex-end;
|
||||
border-bottom: 1px solid var(--senary-contrast);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.docs-card-container-header {
|
||||
align-items: flex-end;
|
||||
border-bottom: 1px solid var(--senary-contrast);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
h2 {
|
||||
padding: 2.5rem 1rem 2.5rem 2.5rem;
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.theme-fill-bg {
|
||||
fill: var(--page-background);
|
||||
stroke: var(--primary-contrast);
|
||||
}
|
||||
.theme-fill-accent-bg {
|
||||
fill: var(--septenary-contrast);
|
||||
stroke: var(--primary-contrast);
|
||||
}
|
||||
.theme-stroke-primary {
|
||||
stroke: var(--primary-contrast);
|
||||
}
|
||||
.theme-fill-primary {
|
||||
fill: var(--primary-contrast);
|
||||
}
|
||||
.theme-fill-secondary {
|
||||
fill: var(--octonary-contrast);
|
||||
}
|
||||
.theme-stroke-accent {
|
||||
stroke: var(--vivid-pink);
|
||||
}
|
||||
.theme-fill-accent {
|
||||
fill: var(--vivid-pink);
|
||||
stroke: var(--primary-contrast);
|
||||
}
|
||||
.theme-stroke-secondary {
|
||||
stroke: var(--senary-contrast);
|
||||
}
|
||||
.theme-fill-secondary {
|
||||
fill: var(--senary-contrast);
|
||||
}
|
||||
|
||||
.header-img {
|
||||
margin-top: 5px;
|
||||
overflow: hidden;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill-opacity: 1;
|
||||
|
||||
@container header (max-width: 550px) {
|
||||
display: none;
|
||||
h2 {
|
||||
padding: 2.5rem 1rem 2.5rem 2.5rem;
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
rect {
|
||||
fill: transparent;
|
||||
.theme-fill-bg {
|
||||
fill: var(--page-background);
|
||||
stroke: var(--primary-contrast);
|
||||
}
|
||||
.theme-fill-accent-bg {
|
||||
fill: var(--septenary-contrast);
|
||||
stroke: var(--primary-contrast);
|
||||
}
|
||||
.theme-stroke-primary {
|
||||
stroke: var(--primary-contrast);
|
||||
}
|
||||
.theme-fill-primary {
|
||||
fill: var(--primary-contrast);
|
||||
}
|
||||
.theme-fill-secondary {
|
||||
fill: var(--octonary-contrast);
|
||||
}
|
||||
.theme-stroke-accent {
|
||||
stroke: var(--vivid-pink);
|
||||
}
|
||||
.theme-fill-accent {
|
||||
fill: var(--vivid-pink);
|
||||
stroke: var(--primary-contrast);
|
||||
}
|
||||
.theme-stroke-secondary {
|
||||
stroke: var(--senary-contrast);
|
||||
}
|
||||
.theme-fill-secondary {
|
||||
fill: var(--senary-contrast);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.header-img {
|
||||
margin-top: 5px;
|
||||
overflow: hidden;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill-opacity: 1;
|
||||
|
||||
@container header (max-width: 550px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
rect {
|
||||
fill: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.docs-card-container-content {
|
||||
margin: 1rem;
|
||||
@@ -212,10 +214,7 @@
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
top: 0; right: 0; bottom: 0; left: 0;
|
||||
z-index: -1;
|
||||
margin: -1px;
|
||||
border-radius: inherit;
|
||||
@@ -224,7 +223,7 @@
|
||||
|
||||
.docs-nav-card-title {
|
||||
background: var(--pink-to-highlight-to-purple-to-blue-horizontal-gradient);
|
||||
padding: 1.5rem 1.5rem 0.5rem;
|
||||
padding: 1.5rem 1.5rem .5rem;
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
@@ -265,11 +264,11 @@
|
||||
gap: 8px;
|
||||
|
||||
h3 {
|
||||
margin-block-end: 0.5rem;
|
||||
margin-block-end: .5rem;
|
||||
}
|
||||
|
||||
svg path {
|
||||
fill: var(--quaternary-contrast);
|
||||
fill: var(--gray-400);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -204,24 +204,15 @@ $code-font-size: 0.875rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&:not([hideDollar]) {
|
||||
.shiki {
|
||||
.line {
|
||||
&::before {
|
||||
content: '$';
|
||||
padding-inline-end: 0.5rem;
|
||||
}
|
||||
}
|
||||
.shiki .line {
|
||||
&::before {
|
||||
content: '$';
|
||||
padding-inline-end: 0.5rem;
|
||||
}
|
||||
}
|
||||
display: block;
|
||||
|
||||
.shiki {
|
||||
.line {
|
||||
display: block;
|
||||
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,7 +239,7 @@ $code-font-size: 0.875rem;
|
||||
opacity: 1;
|
||||
path {
|
||||
transition: fill 0.3s ease;
|
||||
fill: var(--quaternary-contrast);
|
||||
fill: var(--gray-400);
|
||||
}
|
||||
}
|
||||
.docs-check {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// Pill
|
||||
@use './../links' as links;
|
||||
|
||||
@mixin docs-pill() {
|
||||
.docs-pill {
|
||||
@@ -28,11 +27,8 @@
|
||||
background: color-mix(in srgb, var(--pill-accent) 15%, transparent);
|
||||
}
|
||||
|
||||
// External link icon
|
||||
&[href^='http:'],
|
||||
&[href^='https:'] {
|
||||
margin-left: 0rem;
|
||||
@include links.external-link-with-icon();
|
||||
.docs-icon-small {
|
||||
margin-inline-start: 0.25rem;
|
||||
}
|
||||
|
||||
.docs-dark-mode & {
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
backdrop-filter: blur(2px);
|
||||
background-color: color-mix(in srgb, var(--page-background) 5%, transparent);
|
||||
background-color: color-mix(in srgb, var(--gray-1000) 5%, transparent);
|
||||
z-index: 50;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
||||
@@ -95,28 +95,21 @@
|
||||
<div>
|
||||
<h2>Community translations</h2>
|
||||
<ul>
|
||||
<!-- Sorted using Unicode Collation Algorithm (UCA) -->
|
||||
<li>
|
||||
<a href="https://angular.az/" title="Azərbaycanca">Azərbaycanca</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://angular-docs.tr/" title="Türkçe">Türkçe</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://angular-docs.ru/" title="Русский">Русский</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://angular.kr/" title="한국어">한국어</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://angular.jp/" title="日本語版">日本語版</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://angular.cn/" title="简体中文版">简体中文版</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://dev.angular.tw/" title="正體中文版">正體中文版</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://angular.jp/" title="日本語版">日本語版</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://angular.kr/" title="한국어">한국어</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://angular-docs.ru/" title="Русский">Русский</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
background-color 0.3s ease,
|
||||
border-color 0.3s ease;
|
||||
height: 100dvh;
|
||||
padding-block-start: 1rem;
|
||||
padding-block-end: 2rem;
|
||||
box-sizing: border-box;
|
||||
// Add a subtle border for the home page
|
||||
@@ -107,19 +108,6 @@
|
||||
color-mix(in srgb, var(--electric-violet), transparent 70%) 25%,
|
||||
color-mix(in srgb, var(--bright-blue), transparent 60%) 90%
|
||||
);
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
opacity: 0.8;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--octonary-contrast);
|
||||
z-index: -1;
|
||||
}
|
||||
.adev-version-button {
|
||||
border: 1px solid var(--quinary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
&.adev-nav-primary--deprecated {
|
||||
@@ -165,7 +153,6 @@
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-block-start: 1rem;
|
||||
|
||||
@include mq.for-tablet {
|
||||
flex-direction: row;
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
.docs-delete-file,
|
||||
.docs-rename-file {
|
||||
docs-icon {
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
transition: color 0.3s ease;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
@@ -270,7 +270,7 @@
|
||||
border-inline-start: 1px solid var(--senary-contrast);
|
||||
|
||||
docs-icon {
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
transition: color 0.3s ease;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ $width-breakpoint: 950px;
|
||||
z-index: var(--z-index-content);
|
||||
|
||||
docs-icon {
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
margin: auto;
|
||||
font-size: 1.3rem;
|
||||
transition: color 0.3s ease;
|
||||
@@ -120,7 +120,7 @@ $width-breakpoint: 950px;
|
||||
|
||||
&:disabled {
|
||||
docs-icon {
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
.docs-dark-mode & {
|
||||
.adev-embedded-editor-preview-container {
|
||||
background: var(--primary-constrast);
|
||||
background: var(--gray-100);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*!
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {Injectable, OnDestroy} from '@angular/core';
|
||||
import angularHtml from '@shikijs/langs/angular-html';
|
||||
import angularTs from '@shikijs/langs/angular-ts';
|
||||
import githubDark from '@shikijs/themes/github-dark';
|
||||
import githubLight from '@shikijs/themes/github-light';
|
||||
import {CodeToHastOptions, createHighlighterCoreSync, HighlighterCore} from 'shiki/core';
|
||||
import {createOnigurumaEngine} from 'shiki/engine/oniguruma';
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class CodeHighligher implements OnDestroy {
|
||||
private cachedHighligher: HighlighterCore | undefined;
|
||||
|
||||
async codeToHtml(code: string, options: CodeToHastOptions): Promise<string> {
|
||||
const highlighter = await this.getHighlighter();
|
||||
return highlighter.codeToHtml(code, options);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.cachedHighligher?.dispose();
|
||||
}
|
||||
|
||||
private async getHighlighter() {
|
||||
if (!this.cachedHighligher) {
|
||||
const engine = await createOnigurumaEngine(import('shiki/wasm'));
|
||||
this.cachedHighligher = createHighlighterCoreSync({
|
||||
themes: [githubLight, githubDark],
|
||||
langs: [angularTs, angularHtml],
|
||||
engine,
|
||||
});
|
||||
}
|
||||
|
||||
return this.cachedHighligher;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*!
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {AsyncPipe} from '@angular/common';
|
||||
import {ChangeDetectionStrategy, Component, computed, inject, input} from '@angular/core';
|
||||
import {DomSanitizer} from '@angular/platform-browser';
|
||||
import {ThemeManager} from '../../../../core/services/theme-manager.service';
|
||||
import {CodeHighligher} from '../../code-highlighting/code-highlighter';
|
||||
|
||||
@Component({
|
||||
selector: 'adev-code-block',
|
||||
template: `<pre><code [innerHTML]="highlightedCode() | async"></code></pre>`,
|
||||
imports: [AsyncPipe],
|
||||
styles: `
|
||||
::ng-deep pre {
|
||||
margin: 0;
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CodeBlock {
|
||||
codeHighlighter = inject(CodeHighligher);
|
||||
code = input.required<string>();
|
||||
language = input<'angular-html' | 'angular-ts'>('angular-ts');
|
||||
sanitizer = inject(DomSanitizer);
|
||||
theme = inject(ThemeManager);
|
||||
|
||||
highlightedCode = computed(() => {
|
||||
return this.codeHighlighter
|
||||
.codeToHtml(this.code(), {
|
||||
cssVariablePrefix: '--shiki-',
|
||||
lang: this.language(),
|
||||
theme: this.theme.theme() === 'light' ? 'github-light' : 'github-dark',
|
||||
})
|
||||
.then((hightlightedHtml) => {
|
||||
return this.sanitizer.bypassSecurityTrustHtml(hightlightedHtml);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<div class="two-column-step">
|
||||
<div class="step-description">
|
||||
<div class="header">Control Flow</div>
|
||||
<div class="description">
|
||||
Angular's new control flow syntax makes templates easier to write and understand.
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="docs-primary-btn"
|
||||
[attr.text]="'Learn more about Control Flow'"
|
||||
routerLink="/guide/templates/control-flow"
|
||||
>
|
||||
Learn more about Control Flow
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="step-code">
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>my-template.html</span>
|
||||
<span class="copy-icon"></span>
|
||||
</div>
|
||||
|
||||
<adev-code-block [code]="Example" language="angular-html" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,85 +0,0 @@
|
||||
@use '@angular/docs/styles/media-queries' as mq;
|
||||
|
||||
.two-column-step {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--card-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.5rem;
|
||||
padding: 2rem;
|
||||
|
||||
@include mq.for-tablet-down {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
@include mq.for-phone-only {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.step-description {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
|
||||
.header {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.6;
|
||||
color: var(--secondary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
.step-code {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
min-width: 0;
|
||||
|
||||
.code-block {
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
|
||||
.code-header {
|
||||
display: flex;
|
||||
padding: 0.75rem;
|
||||
background: var(--subtle-purple);
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
transition: background 0.3s ease;
|
||||
|
||||
& > span {
|
||||
background-image: var(--purple-to-blue-horizontal-gradient);
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.4rem;
|
||||
letter-spacing: -0.00875rem;
|
||||
margin: 0;
|
||||
word-wrap: break-word;
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
margin: 0;
|
||||
color: #a9b7c6;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*!
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {CodeBlock} from '../code-block/code-block';
|
||||
|
||||
@Component({
|
||||
selector: 'adev-control-flow-example',
|
||||
imports: [RouterLink, CodeBlock],
|
||||
templateUrl: './control-flow-example.html',
|
||||
styleUrls: ['./control-flow-example.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ControlFlowExample {
|
||||
Example = example;
|
||||
}
|
||||
|
||||
const example = `
|
||||
@if(meal() === 'burger') {
|
||||
<p>You selected a burger!</p>
|
||||
} @else if(lang meal === 'pizza') {
|
||||
<p>You selected a pizza!</p>
|
||||
} @else {
|
||||
<p>Please select a meal.</p>
|
||||
}
|
||||
|
||||
@for(item of ShoppingList; track $index) {
|
||||
<p>{{ item }}</p>
|
||||
}
|
||||
|
||||
@switch(user.role) {
|
||||
@case('user') {
|
||||
<p>Welcome, {{user.name}}</p>
|
||||
}
|
||||
@case('moderator')
|
||||
@case('admin') {
|
||||
<p>Welcome</p>
|
||||
}
|
||||
|
||||
@default {
|
||||
<p>Welcome, guest!</p>
|
||||
}
|
||||
}
|
||||
`.trim();
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
<div class="two-column-step">
|
||||
<div class="step-description">
|
||||
<div class="header">Deferrable Views</div>
|
||||
<div class="description">
|
||||
Deferrable views (also known as <code>@defer</code> blocks) reduce the initial bundle size
|
||||
of your application by deferring the loading of code that is not strictly necessary for the
|
||||
initial rendering of a page.
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="docs-primary-btn"
|
||||
[attr.text]="'Learn more about deferred loading'"
|
||||
routerLink="/guide/templates/defer"
|
||||
>
|
||||
Learn more about deferred loading
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="step-code">
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>data-visualization-page.html</span>
|
||||
<span class="copy-icon"></span>
|
||||
</div>
|
||||
|
||||
<adev-code-block [code]="exampleHtml" language="angular-html" />
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>data-visualization-page.ts</span>
|
||||
<span class="copy-icon"></span>
|
||||
</div>
|
||||
|
||||
<adev-code-block [code]="exampleTs" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
@use '@angular/docs/styles/media-queries' as mq;
|
||||
|
||||
.two-column-step {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--card-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.5rem;
|
||||
padding: 2rem;
|
||||
|
||||
@include mq.for-tablet-down {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
@include mq.for-phone-only {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.step-description {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
|
||||
.header {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.6;
|
||||
color: var(--secondary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
.step-code {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
min-width: 0;
|
||||
|
||||
.code-block {
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
overflow: auto;
|
||||
|
||||
.code-header {
|
||||
display: flex;
|
||||
padding: 0.75rem;
|
||||
background: var(--subtle-purple);
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
transition: background 0.3s ease;
|
||||
|
||||
& > span {
|
||||
background-image: var(--purple-to-blue-horizontal-gradient);
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.4rem;
|
||||
letter-spacing: -0.00875rem;
|
||||
margin: 0;
|
||||
word-wrap: break-word;
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
margin: 0;
|
||||
color: #a9b7c6;
|
||||
}
|
||||
}
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/*!
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {CodeBlock} from '../code-block/code-block';
|
||||
|
||||
@Component({
|
||||
selector: 'adev-defer-example',
|
||||
imports: [RouterLink, CodeBlock],
|
||||
templateUrl: './deferrable-views-example.html',
|
||||
styleUrls: ['./deferrable-views-example.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DeferrableViewsExample {
|
||||
exampleHtml = exampleHtml;
|
||||
exampleTs = exampleTs;
|
||||
}
|
||||
|
||||
const exampleTs = `
|
||||
@Component({
|
||||
// importing the component that will be loaded lazily
|
||||
imports: [DataVisualization],
|
||||
})
|
||||
export class DataVisualizationPage {
|
||||
dataService = inject(DataService);
|
||||
dataSet = this.dataService.getData();
|
||||
}
|
||||
`.trim();
|
||||
|
||||
const exampleHtml = `
|
||||
<section>
|
||||
<h2>Data visualization</h2>
|
||||
@defer {
|
||||
<!-- lazy loading a heavy component -->
|
||||
<app-data-visualization [data]="dataSet">
|
||||
}
|
||||
</section>
|
||||
`.trim();
|
||||
@@ -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.dev/license
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
DestroyRef,
|
||||
EnvironmentInjector,
|
||||
inject,
|
||||
input,
|
||||
} from '@angular/core';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {forkJoin, switchMap} from 'rxjs';
|
||||
|
||||
import {
|
||||
EmbeddedEditor,
|
||||
injectEmbeddedTutorialManager,
|
||||
injectNodeRuntimeSandbox,
|
||||
} from '../../../editor';
|
||||
|
||||
@Component({
|
||||
selector: 'adev-code-editor',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [EmbeddedEditor],
|
||||
template: `<embedded-editor />`,
|
||||
})
|
||||
export class CodeEditorComponent {
|
||||
private readonly cdRef = inject(ChangeDetectorRef);
|
||||
private readonly environmentInjector = inject(EnvironmentInjector);
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
readonly tutorialFiles = input.required<string>();
|
||||
|
||||
constructor() {
|
||||
this.loadEmbeddedEditor();
|
||||
}
|
||||
|
||||
private loadEmbeddedEditor() {
|
||||
// If using `async-await`, `this` will be captured until the function is executed
|
||||
// and completed, which can lead to a memory leak if the user navigates away from
|
||||
// this component to another page.
|
||||
forkJoin([
|
||||
injectNodeRuntimeSandbox(this.environmentInjector),
|
||||
injectEmbeddedTutorialManager(this.environmentInjector),
|
||||
])
|
||||
.pipe(
|
||||
switchMap(([nodeRuntimeSandbox, embeddedTutorialManager]) =>
|
||||
embeddedTutorialManager
|
||||
.fetchAndSetTutorialFiles(this.tutorialFiles())
|
||||
.then(() => nodeRuntimeSandbox),
|
||||
),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe((nodeRuntimeSandbox) => {
|
||||
this.cdRef.markForCheck();
|
||||
nodeRuntimeSandbox.init();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
<div class="header">Hydration</div>
|
||||
<div class="description">
|
||||
Hydration is the process that restores the server-side rendered application on the client
|
||||
|
||||
<p>
|
||||
This demo showcases Angular's hydration strategies, allowing you to simulate network latency and
|
||||
observe how different components hydrate based on their configured triggers.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-container">
|
||||
<div class="max-width-wrapper">
|
||||
<div class="main-layout">
|
||||
<!-- Controls & Logs -->
|
||||
<div class="sidebar">
|
||||
<div class="card config-card">
|
||||
<h3 class="sidebar-title font-mono">
|
||||
<docs-icon>schedule</docs-icon>
|
||||
Simulation Config
|
||||
</h3>
|
||||
|
||||
<div class="config-controls">
|
||||
<div class="control-group">
|
||||
<div class="label-row">
|
||||
<label>Network Latency</label>
|
||||
<span class="latency-value font-mono">{{ latency() }}ms</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="4000"
|
||||
step="100"
|
||||
[value]="latency()"
|
||||
(input)="updateLatency($event)"
|
||||
class="range-input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
(click)="resetSimulation()"
|
||||
[disabled]="isSimulationRunning()"
|
||||
class="btn-reset"
|
||||
>
|
||||
<docs-icon>refresh</docs-icon>
|
||||
Reset Lifecycle
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Terminal Log -->
|
||||
<div class="terminal">
|
||||
<h3 class="terminal-title font-mono">Hydration Engine Log</h3>
|
||||
<div class="terminal-body font-mono custom-scrollbar">
|
||||
@for (evt of eventQueue(); track $index) {
|
||||
<div class="log-entry animate-in">
|
||||
<span class="log-index">0{{ $index + 1 }}</span>
|
||||
<span class="log-tag">event:</span>
|
||||
<span class="log-msg">{{ evt }}</span>
|
||||
</div>
|
||||
}
|
||||
@if (eventQueue().length === 0) {
|
||||
<div class="log-placeholder">Awaiting app bootstrap...</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Simulator Stage -->
|
||||
<div class="simulator-stage">
|
||||
<div class="browser-window">
|
||||
<!-- Browser UI -->
|
||||
<div class="browser-header">
|
||||
<div class="window-controls">
|
||||
<div class="dot-win"></div>
|
||||
<div class="dot-win"></div>
|
||||
<div class="dot-win"></div>
|
||||
</div>
|
||||
<div class="address-bar font-mono">
|
||||
<docs-icon>lock</docs-icon>
|
||||
angular.dev/hydration-strategies
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Viewport Content -->
|
||||
<div class="viewport">
|
||||
@if (currentState() === 'Server-Side Rendering...') {
|
||||
<div class="ssr-overlay animate-fade">
|
||||
<div class="ssr-spinner">
|
||||
<div class="spinner-outer"></div>
|
||||
<div class="spinner-inner"></div>
|
||||
</div>
|
||||
<p class="ssr-title">Generating SSR Markup...</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="viewport-flex">
|
||||
<div class="viewport-header">
|
||||
<div class="header-text">
|
||||
<h4 class="viewport-title">Component Strategies</h4>
|
||||
<p class="viewport-subtitle">Mixing eager and deferred hydration triggers.</p>
|
||||
</div>
|
||||
<div class="viewport-stats">
|
||||
<div class="stats-label">Main App</div>
|
||||
<div class="stats-value font-tabular">{{ progress() }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="component-grid">
|
||||
@for (card of [card1(), card2(), card3(), card4()]; track $index) {
|
||||
<div
|
||||
(click)="handleCardClick(card.id)"
|
||||
class="component-card transition-all"
|
||||
[class]="{
|
||||
'interactive': isInteractive() || card.strategy === 'on-interaction',
|
||||
'static': !isInteractive() && card.strategy !== 'on-interaction',
|
||||
'active-card': card.clickCount > 0,
|
||||
'dashed-border': !card.isHydrated,
|
||||
}"
|
||||
>
|
||||
<div class="card-top">
|
||||
<div
|
||||
class="icon-box transition-all"
|
||||
[class]="card.isHydrated ? 'icon-hydrated' : 'icon-static'"
|
||||
>
|
||||
@if (card.isHydrating) {
|
||||
<div class="loading-spinner"></div>
|
||||
} @else {
|
||||
<docs-icon>water_drop</docs-icon>
|
||||
}
|
||||
</div>
|
||||
@if (card.clickCount > 0) {
|
||||
<div class="click-badge font-tabular animate-zoom">
|
||||
<span class="badge-label">CLICKS:</span> {{ card.clickCount }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ card.title }}</h5>
|
||||
<p class="card-desc">{{ card.description }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card-footer">
|
||||
@if (card.isHydrating) {
|
||||
<div class="tag tag-deferred animate-slide-in">
|
||||
<span class="tag-dot spin"></span>
|
||||
Hydrating...
|
||||
</div>
|
||||
} @else if (!card.isHydrated) {
|
||||
<div class="tag tag-deferred">
|
||||
<span class="tag-dot pulse"></span>
|
||||
Static
|
||||
</div>
|
||||
} @else {
|
||||
<div class="tag tag-hydrated animate-slide-in">
|
||||
<span class="tag-dot"></span>
|
||||
Hydrated
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (card.syntax) {
|
||||
<div
|
||||
class="syntax-badge font-mono"
|
||||
[class]="card.isHydrated ? 'syntax-inactive' : 'syntax-active'"
|
||||
>
|
||||
{{ card.syntax }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Lifecycle Progress -->
|
||||
<div class="lifecycle-progress-bar">
|
||||
<div class="progress-fill transition-all" [style.width.%]="progress()"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Explanatory Feature Cards -->
|
||||
<div class="explainer-grid">
|
||||
<div class="explainer-item">
|
||||
<h5 class="explainer-title"><span class="dot-red"></span> Eager Hydration</h5>
|
||||
<p class="explainer-text">
|
||||
Essential components (like navigation or top-fold content) hydrate as soon as the main
|
||||
application bundle is ready.
|
||||
</p>
|
||||
</div>
|
||||
<div class="explainer-item">
|
||||
<h5 class="explainer-title"><span class="dot-violet"></span> Incremental Hydration</h5>
|
||||
<p class="explainer-text">
|
||||
Use hydration triggers like <code>on interaction</code> or <code>on timer</code> to delay
|
||||
JS execution for non-critical elements.
|
||||
</p>
|
||||
</div>
|
||||
<div class="explainer-item">
|
||||
<h5 class="explainer-title"><span class="dot-green"></span> Event Replay</h5>
|
||||
<p class="explainer-text">
|
||||
User clicks are never lost. Angular records events during the "Static" phase and
|
||||
re-dispatches them once hydrated.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="docs-primary-btn"
|
||||
[attr.text]="'Learn more about hydration'"
|
||||
routerLink="/guide/hydration"
|
||||
>
|
||||
Learn more about hydration
|
||||
</button>
|
||||
</div>
|
||||
@@ -1,746 +0,0 @@
|
||||
@use '@angular/docs/styles/media-queries' as mq;
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 2rem 1rem;
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.5rem;
|
||||
--angular-gradient: linear-gradient(135deg, var(--orange-red) 0%, var(--electric-violet) 100%);
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.6;
|
||||
color: var(--secondary-contrast);
|
||||
}
|
||||
|
||||
.demo-container {
|
||||
color: var(--primary-contrast);
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
sans-serif;
|
||||
}
|
||||
.max-width-wrapper {
|
||||
max-width: 1152px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.font-mono {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
}
|
||||
.font-tabular {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.transition-all {
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
@keyframes slide-up {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(2rem);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
@keyframes zoom-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.animate {
|
||||
&-spin {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
&-slide-up {
|
||||
animation: slide-up 0.4s ease-out forwards;
|
||||
}
|
||||
&-zoom {
|
||||
animation: zoom-in 0.2s ease-out forwards;
|
||||
}
|
||||
&-fade {
|
||||
animation: fade-in 0.5s ease-out forwards;
|
||||
}
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
.status {
|
||||
&-header {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
&-pill {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
background: var(--page-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 1rem;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
&-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
&-text {
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--tertiary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
.dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
|
||||
&.pulse {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
&.bg-zinc-300 {
|
||||
background-color: var(--quinary-contrast);
|
||||
}
|
||||
&.bg-orange-500 {
|
||||
background-color: var(--symbolic-yellow);
|
||||
}
|
||||
&.bg-blue-500 {
|
||||
background-color: var(--bright-blue);
|
||||
}
|
||||
&.bg-emerald-500 {
|
||||
background-color: var(--super-green);
|
||||
}
|
||||
}
|
||||
.divider {
|
||||
height: 1rem;
|
||||
width: 1px;
|
||||
background-color: var(--senary-contrast);
|
||||
}
|
||||
.progress-percentage {
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
color: var(--electric-violet);
|
||||
}
|
||||
|
||||
.main-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
}
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.sidebar {
|
||||
grid-column: span 4;
|
||||
}
|
||||
.simulator-stage {
|
||||
grid-column: span 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sidebar & Config */
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--page-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.sidebar-title {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: var(--quaternary-contrast);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
margin-bottom: 1.5rem;
|
||||
margin-top: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.config-controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
.label-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.75rem;
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.latency-value {
|
||||
font-size: 14px;
|
||||
color: var(--electric-violet);
|
||||
font-weight: bold;
|
||||
}
|
||||
.range-input {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
background: var(--septenary-contrast);
|
||||
border-radius: 8px;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: var(--electric-violet);
|
||||
border: 4px solid var(--page-background);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 4px 6px color-mix(in srgb, var(--electric-violet), transparent 80%);
|
||||
}
|
||||
}
|
||||
.btn-reset {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
background: var(--primary-contrast);
|
||||
color: var(--page-background);
|
||||
border: none;
|
||||
border-radius: 1rem;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
transition: transform 0.1s;
|
||||
|
||||
&:hover {
|
||||
background: var(--secondary-contrast);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
&[disabled] {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminal */
|
||||
.terminal {
|
||||
background: var(--primary-contrast);
|
||||
border-radius: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
color: var(--page-background);
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
||||
position: relative;
|
||||
|
||||
&-title {
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
color: var(--quinary-contrast);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.2em;
|
||||
margin-bottom: 1rem;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&-body {
|
||||
min-height: 160px;
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
font-size: 11px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.log {
|
||||
&-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
&-index {
|
||||
color: var(--senary-contrast);
|
||||
}
|
||||
&-tag {
|
||||
color: var(--senary-contrast);
|
||||
}
|
||||
&-msg {
|
||||
color: var(--septenary-contrast);
|
||||
}
|
||||
&-placeholder {
|
||||
color: var(--tertiary-contrast);
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
/* Browser Mock */
|
||||
.browser {
|
||||
&-window {
|
||||
background: var(--page-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 2.5rem;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.05);
|
||||
min-height: 520px;
|
||||
}
|
||||
|
||||
&-header {
|
||||
background: var(--octonary-contrast);
|
||||
border-bottom: 1px solid var(--senary-contrast);
|
||||
padding: 1rem 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
.window-controls {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
.dot-win {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: var(--quinary-contrast);
|
||||
}
|
||||
.address-bar {
|
||||
flex: 1;
|
||||
background: var(--page-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.75rem;
|
||||
padding: 0.375rem 1rem;
|
||||
font-size: 11px;
|
||||
color: var(--quaternary-contrast);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
docs-icon {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.viewport {
|
||||
padding: 2rem;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
|
||||
&-flex {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
&-header {
|
||||
display: flex;
|
||||
margin-bottom: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
&-title {
|
||||
font-size: 24px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.025em;
|
||||
margin-bottom: 0.25rem;
|
||||
margin-top: 0;
|
||||
}
|
||||
&-subtitle {
|
||||
font-size: 12px;
|
||||
color: var(--quaternary-contrast);
|
||||
font-weight: 500;
|
||||
}
|
||||
&-stats {
|
||||
text-align: right;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.ssr {
|
||||
&-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: color-mix(in srgb, var(--page-background), transparent 5%);
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
&-spinner {
|
||||
position: relative;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
&-title {
|
||||
font-weight: bold;
|
||||
color: var(--primary-contrast);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
&-outer {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: var(--angular-gradient);
|
||||
border-radius: 0.75rem;
|
||||
opacity: 0.2;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
&-inner {
|
||||
position: absolute;
|
||||
inset: 8px;
|
||||
background: var(--angular-gradient);
|
||||
border-radius: 0.5rem;
|
||||
animation: spin 1.5s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.stats {
|
||||
&-label {
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
color: var(--quaternary-contrast);
|
||||
letter-spacing: 0.1em;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
&-value {
|
||||
font-size: 32px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.05em;
|
||||
}
|
||||
}
|
||||
|
||||
.component-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
flex: 1;
|
||||
|
||||
@media (min-width: 640px) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Card States */
|
||||
.component-card {
|
||||
position: relative;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
|
||||
&.interactive {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--electric-violet);
|
||||
box-shadow: 0 20px 25px -5px color-mix(in srgb, var(--electric-violet), transparent 95%);
|
||||
}
|
||||
}
|
||||
|
||||
&.static {
|
||||
background: color-mix(in srgb, var(--octonary-contrast), transparent 50%);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
&.active-card {
|
||||
box-shadow: inset 0 2px 4px color-mix(in srgb, var(--electric-violet), transparent 95%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&.dashed-border {
|
||||
border-style: dashed;
|
||||
border-color: var(--quinary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
&-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
&-body {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
&-title {
|
||||
font-size: 18px;
|
||||
font-weight: 900;
|
||||
margin-bottom: 0.125rem;
|
||||
}
|
||||
&-desc {
|
||||
font-size: 10px;
|
||||
color: var(--quaternary-contrast);
|
||||
font-weight: 500;
|
||||
line-height: 1.25;
|
||||
}
|
||||
&-footer {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
&-box {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
&-hydrated {
|
||||
background: var(--septenary-contrast);
|
||||
|
||||
.component-card.interactive:hover & {
|
||||
background: var(--electric-violet);
|
||||
color: var(--page-background);
|
||||
}
|
||||
}
|
||||
&-static {
|
||||
background: var(--octonary-contrast);
|
||||
color: var(--senary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 2px solid var(--senary-contrast);
|
||||
border-top-color: var(--electric-violet);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.click {
|
||||
&-badge {
|
||||
background: var(--electric-violet);
|
||||
color: var(--page-background);
|
||||
padding: 0.25rem 0.625rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 10px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.05em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.badge-label {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 9px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
width: fit-content;
|
||||
|
||||
&-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&-deferred {
|
||||
color: var(--symbolic-yellow);
|
||||
background: color-mix(in srgb, var(--symbolic-yellow), transparent 90%);
|
||||
|
||||
.tag-dot {
|
||||
background: var(--symbolic-yellow);
|
||||
}
|
||||
}
|
||||
|
||||
&-hydrated {
|
||||
color: var(--super-green);
|
||||
background: color-mix(in srgb, var(--super-green), transparent 90%);
|
||||
|
||||
.tag-dot {
|
||||
background: var(--super-green);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.syntax {
|
||||
&-badge {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 0.25rem 0.75rem;
|
||||
font-size: 8px;
|
||||
font-weight: bold;
|
||||
border-left: 1px solid;
|
||||
border-bottom: 1px solid;
|
||||
border-bottom-left-radius: 0.75rem;
|
||||
}
|
||||
&-active {
|
||||
background: color-mix(in srgb, var(--electric-violet), transparent 95%);
|
||||
color: var(--electric-violet);
|
||||
border-color: color-mix(in srgb, var(--electric-violet), transparent 90%);
|
||||
}
|
||||
&-inactive {
|
||||
background: var(--septenary-contrast);
|
||||
color: var(--quaternary-contrast);
|
||||
border-color: var(--senary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
/* Progress bar */
|
||||
.lifecycle-progress-bar {
|
||||
height: 6px;
|
||||
background: var(--septenary-contrast);
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.progress-fill {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
background: var(--angular-gradient);
|
||||
box-shadow: 0 0 10px color-mix(in srgb, var(--electric-violet), transparent 70%);
|
||||
}
|
||||
|
||||
/* Explainer */
|
||||
.explainer {
|
||||
&-grid {
|
||||
margin-top: 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 3rem;
|
||||
border-top: 1px solid var(--senary-contrast);
|
||||
padding-top: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
&-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
&-title {
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
|
||||
span {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
&-text {
|
||||
font-size: 14px;
|
||||
color: var(--quaternary-contrast);
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.dot {
|
||||
&-red {
|
||||
background: var(--orange-red);
|
||||
}
|
||||
&-violet {
|
||||
background: var(--electric-violet);
|
||||
}
|
||||
&-green {
|
||||
background: var(--super-green);
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
background: var(--septenary-contrast);
|
||||
padding: 0 4px;
|
||||
border-radius: 4px;
|
||||
color: var(--electric-violet);
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
.custom-scrollbar {
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--tertiary-contrast);
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
/*!
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component, signal, WritableSignal} from '@angular/core';
|
||||
import {IconComponent} from '@angular/docs';
|
||||
import {RouterLink} from '@angular/router';
|
||||
|
||||
interface SimulationCard {
|
||||
id: number;
|
||||
clickCount: number;
|
||||
penddingEvents: number;
|
||||
isHydrated: boolean;
|
||||
isHydrating: boolean;
|
||||
strategy?: 'on-interaction' | 'on-timer';
|
||||
syntax?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'adev-hydration-example',
|
||||
imports: [RouterLink, IconComponent],
|
||||
templateUrl: './hydration-example.html',
|
||||
styleUrls: ['./hydration-example.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class HydrationExample {
|
||||
latency = signal(500);
|
||||
progress = signal(0);
|
||||
currentState = signal<
|
||||
'Server-Side Rendering...' | 'Initial Paint' | 'Loading Bundle' | 'Hydrated'
|
||||
>('Server-Side Rendering...');
|
||||
isInteractive = signal(false);
|
||||
eventQueue = signal<string[]>([]);
|
||||
isSimulationRunning = signal(false);
|
||||
|
||||
card1 = signal<SimulationCard>({
|
||||
id: 1,
|
||||
clickCount: 0,
|
||||
penddingEvents: 0,
|
||||
isHydrated: false,
|
||||
isHydrating: true,
|
||||
title: 'Eager Module',
|
||||
description: 'Part of initial bundle.',
|
||||
});
|
||||
card2 = signal<SimulationCard>({
|
||||
id: 2,
|
||||
clickCount: 0,
|
||||
penddingEvents: 0,
|
||||
isHydrated: false,
|
||||
isHydrating: true,
|
||||
title: 'Eager Module',
|
||||
description: 'Part of initial bundle.',
|
||||
});
|
||||
card3 = signal<SimulationCard>({
|
||||
id: 3,
|
||||
clickCount: 0,
|
||||
penddingEvents: 0,
|
||||
isHydrated: false,
|
||||
isHydrating: false,
|
||||
strategy: 'on-interaction',
|
||||
syntax: '@defer (hydrate on interaction)',
|
||||
title: 'Interaction Module',
|
||||
description: 'Logic loads on click.',
|
||||
});
|
||||
card4 = signal<SimulationCard>({
|
||||
id: 4,
|
||||
clickCount: 0,
|
||||
penddingEvents: 0,
|
||||
isHydrated: false,
|
||||
isHydrating: false,
|
||||
strategy: 'on-timer',
|
||||
syntax: '@defer (hydrate on timer(2s))',
|
||||
title: 'Timer Module',
|
||||
description: 'Hydrates after 2s delay.',
|
||||
});
|
||||
|
||||
constructor() {
|
||||
this.startLifecycle();
|
||||
}
|
||||
|
||||
protected async startLifecycle() {
|
||||
if (this.isSimulationRunning()) return;
|
||||
this.isSimulationRunning.set(true);
|
||||
this.currentState.set('Server-Side Rendering...');
|
||||
this.progress.set(0);
|
||||
this.isInteractive.set(false);
|
||||
this.eventQueue.set([]);
|
||||
|
||||
const resetCard = (card: SimulationCard): SimulationCard => ({
|
||||
...card,
|
||||
clickCount: 0,
|
||||
penddingEvents: 0,
|
||||
isHydrated: false,
|
||||
isHydrating: card.strategy ? false : true,
|
||||
});
|
||||
|
||||
this.card1.update(resetCard);
|
||||
this.card2.update(resetCard);
|
||||
this.card3.update(resetCard);
|
||||
this.card4.update(resetCard);
|
||||
|
||||
await this.wait(1000);
|
||||
|
||||
this.currentState.set('Initial Paint');
|
||||
this.progress.set(20);
|
||||
|
||||
await this.wait(300);
|
||||
|
||||
this.currentState.set('Loading Bundle');
|
||||
let currentP = 20;
|
||||
const interval = setInterval(
|
||||
() => {
|
||||
currentP += 1;
|
||||
if (currentP <= 100) this.progress.set(currentP);
|
||||
if (currentP >= 100) clearInterval(interval);
|
||||
},
|
||||
Math.max(this.latency() / 80, 5),
|
||||
);
|
||||
|
||||
await this.wait(this.latency());
|
||||
|
||||
this.currentState.set('Hydrated');
|
||||
this.isInteractive.set(true);
|
||||
this.progress.set(100);
|
||||
|
||||
const hydrateCard = (card: SimulationCard): SimulationCard =>
|
||||
!card.strategy ? {...card, isHydrated: true, isHydrating: false} : card;
|
||||
|
||||
this.card1.update(hydrateCard);
|
||||
this.card2.update(hydrateCard);
|
||||
|
||||
const pendingEvents = this.card1().penddingEvents + this.card2().penddingEvents;
|
||||
await this.wait(800);
|
||||
if (pendingEvents > 0) {
|
||||
this.logEvent(`Replaying ${pendingEvents} queued event(s)...`);
|
||||
this.processPendingEvents(this.card1);
|
||||
this.processPendingEvents(this.card2);
|
||||
}
|
||||
|
||||
await this.triggerTimerHydration(4);
|
||||
this.isSimulationRunning.set(false);
|
||||
}
|
||||
|
||||
protected async triggerTimerHydration(id: number) {
|
||||
const cardSignal = this.getCardSignal(id);
|
||||
await this.wait(2000);
|
||||
|
||||
if (!this.card4().isHydrated) {
|
||||
this.logEvent(`Timer fired: Hydrating Module#4`);
|
||||
cardSignal.update((c) => ({...c, isHydrating: true}));
|
||||
await this.wait(800);
|
||||
this.card4.update((c) => ({...c, isHydrating: false, isHydrated: true}));
|
||||
|
||||
if (cardSignal().penddingEvents > 0) {
|
||||
this.logEvent(`Replaying ${cardSignal().penddingEvents} queued event(s)...`);
|
||||
await this.wait(600);
|
||||
this.processPendingEvents(cardSignal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async handleCardClick(id: number) {
|
||||
const card = this.getCardSignal(id);
|
||||
if (card().isHydrated) {
|
||||
this.processAction(card);
|
||||
return;
|
||||
}
|
||||
|
||||
if (card().strategy === 'on-interaction' && !card().isHydrated) {
|
||||
if (!card().isHydrating) {
|
||||
this.logEvent(`Manual trigger: Hydrating Module#${card().id}`);
|
||||
this.logEvent(`Queued click for Module#${card().id}`);
|
||||
card.update((c) => ({...c, isHydrating: true, penddingEvents: 1}));
|
||||
await this.wait(600);
|
||||
if (card().penddingEvents > 0) {
|
||||
this.logEvent(`Replaying ${card().penddingEvents} queued event(s)...`);
|
||||
}
|
||||
this.processPendingEvents(card);
|
||||
card.update((c) => ({...c, isHydrating: false, isHydrated: true}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!card().isHydrated) {
|
||||
this.queueClick(card);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected updateLatency(ev: any) {
|
||||
this.latency.set(parseInt(ev.target.value));
|
||||
}
|
||||
|
||||
protected resetSimulation() {
|
||||
this.startLifecycle();
|
||||
}
|
||||
|
||||
private async queueClick(card: WritableSignal<SimulationCard>) {
|
||||
card.update((c) => ({...c, penddingEvents: c.penddingEvents + 1}));
|
||||
this.logEvent(`Queued click for Module#${card().id}`);
|
||||
}
|
||||
|
||||
private processAction(card: WritableSignal<SimulationCard>) {
|
||||
card.update((c) => ({...c, clickCount: c.clickCount + 1}));
|
||||
}
|
||||
|
||||
private processPendingEvents(card: WritableSignal<SimulationCard>) {
|
||||
const pending = card().penddingEvents;
|
||||
card.update((c) => ({...c, penddingEvents: 0}));
|
||||
for (let i = 0; i < pending; i++) {
|
||||
this.processAction(card);
|
||||
}
|
||||
}
|
||||
|
||||
private logEvent(msg: string) {
|
||||
this.eventQueue.update((q) => [...q, msg]);
|
||||
}
|
||||
|
||||
private wait(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
private getCardSignal(id: number): WritableSignal<SimulationCard> {
|
||||
switch (id) {
|
||||
case 1:
|
||||
return this.card1;
|
||||
case 2:
|
||||
return this.card2;
|
||||
case 3:
|
||||
return this.card3;
|
||||
case 4:
|
||||
return this.card4;
|
||||
default:
|
||||
throw new Error('Invalid card id');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<div class="two-column-step">
|
||||
<div class="step-description">
|
||||
<div class="header">Signals: Fine-Grained Reactivity</div>
|
||||
<div class="description">
|
||||
Type in the search box to filter the list. A
|
||||
<code>computed</code> signal automatically recalculates the
|
||||
<code>filteredItems</code> whenever the <code>searchTerm</code> signal changes.
|
||||
</div>
|
||||
|
||||
<div class="demo-display">
|
||||
<input
|
||||
[value]="searchTerm()"
|
||||
(input)="onSearch($event.target.value)"
|
||||
placeholder="Search for fruit..."
|
||||
class="demo-input"
|
||||
/>
|
||||
<div class="demo-list">
|
||||
@for (item of filteredItems(); track item) {
|
||||
<div class="demo-item">{{ item }}</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="docs-primary-btn"
|
||||
[attr.text]="'Learn more about signals'"
|
||||
routerLink="/guide/signals"
|
||||
>
|
||||
Learn more about signals
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="step-code">
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>component.ts</span>
|
||||
<span class="copy-icon"></span>
|
||||
</div>
|
||||
|
||||
<adev-code-block [code]="tsExample" />
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>component.html</span>
|
||||
<span class="copy-icon"></span>
|
||||
</div>
|
||||
<adev-code-block [code]="htmlExample" language="angular-html" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,129 +0,0 @@
|
||||
@use '@angular/docs/styles/media-queries' as mq;
|
||||
|
||||
.two-column-step {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--card-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.5rem;
|
||||
padding: 2rem;
|
||||
|
||||
@include mq.for-tablet-down {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
@include mq.for-phone-only {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.step-description {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
|
||||
.header {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.6;
|
||||
color: var(--secondary-contrast);
|
||||
}
|
||||
|
||||
.demo-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
height: 250px;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
.demo-input {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--senary-contrast);
|
||||
background: var(--septenary-contrast);
|
||||
color: var(--primary-contrast);
|
||||
font-size: 1rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid var(--primary-color);
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-list {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
padding-right: 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
overflow-y: auto;
|
||||
border: 1px solid var(--senary-contrast);
|
||||
background: var(--septenary-contrast);
|
||||
color: var(--primary-contrast);
|
||||
|
||||
.demo-item {
|
||||
padding: 0.25rem 1rem;
|
||||
color: var(--secondary-contrast);
|
||||
border-radius: 0.5rem;
|
||||
transition: background 0.2s;
|
||||
margin: 0.2rem;
|
||||
|
||||
&:hover {
|
||||
background: var(--senary-contrast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step-code {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
min-width: 0;
|
||||
|
||||
.code-block {
|
||||
background: var(--card-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
overflow: auto;
|
||||
|
||||
.code-header {
|
||||
display: flex;
|
||||
padding: 0.75rem;
|
||||
background: var(--subtle-purple);
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
transition: background 0.3s ease;
|
||||
|
||||
& > span {
|
||||
background-image: var(--purple-to-blue-horizontal-gradient);
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.4rem;
|
||||
letter-spacing: -0.00875rem;
|
||||
margin: 0;
|
||||
word-wrap: break-word;
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*!
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component, computed, signal} from '@angular/core';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {CodeBlock} from '../code-block/code-block';
|
||||
|
||||
@Component({
|
||||
selector: 'adev-signals-demo',
|
||||
imports: [RouterLink, CodeBlock],
|
||||
templateUrl: './signals-demo.html',
|
||||
styleUrls: ['./signals-demo.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SignalsDemo {
|
||||
tsExample = tsExample;
|
||||
htmlExample = htmlExample;
|
||||
|
||||
items = signal([
|
||||
'Apple',
|
||||
'Apricot',
|
||||
'Avocado',
|
||||
'Banana',
|
||||
'Blueberry',
|
||||
'Cherry',
|
||||
'Date',
|
||||
'Dragonfruit',
|
||||
]);
|
||||
searchTerm = signal('');
|
||||
|
||||
// A computed signal that derives the filtered list.
|
||||
// It automatically re-runs when a dependency changes.
|
||||
filteredItems = computed(() => {
|
||||
const lowerCaseSearchTerm = this.searchTerm().toLowerCase();
|
||||
return this.items().filter((item) => item.toLowerCase().includes(lowerCaseSearchTerm));
|
||||
});
|
||||
|
||||
onSearch(searchTerm: string) {
|
||||
this.searchTerm.set(searchTerm);
|
||||
}
|
||||
}
|
||||
|
||||
const tsExample = `
|
||||
// Source signals for state.
|
||||
items = signal(['Apple', 'Banana', /*...*/ ]);
|
||||
searchTerm = signal('');
|
||||
// A computed signal that derives the filtered list.
|
||||
// It automatically re-runs when a dependency changes.
|
||||
filteredItems = computed(() => {
|
||||
const lowerCaseSearchTerm = this.searchTerm().toLowerCase();
|
||||
return this.items().filter(item =>
|
||||
item.toLowerCase().includes(lowerCaseSearchTerm)
|
||||
);
|
||||
});
|
||||
`.trim();
|
||||
|
||||
const htmlExample = `
|
||||
<input [value]="searchTerm()" (input)="searchTerm.set($event.target.value)" />
|
||||
<ul>
|
||||
@for (item of filteredItems(); track $index) {
|
||||
<li>{{ item }}</li>
|
||||
}
|
||||
</ul>
|
||||
`.trim();
|
||||
@@ -1,242 +1,489 @@
|
||||
<main class="adev-home" #home>
|
||||
<div class="banners-layer layer">
|
||||
<div class="adev-banner-container">
|
||||
<a href="events/v21" class="adev-banner" target="_blank">
|
||||
<h1 tabindex="-1">Angular v21 is here!</h1>
|
||||
<p class="adev-banner-cta">🕹️ Start your adventure</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<section class="logo-section">
|
||||
<div class="pattern"></div>
|
||||
<div class="content">
|
||||
<div class="adev-banner-container">
|
||||
<a href="events/v21" class="adev-banner" target="_blank">
|
||||
<h1 tabindex="-1">Angular v21 is here!</h1>
|
||||
<p class="adev-banner-cta">🕹️ Start your adventure</p>
|
||||
</a>
|
||||
|
||||
<div class="search-field">
|
||||
<docs-text-field placeholder="search" (click)="openSearch()" />
|
||||
</div>
|
||||
@if (!isUwu) {
|
||||
<!-- Angular logo -->
|
||||
<div class="logo-layer">
|
||||
<svg class="svg" viewBox="0 0 1280 400" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<!-- Do not remove `gradientTransform` attribute. Safari needs it in order to start the animation. -->
|
||||
<linearGradient
|
||||
id="gradient"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="rotate(0 640 125)"
|
||||
>
|
||||
<stop offset="0" stop-color="#ed0100" />
|
||||
<stop offset="0.25" stop-color="#e449b4" />
|
||||
<stop offset="0.5" stop-color="#ae3bfc" />
|
||||
<stop offset="1" stop-color="#7f15fd" />
|
||||
<animateTransform
|
||||
attributeName="gradientTransform"
|
||||
type="rotate"
|
||||
from="0 640 125"
|
||||
to="360 640 125"
|
||||
dur="6.5s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g class="wrapper" fill="url(#gradient)">
|
||||
<g class="logo">
|
||||
<g class="shield">
|
||||
<path
|
||||
class="shield-base"
|
||||
d="M311.8,101.7L302,255.6L208.3,53.8L311.8,101.7ZM246.9,300.7L176.1,341.1L105.3,300.7L246.9,300.7ZM50.1,255.6L40.4,101.7L143.9,53.8L50.1,255.6Z"
|
||||
/>
|
||||
<path class="shield-middle" d="M176.1,130.4L213.2,220.6L139,220.6L176.1,130.4Z" />
|
||||
<path
|
||||
class="shield-bottom-a-arc"
|
||||
d="M106.419,301.339L105.3,300.7L119.7,265.8L232.5,265.8L246.9,300.7L245.781,301.339L106.419,301.339Z"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
class="capt-a-letter letter"
|
||||
d="M515.4,288L553.1,288L484.4,92.7L440.7,92.7L372,288L409.7,288L425.8,239.9L499.2,239.9L515.4,288ZM435.4,211.4L461.8,132.8L463.3,132.8L489.7,211.4L435.4,211.4Z"
|
||||
/>
|
||||
<path
|
||||
class="n-letter letter"
|
||||
d="M590.4,202.2L590.4,288L555.9,288L555.9,141.6L588.9,141.6L588.9,166.5L590.6,166.5C594,158.3 599.4,151.8 606.8,147C614.2,142.2 623.4,139.8 634.3,139.8C644.4,139.8 653.2,142 660.8,146.3C668.3,150.6 674.2,156.9 678.3,165.1C682.5,173.3 684.5,183.2 684.4,194.9L684.4,288L649.9,288L649.9,200.1C649.9,190.3 647.4,182.7 642.3,177.1C637.2,171.6 630.3,168.8 621.4,168.8C615.4,168.8 610,170.1 605.3,172.8C600.6,175.4 597,179.2 594.3,184.2C591.8,189.1 590.4,195.1 590.4,202.2Z"
|
||||
/>
|
||||
<path
|
||||
class="g-letter letter"
|
||||
d="M760.5,345.9C748.1,345.9 737.5,344.2 728.6,340.9C719.7,337.6 712.6,333.1 707.2,327.5C701.8,321.9 698,315.7 696,308.9L727.1,301.4C728.5,304.3 730.5,307.1 733.2,309.9C735.9,312.7 739.5,315.1 744,317C748.5,318.9 754.3,319.8 761.2,319.8C771,319.8 779.1,317.4 785.5,312.7C791.9,308 795.1,300.2 795.1,289.4L795.1,261.7L793.4,261.7C791.6,265.3 789,268.9 785.6,272.7C782.2,276.5 777.7,279.6 772.2,282.1C766.6,284.6 759.7,285.9 751.3,285.9C740.1,285.9 729.9,283.2 720.7,277.9C711.6,272.6 704.3,264.6 699,254.1C693.6,243.5 690.9,230.3 690.9,214.3C690.9,198.2 693.6,184.6 699,173.5C704.4,162.4 711.6,154 720.8,148.2C730,142.4 740.2,139.6 751.4,139.6C760,139.6 767.1,141 772.6,143.9C778.2,146.8 782.6,150.3 785.9,154.3C789.2,158.3 791.7,162.1 793.4,165.7L795.3,165.7L795.3,141.5L829.3,141.5L829.3,290.3C829.3,302.8 826.3,313.2 820.3,321.4C814.3,329.6 806.2,335.7 795.8,339.8C785.4,343.9 773.6,345.9 760.5,345.9ZM760.8,258.8C768.1,258.8 774.3,257 779.5,253.5C784.6,249.9 788.6,244.8 791.2,238.2C793.9,231.5 795.2,223.5 795.2,214.2C795.2,205 793.9,196.9 791.2,190C788.6,183.1 784.7,177.7 779.6,173.8C774.5,170 768.2,168 760.8,168C753.1,168 746.7,170 741.5,174C736.4,178 732.5,183.5 729.9,190.4C727.3,197.4 726,205.3 726,214.1C726,223.1 727.3,230.9 730,237.6C732.6,244.3 736.5,249.5 741.7,253.2C746.8,256.9 753.2,258.8 760.8,258.8Z"
|
||||
/>
|
||||
<path
|
||||
class="u-letter letter"
|
||||
d="M933.8,226.4L933.8,141.6L968.3,141.6L968.3,288L934.8,288L934.8,262L933.3,262C930,270.2 924.6,276.9 917,282.1C909.5,287.3 900.2,289.9 889.2,289.9C879.6,289.9 871.1,287.8 863.8,283.5C856.5,279.2 850.7,273 846.6,264.7C842.5,256.5 840.4,246.5 840.4,234.8L840.4,141.6L875,141.6L875,229.5C875,238.8 877.5,246.2 882.6,251.6C887.7,257.1 894.4,259.8 902.6,259.8C907.7,259.8 912.6,258.6 917.4,256.1C922.2,253.6 926.1,249.9 929.2,245C932.3,240 933.8,233.8 933.8,226.4Z"
|
||||
/>
|
||||
<rect class="l-letter letter" x="979.6" y="92.7" width="34.5" height="195.3" />
|
||||
<path
|
||||
class="a-letter letter"
|
||||
d="M1068.9,290.9C1059.6,290.9 1051.3,289.2 1043.9,285.9C1036.5,282.6 1030.6,277.6 1026.4,271.1C1022.1,264.6 1020,256.5 1020,246.9C1020,238.6 1021.5,231.8 1024.6,226.4C1027.7,221 1031.8,216.7 1037.1,213.4C1042.4,210.2 1048.3,207.7 1055,206C1061.6,204.3 1068.5,203.1 1075.6,202.3C1084.2,201.4 1091.1,200.6 1096.5,199.9C1101.8,199.2 1105.7,198 1108.2,196.5C1110.6,194.9 1111.9,192.5 1111.9,189.2L1111.9,188.6C1111.9,181.4 1109.8,175.9 1105.5,171.9C1101.2,168 1095.1,166 1087.1,166C1078.6,166 1072,167.8 1067,171.5C1062.1,175.2 1058.8,179.5 1057,184.6L1024.8,180C1027.3,171.1 1031.5,163.7 1037.4,157.6C1043.2,151.6 1050.4,147.1 1058.8,144.1C1067.3,141.1 1076.6,139.6 1086.8,139.6C1093.9,139.6 1100.9,140.4 1107.9,142.1C1114.9,143.8 1121.3,146.5 1127.1,150.3C1132.9,154.1 1137.5,159.2 1141.1,165.7C1144.6,172.2 1146.4,180.3 1146.4,190L1146.4,288L1113.2,288L1113.2,267.9L1112.1,267.9C1110,272 1107.1,275.8 1103.3,279.3C1099.5,282.8 1094.8,285.7 1089.1,287.8C1083.2,289.9 1076.6,290.9 1068.9,290.9ZM1077.9,265.6C1084.8,265.6 1090.8,264.2 1095.9,261.5C1101,258.7 1104.9,255.1 1107.7,250.5C1110.5,245.9 1111.8,240.9 1111.8,235.5L1111.8,218.2C1110.7,219.1 1108.9,219.9 1106.3,220.7C1103.7,221.5 1100.9,222.1 1097.7,222.7C1094.5,223.3 1091.4,223.8 1088.3,224.2C1085.2,224.6 1082.5,225 1080.2,225.3C1075.1,226 1070.4,227.1 1066.4,228.7C1062.3,230.3 1059.1,232.5 1056.8,235.3C1054.4,238.1 1053.3,241.8 1053.3,246.2C1053.3,252.6 1055.6,257.4 1060.3,260.6C1064.8,264 1070.7,265.6 1077.9,265.6Z"
|
||||
/>
|
||||
<path
|
||||
class="r-letter letter"
|
||||
d="M1156.9,288L1156.9,141.6L1190.4,141.6L1190.4,166L1191.9,166C1194.6,157.5 1199.2,151 1205.7,146.4C1212.2,141.8 1219.7,139.5 1228.1,139.5C1230,139.5 1232.2,139.6 1234.5,139.7C1236.9,139.9 1238.9,140.1 1240.5,140.4L1240.5,172.1C1239,171.6 1236.7,171.1 1233.6,170.7C1230.5,170.3 1227.4,170.1 1224.5,170.1C1218.2,170.1 1212.6,171.5 1207.6,174.2C1202.6,176.9 1198.7,180.6 1195.8,185.4C1192.9,190.2 1191.5,195.7 1191.5,201.9L1191.5,288L1156.9,288Z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h2>The framework for building scalable web apps with confidence</h2>
|
||||
</div>
|
||||
} @else {
|
||||
<!-- UwU logo -->
|
||||
<div layerId="uwu" class="uwu-layer">
|
||||
<img src="assets/images/uwu.png" alt="Angular logo" />
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!isUwu) {
|
||||
<div class="title">
|
||||
<h2>Productivity<br />Meets scalability</h2>
|
||||
<h3>The framework for building scalable web apps with confidence</h3>
|
||||
</div>
|
||||
} @else {
|
||||
<!-- UwU logo -->
|
||||
<div class="uwu">
|
||||
<img src="assets/images/uwu.png" alt="Angular logo" />
|
||||
</div>
|
||||
}
|
||||
<div class="learn-angular">
|
||||
<a href="#learn-more" class="adev-cta">
|
||||
<button class="docs-primary-btn" [attr.text]="'Get Started'" aria-label="Get Started">
|
||||
Get Started
|
||||
</button>
|
||||
</a>
|
||||
<div class="adev-arrow"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="learn-angular">
|
||||
<a href="#learn-more" class="adev-cta">
|
||||
<button class="docs-primary-btn" [attr.text]="'Get Started'" aria-label="Get Started">
|
||||
Get Started
|
||||
</button>
|
||||
</a>
|
||||
<div class="adev-arrow"></div>
|
||||
<section class="features">
|
||||
<h2>Productivity meets scalability</h2>
|
||||
<div class="features-grid">
|
||||
<div class="feature">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g><rect fill="none" height="24" width="24" x="0" /></g>
|
||||
<g>
|
||||
<g>
|
||||
<polygon points="19,9 20.25,6.25 23,5 20.25,3.75 19,1 17.75,3.75 15,5 17.75,6.25" />
|
||||
<polygon
|
||||
points="19,15 17.75,17.75 15,19 17.75,20.25 19,23 20.25,20.25 23,19 20.25,17.75"
|
||||
/>
|
||||
<path
|
||||
d="M11.5,9.5L9,4L6.5,9.5L1,12l5.5,2.5L9,20l2.5-5.5L17,12L11.5,9.5z M9.99,12.99L9,15.17l-0.99-2.18L5.83,12l2.18-0.99 L9,8.83l0.99,2.18L12.17,12L9.99,12.99z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h3>AI-forward</h3>
|
||||
<p>Resources and integrations to supercharge your development with AI</p>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
|
||||
<path
|
||||
d="m480-400-80-80 80-80 80 80-80 80Zm-85-235L295-735l185-185 185 185-100 100-85-85-85 85ZM225-295 40-480l185-185 100 100-85 85 85 85-100 100Zm510 0L635-395l85-85-85-85 100-100 185 185-185 185ZM480-40 295-225l100-100 85 85 85-85 100 100L480-40Z"
|
||||
/>
|
||||
</svg>
|
||||
<h3>Opinionated & versatile</h3>
|
||||
<p>Organized yet modular thanks to Angular components and dependency injection</p>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
|
||||
<path
|
||||
d="M197-197q-54-55-85.5-127.5T80-480q0-84 31.5-156.5T197-763l57 57q-44 44-69 102t-25 124q0 67 25 125t69 101l-57 57Zm113-113q-32-33-51-76.5T240-480q0-51 19-94.5t51-75.5l57 57q-22 22-34.5 51T320-480q0 33 12.5 62t34.5 51l-57 57Zm170-90q-33 0-56.5-23.5T400-480q0-33 23.5-56.5T480-560q33 0 56.5 23.5T560-480q0 33-23.5 56.5T480-400Zm170 90-57-57q22-22 34.5-51t12.5-62q0-33-12.5-62T593-593l57-57q32 32 51 75.5t19 94.5q0 50-19 93.5T650-310Zm113 113-57-57q44-44 69-102t25-124q0-67-25-125t-69-101l57-57q54 54 85.5 126.5T880-480q0 83-31.5 155.5T763-197Z"
|
||||
/>
|
||||
</svg>
|
||||
<h3>Reactive</h3>
|
||||
<p>Fast state updates with fine-grained reactivity based on Angular Signals</p>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
|
||||
<path
|
||||
d="M220-260q-92 0-156-64T0-480q0-92 64-156t156-64q37 0 71 13t61 37l68 62-60 54-62-56q-16-14-36-22t-42-8q-58 0-99 41t-41 99q0 58 41 99t99 41q22 0 42-8t36-22l310-280q27-24 61-37t71-13q92 0 156 64t64 156q0 92-64 156t-156 64q-37 0-71-13t-61-37l-68-62 60-54 62 56q16 14 36 22t42 8q58 0 99-41t41-99q0-58-41-99t-99-41q-22 0-42 8t-36 22L352-310q-27 24-61 37t-71 13Z"
|
||||
/>
|
||||
</svg>
|
||||
<h3>Fully featured</h3>
|
||||
<p>
|
||||
Everything works together with Angular's first-party modules for forms, routing, and more
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="features-section">
|
||||
<h2 id="features">Features that actually <br />help you solve problems</h2>
|
||||
<!-- -->
|
||||
|
||||
<div ngTabs class="material-tabs">
|
||||
<div ngTabList selectionMode="follow" selectedTab="signals">
|
||||
<div class="tab-background"></div>
|
||||
<div ngTab value="signals">Signals</div>
|
||||
<div ngTab value="control-flow">Control Flow</div>
|
||||
<div ngTab value="deferrable-views">Deferrable Views</div>
|
||||
<div ngTab value="hydration">Hydration</div>
|
||||
</div>
|
||||
|
||||
<div class="sliding-window">
|
||||
<div ngTabPanel [preserveContent]="true" value="signals">
|
||||
<ng-template ngTabContent>
|
||||
@defer (on idle) {
|
||||
<adev-signals-demo />
|
||||
}
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div ngTabPanel [preserveContent]="true" value="control-flow">
|
||||
<ng-template ngTabContent>
|
||||
@defer (on idle) {
|
||||
<adev-control-flow-example />
|
||||
}
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div ngTabPanel [preserveContent]="true" value="deferrable-views">
|
||||
<ng-template ngTabContent>
|
||||
@defer {
|
||||
<adev-defer-example />
|
||||
}
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div ngTabPanel [preserveContent]="true" value="hydration">
|
||||
<ng-template ngTabContent>
|
||||
@defer {
|
||||
<adev-hydration-example />
|
||||
}
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="selling-points">
|
||||
<h2>Enabling you to build<br />smarter and faster</h2>
|
||||
<div class="cards">
|
||||
<a class="card" routerLink="/ai/develop-with-ai">
|
||||
<div class="icon-wrapper">
|
||||
<docs-icon>auto_awesome</docs-icon>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>
|
||||
<strong>AI-forward</strong> resources and integrations to supercharge your development
|
||||
with AI
|
||||
</h3>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card" routerLink="/essentials">
|
||||
<div class="icon-wrapper">
|
||||
<docs-icon>grid_view</docs-icon>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>
|
||||
<strong>Opinionated & versatile,</strong> organized yet modular thanks to Angular
|
||||
components and dependency injection
|
||||
</h3>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card" routerLink="/essentials/signals">
|
||||
<div class="icon-wrapper">
|
||||
<docs-icon>sensors</docs-icon>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>
|
||||
<strong>Reactive</strong> and fast state updates with fine-grained reactivity based on
|
||||
Angular Signals
|
||||
</h3>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card" routerLink="/overview">
|
||||
<div class="icon-wrapper">
|
||||
<docs-icon>layers</docs-icon>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>
|
||||
<strong>Fully featured</strong> platform where everything works together with Angular's
|
||||
first-party modules for forms, routing, and more
|
||||
</h3>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="performance-section" id="performance">
|
||||
<div class="wrapper">
|
||||
<div class="pattern"></div>
|
||||
<div class="content">
|
||||
<h2>Where performance matters</h2>
|
||||
<h3>
|
||||
<section class="performance">
|
||||
<div class="section-content">
|
||||
<div class="performance-half">
|
||||
<h2>When performance matters</h2>
|
||||
<p class="secondary">
|
||||
Trusted by millions to build fast, reliable applications that scale with the size of your
|
||||
team
|
||||
</h3>
|
||||
<button
|
||||
class="docs-primary-btn"
|
||||
[attr.text]="'Get started'"
|
||||
routerLink="/guide/performance"
|
||||
</p>
|
||||
<div class="docs-card-grid">
|
||||
<a routerLink="/guide/signals" class="docs-card">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 -960 960 960"
|
||||
height="24px"
|
||||
width="24px"
|
||||
>
|
||||
<path
|
||||
d="M197-197q-54-55-85.5-127.5T80-480q0-84 31.5-156.5T197-763l57 57q-44 44-69 102t-25 124q0 67 25 125t69 101l-57 57Zm113-113q-32-33-51-76.5T240-480q0-51 19-94.5t51-75.5l57 57q-22 22-34.5 51T320-480q0 33 12.5 62t34.5 51l-57 57Zm170-90q-33 0-56.5-23.5T400-480q0-33 23.5-56.5T480-560q33 0 56.5 23.5T560-480q0 33-23.5 56.5T480-400Zm170 90-57-57q22-22 34.5-51t12.5-62q0-33-12.5-62T593-593l57-57q32 32 51 75.5t19 94.5q0 50-19 93.5T650-310Zm113 113-57-57q44-44 69-102t25-124q0-67-25-125t-69-101l57-57q54 54 85.5 126.5T880-480q0 83-31.5 155.5T763-197Z"
|
||||
/>
|
||||
</svg>
|
||||
<div class="card-content">
|
||||
<p>Reactivity with signals makes it a breeze to manage your state</p>
|
||||
</div>
|
||||
<span>Explore signals</span>
|
||||
</a>
|
||||
<a routerLink="/guide/routing/rendering-strategies" class="docs-card">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
>
|
||||
<path
|
||||
d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-507h560v-133H200v133Zm0 214h560v-134H200v134Zm0 213h560v-133H200v133Zm40-454v-80h80v80h-80Zm0 214v-80h80v80h-80Zm0 214v-80h80v80h-80Z"
|
||||
/>
|
||||
</svg>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
Meet your performance targets with SSR, SSG, hydration, and next generation deferred
|
||||
loading
|
||||
</p>
|
||||
</div>
|
||||
<span>Learn about rendering strategies</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="performance-half">
|
||||
<svg
|
||||
width="558"
|
||||
height="365"
|
||||
viewBox="0 0 558 365"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<!-- TODO: LINK -->
|
||||
Get started
|
||||
</button>
|
||||
<path
|
||||
d="M228.166 59.3864L234.455 85.9391C241.018 84.5704 247.58 83.2017 254.143 82.3805L250.588 55.2803C242.932 56.3752 235.549 57.7439 228.166 59.3864Z"
|
||||
fill="url(#paint0_linear_194_759)"
|
||||
/>
|
||||
<path
|
||||
d="M98.2778 145.614L120.427 161.765C124.255 156.29 128.631 151.089 133.006 146.162L112.771 127.821C107.575 133.57 102.653 139.592 98.2778 145.614Z"
|
||||
fill="url(#paint1_linear_194_759)"
|
||||
/>
|
||||
<path
|
||||
d="M63.8232 217.06L90.0743 224.451C91.715 218.155 93.9026 211.585 96.3636 205.563L70.9329 195.435C68.1984 202.552 66.0108 209.669 63.8232 217.06Z"
|
||||
fill="url(#paint2_linear_194_759)"
|
||||
/>
|
||||
<path
|
||||
d="M155.429 90.8662L170.468 113.587C175.937 110.028 181.68 106.469 187.696 103.458L174.844 79.3691C168.281 82.654 161.718 86.7601 155.429 90.8662Z"
|
||||
fill="url(#paint3_linear_194_759)"
|
||||
/>
|
||||
<path
|
||||
d="M424.502 146.435C428.877 151.363 433.252 156.564 437.081 162.038L459.23 145.888C454.855 139.866 449.933 133.843 445.011 128.095L424.502 146.435Z"
|
||||
fill="url(#paint4_linear_194_759)"
|
||||
/>
|
||||
<path
|
||||
d="M382.391 79.3691L369.539 103.458C375.281 106.469 381.023 110.028 386.766 113.587L401.806 90.8662C395.79 86.7601 389.227 82.9278 382.391 79.3691Z"
|
||||
fill="url(#paint5_linear_194_759)"
|
||||
/>
|
||||
<path
|
||||
d="M486.301 195.435L460.871 205.289C463.332 211.585 465.519 217.881 467.16 224.177L493.411 216.786C491.497 209.943 489.036 202.552 486.301 195.435Z"
|
||||
fill="url(#paint6_linear_194_759)"
|
||||
/>
|
||||
<path
|
||||
d="M363.523 13.6719L353.952 39.4034C454.581 71.1572 527.865 164.502 529.779 275.093H333.99L306.919 302.467H556.304L556.851 288.507C556.851 285.495 557.124 282.484 557.124 279.199C556.851 154.922 475.637 49.5318 363.523 13.6719Z"
|
||||
fill="url(#paint7_linear_194_759)"
|
||||
/>
|
||||
<path
|
||||
d="M227.892 274.82H27.7281C29.9157 138.224 141.483 27.6328 278.754 27.6328C285.317 27.6328 291.879 27.9065 298.169 28.454L322.506 3.81741C308.286 1.6275 293.52 0.258789 278.48 0.258789C125.349 0.258789 0.383301 125.358 0.383301 278.926C0.383301 281.937 0.383301 284.948 0.656749 288.233L1.20365 302.194H217.501L227.892 274.82Z"
|
||||
fill="url(#paint8_linear_194_759)"
|
||||
/>
|
||||
<path
|
||||
d="M341.373 13.9453L162.265 194.614L268.363 224.999L215.861 364.606L394.969 183.938L288.871 153.553L341.373 13.9453Z"
|
||||
fill="url(#paint9_linear_194_759)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_194_759"
|
||||
x1="224.18"
|
||||
y1="87.8605"
|
||||
x2="263.436"
|
||||
y2="48.6467"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_194_759"
|
||||
x1="102.734"
|
||||
y1="158.687"
|
||||
x2="131.291"
|
||||
y2="130.162"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear_194_759"
|
||||
x1="63.1336"
|
||||
y1="227.404"
|
||||
x2="100.224"
|
||||
y2="190.353"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint3_linear_194_759"
|
||||
x1="157.935"
|
||||
y1="110.828"
|
||||
x2="190.444"
|
||||
y2="78.3545"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint4_linear_194_759"
|
||||
x1="426.244"
|
||||
y1="161.616"
|
||||
x2="461.128"
|
||||
y2="126.768"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint5_linear_194_759"
|
||||
x1="368.074"
|
||||
y1="113.184"
|
||||
x2="405.694"
|
||||
y2="75.6042"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint6_linear_194_759"
|
||||
x1="459.571"
|
||||
y1="228.959"
|
||||
x2="499.852"
|
||||
y2="188.721"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint7_linear_194_759"
|
||||
x1="311.154"
|
||||
y1="306.775"
|
||||
x2="505.716"
|
||||
y2="112.419"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint8_linear_194_759"
|
||||
x1="20.4484"
|
||||
y1="321.544"
|
||||
x2="330.571"
|
||||
y2="11.7518"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint9_linear_194_759"
|
||||
x1="223.592"
|
||||
y1="-19.7554"
|
||||
x2="484.225"
|
||||
y2="256.555"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F941EA" />
|
||||
<stop offset="1" stop-color="#9138FF" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="explore-section" id="learn-more">
|
||||
<div class="title">
|
||||
<h2>What to learn more about Angular?</h2>
|
||||
<div class="pattern"></div>
|
||||
</div>
|
||||
<!-- -->
|
||||
|
||||
<div class="cards-grid">
|
||||
<!-- Card 1: Tutorials -->
|
||||
<a routerLink="/tutorials/learn-angular" class="explore-card">
|
||||
<div class="card-content">
|
||||
<p>
|
||||
<span class="emphasis">New to Angular?</span>
|
||||
Try our completely in browser tutorial lessons designed to give you hands on experience
|
||||
with Angular.
|
||||
</p>
|
||||
<span class="fake-button">Start coding <docs-icon>arrow_forward</docs-icon></span>
|
||||
<div class="editor-background"></div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Card 2: AI -->
|
||||
<a routerLink="/ai" class="explore-card">
|
||||
<div class="card-content">
|
||||
<p>
|
||||
<span class="emphasis">Are you an LLM or curious about AI in Angular?</span>
|
||||
Head over to our AI section to find prompts, strategies, best practices, examples, and
|
||||
more.
|
||||
</p>
|
||||
<span class="fake-button">Angular + AI <docs-icon>arrow_forward</docs-icon></span>
|
||||
<div class="angular-mcp-container">
|
||||
<div class="mcp-content">
|
||||
<div class="mcp-label">Angular MCP</div>
|
||||
<div class="mcp-pills">
|
||||
<span class="mcp-pill">get_best_practices</span>
|
||||
<span class="mcp-pill">ai_tutor</span>
|
||||
<span class="mcp-pill">find_examples</span>
|
||||
</div>
|
||||
</div>
|
||||
<section class="learn-more">
|
||||
<div class="section-content">
|
||||
<h2 id="learn-more">Want to learn more?</h2>
|
||||
<div class="docs-card-grid">
|
||||
<a routerLink="/tutorials/learn-angular" class="docs-card">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
|
||||
<path
|
||||
d="m188.15-529.46 108.7 46.15q19.15-38.3 41.57-75.42 22.43-37.11 48.5-71.04l-75.53-14.84q-3.08-.77-5.97.19-2.88.96-5.19 3.27L188.15-529.46Zm144.77 73.69 127.62 127.62q55.46-26 104.88-59 49.42-33 84.66-68.23 75.23-75.23 111.11-154.27 35.89-79.04 41.19-188.35-109.69 5.31-188.34 41-78.66 35.69-153.89 110.92-35.23 35.24-68.23 84.85-33 49.62-59 105.46Zm229.77-102.92q-18.08-17.69-18.08-43.92t18.08-44.31Q580.77-665 607.19-665t44.5 18.08q18.08 18.08 18.08 44.31 0 26.23-18.08 43.92-18.08 18.08-44.5 18.08t-44.5-18.08Zm-29.23 374.92 112.08-111.69q2.3-2.31 3.07-5.39.77-3.07.39-5.77l-15.23-75.53q-33.93 25.69-70.85 48.11-36.92 22.42-75.61 41.96l46.15 108.31Zm314.08-659q5.53 126.39-34.97 228.19-40.5 101.81-129.11 190.04-2.54 2.54-4.88 5.08-2.35 2.54-4.89 4.69l19.69 98.85q2.62 14.61-1.69 28.03-4.31 13.43-14.54 23.66L518.08-104.54l-75.77-177.61-156.16-155.77-177.22-76.54 159.3-158.69q10.62-10.23 24.04-14.73t28.04-1.5l99.23 19.69q2.54-2.15 4.69-4.39 2.16-2.23 4.69-4.38 88.62-88.61 190.23-129.23 101.62-40.61 228.39-35.08ZM175.16-320q29.23-29.61 71.07-29.54 41.85.08 71.46 29.31 29.23 29.23 28.92 71.08-.3 41.84-29.53 71.46-23.7 23.3-72.43 38.96-48.73 15.65-134.26 26.04 10.38-85.54 25.73-134.77 15.34-49.23 39.04-72.54Zm31.61 33q-13.61 14.61-24.42 44.88-10.81 30.27-17.27 74.5 44.23-6.84 74.5-17.65 30.27-10.81 44.88-24.81 17.08-15.46 17.39-38.46.3-23-16.16-40.08-17.07-16.46-40.07-15.96T206.77-287Z"
|
||||
/>
|
||||
</svg>
|
||||
<div class="card-content">
|
||||
<h3>New to Angular?</h3>
|
||||
<p>
|
||||
Try our completely in browser tutorial lessons designed to give you hands on
|
||||
experience with Angular.
|
||||
</p>
|
||||
<p class="secondary">
|
||||
Recommended for developers new to Angular looking to dive right into the code
|
||||
</p>
|
||||
<span>Start coding</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Card 3: Overview -->
|
||||
<a routerLink="/overview" class="explore-card">
|
||||
<div class="card-content">
|
||||
<p>
|
||||
<span class="emphasis">Why Angular?</span>
|
||||
Learn about Angular, its benefits, and if it's right for you.
|
||||
</p>
|
||||
<div class="logo-background"></div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Card 4: Essentials -->
|
||||
<a routerLink="/essentials" class="explore-card">
|
||||
<div class="card-content">
|
||||
<p>
|
||||
<span class="emphasis">More of a reader?</span>
|
||||
Our essentials guides are designed to help you understand Angular fundamentals in the
|
||||
time it would take to finish a cup of coffee (or a tea).
|
||||
</p>
|
||||
<span class="fake-button">Angular concepts <docs-icon>arrow_forward</docs-icon></span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="learn-more-bottom-section" id="bottom">
|
||||
<div class="pattern"></div>
|
||||
<div class="content">
|
||||
<h2>Want to learn more about Angular ?</h2>
|
||||
<button
|
||||
class="docs-primary-btn"
|
||||
[attr.text]="'Learn more'"
|
||||
aria-label="Learn more"
|
||||
routerLink="/overview"
|
||||
>
|
||||
Learn more
|
||||
</button>
|
||||
</a>
|
||||
<a routerLink="/essentials" class="docs-card">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
|
||||
<path
|
||||
d="M557.69-577.46v-38q32.62-15.15 68.27-22.73 35.66-7.58 74.04-7.58 24.08 0 46.77 3.42 22.69 3.43 45.54 9.04v35.54q-22.46-7.85-44.66-11.38-22.19-3.54-47.65-3.54-38.38 0-74.35 9.11-35.96 9.12-67.96 26.12Zm0 219.23v-39.38q31.85-14.85 68.08-22.27 36.23-7.43 74.23-7.43 24.08 0 46.77 3.43 22.69 3.42 45.54 9.03v35.54q-22.46-7.84-44.66-11.38-22.19-3.54-47.65-3.54-38.38 0-74.35 9.19-35.96 9.19-67.96 26.81Zm0-109.23v-38.77q32.62-15.15 68.27-22.73 35.66-7.58 74.04-7.58 24.08 0 46.77 3.42 22.69 3.43 45.54 9.04v35.54q-22.46-7.85-44.66-11.38-22.19-3.54-47.65-3.54-38.38 0-74.35 9.5-35.96 9.5-67.96 26.5ZM251.08-304.62q54.53 0 106.11 12.89 51.58 12.88 101.73 39.42v-417.38q-45-31.92-99.04-48.81-54.04-16.88-108.8-16.88-37.61 0-69.5 7.38t-67.73 20.23q-4.62 1.54-6.54 4.42-1.92 2.89-1.92 6.35v406.31q0 5 3.84 7.5 3.85 2.5 8.46.96 25.62-11.31 60.7-16.85 35.07-5.54 72.69-5.54Zm253.23 52.31q50.38-26.54 99.92-39.42 49.54-12.89 104.69-12.89 37.62 0 73.5 5.23 35.89 5.24 59.89 13.31 4.61 1.93 8.46-.57 3.84-2.5 3.84-7.89V-697q0-3.46-1.92-6.15-1.92-2.7-6.54-4.62-33.61-14.69-66.43-21.15-32.83-6.46-70.8-6.46-55.15 0-107.57 16.88-52.43 16.89-97.04 48.81v417.38Zm-22.89 67.69q-50.8-35.69-109.65-54.84-58.85-19.16-120.69-19.16-32.47 0-63.77 6.7-31.31 6.69-62.85 17.38-23.1 10.23-43.78-4.34T60-279.46v-420.31q0-15.77 7.77-29t22.54-19.92q37.77-16.54 78.34-24.31t82.43-7.77q62.19 0 120.75 17.39Q430.38-746 481.62-711q50.23-35 108.15-52.38 57.92-17.39 119.15-17.39 41.65 0 82.02 7.77t78.14 24.31q14.76 6.61 22.84 19.88t8.08 29.04v420.31q0 27.12-22.31 41.67-22.31 14.56-45.08 2.48-30.15-10.92-61.15-17.11-31-6.2-62.54-6.2-61.94 0-119.32 19.46-57.37 19.47-108.18 54.54ZM282.15-493.23Z"
|
||||
/>
|
||||
</svg>
|
||||
<div class="card-content">
|
||||
<h3>More of a reader?</h3>
|
||||
<p>
|
||||
Our essentials guides are designed to help you understand Angular fundamentals in the
|
||||
time it would take to finish a cup of coffee (or tea).
|
||||
</p>
|
||||
<p class="secondary">
|
||||
Recommended for developers with framework experience but want quick overview of
|
||||
concepts
|
||||
</p>
|
||||
<span>Angular concepts</span>
|
||||
</div>
|
||||
</a>
|
||||
<a routerLink="/overview" class="docs-card">
|
||||
<svg class="angular-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 223 236">
|
||||
<g clip-path="url(#a)">
|
||||
<path
|
||||
fill="url(#b)"
|
||||
d="m222.077 39.192-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z"
|
||||
/>
|
||||
<path
|
||||
fill="url(#c)"
|
||||
d="m222.077 39.192-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="b"
|
||||
x1="49.009"
|
||||
x2="225.829"
|
||||
y1="213.75"
|
||||
y2="129.722"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#E40035" />
|
||||
<stop offset=".24" stop-color="#F60A48" />
|
||||
<stop offset=".352" stop-color="#F20755" />
|
||||
<stop offset=".494" stop-color="#DC087D" />
|
||||
<stop offset=".745" stop-color="#9717E7" />
|
||||
<stop offset="1" stop-color="#6C00F5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="c"
|
||||
x1="41.025"
|
||||
x2="156.741"
|
||||
y1="28.344"
|
||||
y2="160.344"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#FF31D9" />
|
||||
<stop offset="1" stop-color="#FF5BE1" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
<clipPath id="a">
|
||||
<path fill="#fff" d="M0 0h223v236H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<div class="card-content">
|
||||
<h3>Why Angular?</h3>
|
||||
<p>Learn about Angular, its benefits, and if it's right for you.</p>
|
||||
<p class="secondary">
|
||||
Recommended for developers seeking to learn more about the Angular framework
|
||||
</p>
|
||||
<span>About Angular</span>
|
||||
</div>
|
||||
</a>
|
||||
<a routerLink="/ai" class="docs-card">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<polygon points="19,9 20.25,6.25 23,5 20.25,3.75 19,1 17.75,3.75 15,5 17.75,6.25" />
|
||||
<polygon
|
||||
points="19,15 17.75,17.75 15,19 17.75,20.25 19,23 20.25,20.25 23,19 20.25,17.75"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.2"
|
||||
d="M 11.5 9.5 L 9 4 L 6.5 9.5 L 1 12 l 5.5 2.5 L 9 20 l 2.5 -5.5 L 17 12 L 11.5 9.5 z z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
<div class="card-content">
|
||||
<h3>Are you an LLM or curious about AI in Angular?</h3>
|
||||
<p>
|
||||
Head over to our AI section to find prompts, strategies, best practices, examples, and
|
||||
more.
|
||||
</p>
|
||||
<p class="secondary">
|
||||
Recommended for robots... and developers who want to get the most out of Angular and
|
||||
AI
|
||||
</p>
|
||||
<span>Angular + AI</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,34 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Tab, TabContent, TabList, TabPanel, Tabs} from '@angular/aria/tabs';
|
||||
import {A11yModule} from '@angular/cdk/a11y';
|
||||
import {ChangeDetectionStrategy, Component, inject} from '@angular/core';
|
||||
import {IS_SEARCH_DIALOG_OPEN, IconComponent, TextField} from '@angular/docs';
|
||||
import {ActivatedRoute, RouterLink} from '@angular/router';
|
||||
import {CodeHighligher} from './code-highlighting/code-highlighter';
|
||||
import {ControlFlowExample} from './components/control-flow/control-flow-example';
|
||||
import {DeferrableViewsExample} from './components/deferrable-views-example/deferrable-views-example';
|
||||
import {HydrationExample} from './components/hydration-example/hydration-example';
|
||||
import {SignalsDemo} from './components/signals-demo/signals-demo';
|
||||
|
||||
@Component({
|
||||
selector: 'adev-home',
|
||||
imports: [
|
||||
RouterLink,
|
||||
TextField,
|
||||
TabList,
|
||||
Tab,
|
||||
Tabs,
|
||||
TabPanel,
|
||||
TabContent,
|
||||
IconComponent,
|
||||
A11yModule,
|
||||
SignalsDemo,
|
||||
ControlFlowExample,
|
||||
DeferrableViewsExample,
|
||||
HydrationExample,
|
||||
],
|
||||
imports: [RouterLink],
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
@@ -41,11 +19,4 @@ import {SignalsDemo} from './components/signals-demo/signals-demo';
|
||||
export default class Home {
|
||||
private readonly activatedRoute = inject(ActivatedRoute);
|
||||
protected readonly isUwu = 'uwu' in this.activatedRoute.snapshot.queryParams;
|
||||
private readonly codeHighlighter = inject(CodeHighligher);
|
||||
|
||||
protected readonly displaySearchDialog = inject(IS_SEARCH_DIALOG_OPEN);
|
||||
|
||||
openSearch() {
|
||||
this.displaySearchDialog.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
var(--symbolic-yellow) var(--item-attr-base-mix),
|
||||
var(--octonary-contrast)
|
||||
);
|
||||
color: var(--page-background);
|
||||
color: var(--gray-1000);
|
||||
}
|
||||
|
||||
&.adev-experimental {
|
||||
@@ -119,7 +119,7 @@
|
||||
var(--symbolic-green) var(--item-attr-base-mix),
|
||||
var(--octonary-contrast)
|
||||
);
|
||||
color: var(--page-background);
|
||||
color: var(--gray-1000);
|
||||
}
|
||||
|
||||
&.adev-deprecated {
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
color: var(--quaternary-contrast);
|
||||
color: var(--gray-400);
|
||||
background-color: var(--page-background);
|
||||
border-block-start: 1px solid var(--senary-contrast);
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
|
||||
@@ -46,6 +46,8 @@ h4 {
|
||||
}
|
||||
|
||||
.wizard {
|
||||
padding-inline: 1rem;
|
||||
|
||||
.show-button {
|
||||
display: block;
|
||||
margin-block-start: 2rem;
|
||||
@@ -161,15 +163,9 @@ h4 {
|
||||
}
|
||||
}
|
||||
|
||||
.adev-complexity-1 {
|
||||
--badge-color: var(--super-green);
|
||||
}
|
||||
.adev-complexity-2 {
|
||||
--badge-color: var(--bright-blue);
|
||||
}
|
||||
.adev-complexity-3 {
|
||||
--badge-color: var(--symbolic-orange);
|
||||
}
|
||||
.adev-complexity-1 { --badge-color: var(--super-green); }
|
||||
.adev-complexity-2 { --badge-color: var(--bright-blue); }
|
||||
.adev-complexity-3 { --badge-color: var(--symbolic-orange); }
|
||||
|
||||
// Code blocks are generable from the markdown, we need to opt-out of the scoping
|
||||
::ng-deep code {
|
||||
|
||||
@@ -9,8 +9,7 @@ ts_project(
|
||||
tsconfig = {
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"moduleResolution": "node",
|
||||
"types": ["node"],
|
||||
"rootDir": ".",
|
||||
"skipLibCheck": True,
|
||||
|
||||
@@ -341,12 +341,6 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
path: 'guide/di/di-in-action',
|
||||
contentPath: 'guide/di/di-in-action',
|
||||
},
|
||||
{
|
||||
label: 'Debugging and troubleshooting DI',
|
||||
path: 'guide/di/debugging-and-troubleshooting-di',
|
||||
contentPath: 'guide/di/debugging-and-troubleshooting-di',
|
||||
status: 'new',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -363,11 +357,6 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
path: 'guide/routing/define-routes',
|
||||
contentPath: 'guide/routing/define-routes',
|
||||
},
|
||||
{
|
||||
label: 'Route Loading Strategies',
|
||||
path: 'guide/routing/loading-strategies',
|
||||
contentPath: 'guide/routing/loading-strategies',
|
||||
},
|
||||
{
|
||||
label: 'Show routes with Outlets',
|
||||
path: 'guide/routing/show-routes-with-outlets',
|
||||
@@ -496,13 +485,6 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
category: 'Signal Forms',
|
||||
status: 'new',
|
||||
},
|
||||
{
|
||||
label: 'Async operations',
|
||||
path: 'guide/forms/signals/async-operations',
|
||||
contentPath: 'guide/forms/signals/async-operations',
|
||||
category: 'Signal Forms',
|
||||
status: 'new',
|
||||
},
|
||||
{
|
||||
label: 'Custom controls',
|
||||
path: 'guide/forms/signals/custom-controls',
|
||||
@@ -518,7 +500,7 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
status: 'new',
|
||||
},
|
||||
{
|
||||
label: 'Migrating from Reactive Forms',
|
||||
label: 'Migrating from Legacy Forms',
|
||||
path: 'guide/forms/signals/migration',
|
||||
contentPath: 'guide/forms/signals/migration',
|
||||
category: 'Signal Forms',
|
||||
@@ -1082,78 +1064,33 @@ export const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
},
|
||||
{
|
||||
label: 'Performance',
|
||||
preserveOtherCategoryOrder: true,
|
||||
children: [
|
||||
{
|
||||
label: 'Overview',
|
||||
path: 'best-practices/performance',
|
||||
contentPath: 'best-practices/performance/overview',
|
||||
},
|
||||
|
||||
// Loading Performance
|
||||
{
|
||||
label: 'Lazy-loaded routes',
|
||||
path: 'best-practices/performance/lazy-loaded-routes',
|
||||
contentPath: 'guide/routing/loading-strategies',
|
||||
category: 'Loading Performance',
|
||||
},
|
||||
{
|
||||
label: 'Deferred loading with @defer',
|
||||
path: 'best-practices/performance/defer',
|
||||
contentPath: 'guide/templates/defer',
|
||||
category: 'Loading Performance',
|
||||
},
|
||||
{
|
||||
label: 'Image optimization',
|
||||
path: 'best-practices/performance/image-optimization',
|
||||
contentPath: 'guide/image-optimization',
|
||||
category: 'Loading Performance',
|
||||
},
|
||||
{
|
||||
label: 'Server-side rendering',
|
||||
path: 'best-practices/performance/ssr',
|
||||
contentPath: 'guide/ssr',
|
||||
category: 'Loading Performance',
|
||||
},
|
||||
|
||||
// Runtime Performance
|
||||
{
|
||||
label: 'Overview',
|
||||
path: 'best-practices/runtime-performance',
|
||||
contentPath: 'best-practices/runtime-performance/overview',
|
||||
category: 'Runtime Performance',
|
||||
},
|
||||
{
|
||||
label: 'Zoneless',
|
||||
path: 'guide/zoneless',
|
||||
contentPath: 'guide/zoneless',
|
||||
category: 'Runtime Performance',
|
||||
},
|
||||
{
|
||||
label: 'Slow computations',
|
||||
path: 'best-practices/slow-computations',
|
||||
contentPath: 'best-practices/runtime-performance/slow-computations',
|
||||
category: 'Runtime Performance',
|
||||
},
|
||||
{
|
||||
label: 'Skipping component subtrees',
|
||||
path: 'best-practices/skipping-subtrees',
|
||||
contentPath: 'best-practices/runtime-performance/skipping-subtrees',
|
||||
category: 'Runtime Performance',
|
||||
},
|
||||
{
|
||||
label: 'Zone pollution',
|
||||
path: 'best-practices/zone-pollution',
|
||||
contentPath: 'best-practices/runtime-performance/zone-pollution',
|
||||
category: 'Runtime Performance',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Chrome DevTools profiling',
|
||||
label: 'Slow computations',
|
||||
path: 'best-practices/slow-computations',
|
||||
contentPath: 'best-practices/runtime-performance/slow-computations',
|
||||
},
|
||||
{
|
||||
label: 'Skipping component subtrees',
|
||||
path: 'best-practices/skipping-subtrees',
|
||||
contentPath: 'best-practices/runtime-performance/skipping-subtrees',
|
||||
},
|
||||
{
|
||||
label: 'Profiling with the Chrome DevTools',
|
||||
path: 'best-practices/profiling-with-chrome-devtools',
|
||||
contentPath: 'best-practices/runtime-performance/profiling-with-chrome-devtools',
|
||||
category: 'Runtime Performance',
|
||||
},
|
||||
{label: 'Zoneless', path: 'guide/zoneless', contentPath: 'guide/zoneless'},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -10,7 +10,6 @@ copy_to_directory(
|
||||
"//adev/src/content/ai",
|
||||
"//adev/src/content/aria:aria_docs",
|
||||
"//adev/src/content/best-practices",
|
||||
"//adev/src/content/best-practices/performance",
|
||||
"//adev/src/content/best-practices/runtime-performance",
|
||||
"//adev/src/content/cdk:cdk_docs",
|
||||
"//adev/src/content/cli:cli_docs",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='489.63' height='453.44' viewBox='4.516 2.755 489.63 453.44'><filter id='filter3_n_5746_17015' x='339.133' y='4855' width='490.001' height='453.444' filterUnits='userSpaceOnUse' color-interpolation-filters='sRGB'><feFlood flood-opacity='0' result='BackgroundImageFix'/><feBlend mode='normal' in='SourceGraphic' in2='BackgroundImageFix' result='shape'/><feTurbulence type='fractalNoise' baseFrequency='4.6613855361938477 4.6613855361938477' stitchTiles='stitch' numOctaves='3' result='noise' seed='9369'/><feColorMatrix in='noise' type='luminanceToAlpha' result='alphaNoise'/><feComponentTransfer in='alphaNoise' result='coloredNoise1'><feFuncA type='discrete' tableValues='1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 '/></feComponentTransfer><feComposite operator='in' in2='shape' in='coloredNoise1' result='noise1Clipped'/><feFlood flood-color='rgba(0, 0, 0, 0.25)' result='color1Flood'/><feComposite operator='in' in2='noise1Clipped' in='color1Flood' result='color1'/><feMerge result='effect1_noise_5746_17015'><feMergeNode in='shape'/><feMergeNode in='color1'/></feMerge></filter><g xmlns='http://www.w3.org/2000/svg' filter='url(#filter3_n_5746_17015)' opacity='.5' transform='translate(-334.617 -4852.245)'><path fill='#121114' d='M828.763 5154.15 589.175 4855l172.14 72.78z'/><mask id='a' width='240' height='300' x='589' y='4855' maskUnits='userSpaceOnUse' style='mask-type: luminance'><path fill='#fff' d='M828.763 5154.15 589.175 4855l172.14 72.78z'/></mask><g mask='url(#a)'><mask id='b' width='240' height='300' x='589' y='4855' maskUnits='userSpaceOnUse' style='mask-type: luminance'><path fill='#fff' d='M828.763 5154.15 589.175 4855l172.14 72.78z'/></mask><g mask='url(#b)'><path fill='#9d43f7' d='M828.763 5154.15 589.175 4855l172.14 72.78z'/></g></g><path fill='#33264e' d='m828.762 5154.15-20.165 27.05-239.588-299.15 20.166-27.05z'/><path fill='#381e37' d='m664.565 5096.27-20.154 27.05-114.121 7.97 20.165-27.04z'/><path fill='#121114' d='m550.455 5104.25 16.865-139.15 97.245 131.17z'/><mask id='c' width='115' height='140' x='550' y='4965' maskUnits='userSpaceOnUse' style='mask-type: luminance'><path fill='#fff' d='m550.455 5104.25 16.865-139.15 97.245 131.17z'/></mask><g mask='url(#c)'><mask id='d' width='115' height='140' x='550' y='4965' maskUnits='userSpaceOnUse' style='mask-type: luminance'><path fill='#fff' d='m550.455 5104.25 16.865-139.15 97.245 131.17z'/></mask><g mask='url(#d)'><path fill='#f85de3' d='m550.455 5104.25 16.865-139.15 97.245 131.17z'/></g></g><path fill='#33264e' d='m550.455 5104.25-20.165 27.04 16.864-139.14 20.166-27.05z'/><path fill='#1a1a1a' d='m752.201 5212.53-20.166 27.05-90.643 68.86 20.165-27.05z'/><path fill='#121114' d='m541.015 5174.27 173.48-12.13 37.706 50.39-90.643 68.86-127.145-53.63z'/><mask id='e' width='219' height='120' x='534' y='5162' maskUnits='userSpaceOnUse' style='mask-type: luminance'><path fill='#fff' d='m541.015 5174.27 173.48-12.13 37.706 50.39-90.643 68.86-127.145-53.63z'/></mask><g mask='url(#e)'><path fill='#f759ce' d='m661.558 5281.39-127.145-53.63 6.602-53.49 173.48-12.13 37.706 50.39z'/></g><path fill='#171218' d='m661.557 5281.39-20.165 27.05-127.145-53.64 20.166-27.04z'/><path fill='#1a131a' d='m534.413 5227.76-20.166 27.04 6.602-53.48 20.165-27.05z'/><path fill='#121114' d='m426.746 5182.26-67.447-226.38 122.785-93.39z'/><mask id='f' width='124' height='321' x='359' y='4862' maskUnits='userSpaceOnUse' style='mask-type: luminance'><path fill='#fff' d='m426.746 5182.26-67.447-226.38 122.785-93.39z'/></mask><g mask='url(#f)'><mask id='g' width='124' height='321' x='359' y='4862' maskUnits='userSpaceOnUse' style='mask-type: luminance'><path fill='#fff' d='m482.084 4862.49-55.338 319.77-67.447-226.38z'/></mask><g mask='url(#g)'><path fill='#852c49' d='m482.084 4862.49-55.338 319.77-67.447-226.38z'/></g></g><path fill='#311822' d='m426.747 5182.26-20.166 27.05-67.448-226.38 20.166-27.05z'/></g></svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user