diff --git a/.ai/skills/CHANGELOG.md b/.ai/skills/CHANGELOG.md index 6e2a692fd0..07962f9a3c 100644 --- a/.ai/skills/CHANGELOG.md +++ b/.ai/skills/CHANGELOG.md @@ -14,7 +14,8 @@ including content-unchanged files, per the blog-creator convention). | Change | File(s) | |---|---| | igniteui-topic-frontmatter split: SKILL.md becomes a router (scope, audit-first mode, task table, hard boundaries); the field checks + severity ladder move to `references/audit-rules.md`; report shape + apply procedure move to `references/report-format.md`. `description` unchanged (adapter byte-match preserved). | igniteui-topic-frontmatter/* | -| igniteui-doc-topics slimmed: SKILL.md keeps identity, two modes, compass, composite principle, task table, grounding boundaries. Create steps 1–7 (6a–6e) + the category/index structure move to `references/create-workflow.md`; the 5 audit-workflow steps move into `audit-rubric.md`. `description` unchanged. | igniteui-doc-topics/SKILL.md, references/create-workflow.md, references/audit-rubric.md | +| igniteui-doc-topics slimmed: SKILL.md keeps identity, two modes, compass, composite principle, task table, grounding boundaries. Create steps 1–7 (6a–6f) + the category/index structure move to `references/create-workflow.md`; the 5 audit-workflow steps move into `audit-rubric.md`. `description` unchanged. | igniteui-doc-topics/SKILL.md, references/create-workflow.md, references/audit-rubric.md | +| Accessibility generation is source-first: derive DOM, roles, ARIA, focus/state behavior, and keyboard actions from component templates and typed source; use event handlers only for interaction evidence and require official sources for conformance claims. | igniteui-doc-topics/references/house-style.md, references/create-workflow.md | | Dedup (D2-03 stage 2): the section→mode map is no longer restated in SKILL.md — it is the "Diátaxis mode" column of house-style's canonical section table; SKILL.md keeps only the one-section-one-mode rule and the concrete mode-bleed examples. The category blueprint now lives in house-style + create-workflow only. Stale pointers fixed (house-style intro pointed at a SKILL.md map that moved; body-support bullet pointed at "Create workflow step 4" which now lives in create-workflow.md). | igniteui-doc-topics/SKILL.md, references/house-style.md | | Set-level README.md added: human-readable intent, file map, authority chain, and the five-step update procedure (edit references not routers; uniform version bump; adapter byte-match; changelog entry; resolve ‹VERIFY› by pre-committed outcome). | README.md | | Set-wide version line: every file now carries `Version: v3 · 2026-08-14 · igniteui doc-skill set`, including content-unchanged house-style and diataxis-cheatsheet (the cheatsheet gains its first version line). | all files | diff --git a/.ai/skills/igniteui-doc-topics/references/create-workflow.md b/.ai/skills/igniteui-doc-topics/references/create-workflow.md index 4d2b677c27..db35f97ca8 100644 --- a/.ai/skills/igniteui-doc-topics/references/create-workflow.md +++ b/.ai/skills/igniteui-doc-topics/references/create-workflow.md @@ -16,6 +16,12 @@ mechanics, and the frontmatter contract live in `house-style.md`; run the rubric matching Indigo.Design component documentation under `https://www.infragistics.com/products/indigo-design/help/components/` and use its component structure as input for Usage subsection suggestions. + For the Accessibility section, inspect the component template/render method and typed source + first: extract rendered native elements, `role`, `aria-*` attributes, focus and disabled + conditions, and validation/selection state mapping. Read keyboard and pointer event handlers to + derive interaction and state-change facts. Use the API registry to verify public property and + event names. Generate platform-specific differences with ``, and mark unresolved + facts with `‹VERIFY: source fact needed›` rather than inferring them from generic HTML behavior. 4. **Scaffold frontmatter** — the metadata contract lives in `house-style.md` → "File format & frontmatter"; this step orders the work, it does not restate the rules. Apply the contract to every topic type, including category/index topics. diff --git a/.ai/skills/igniteui-doc-topics/references/house-style.md b/.ai/skills/igniteui-doc-topics/references/house-style.md index baaee48eaf..3412a1a42e 100644 --- a/.ai/skills/igniteui-doc-topics/references/house-style.md +++ b/.ai/skills/igniteui-doc-topics/references/house-style.md @@ -300,6 +300,27 @@ when its styling isn't shown as copyable code. `## Accessibility` always carries three `###` sub-sections, in this order. All three are **reference** mode: statements of fact in tables and short lists — no steps, no marketing. +#### Source-first generation contract + +Generate the Accessibility section from the component implementation before writing prose. Inspect +the component template/render method and typed source for the rendered native elements, `role`, +`aria-*` attributes, focus/tab-order conditions, disabled handling, and indeterminate or validation +state mapping. Inspect keyboard and pointer event handlers to derive the key-to-action table and +state transitions. Inspect the public API registry to verify property and event names, then map each +fact to the platform that actually implements it. + +- Treat rendered template/source as the authority for DOM, roles, ARIA attributes, and default state + behavior; treat the topic's existing prose as evidence to re-check, never as the source. +- Treat event handlers as evidence for interaction and state changes only. An event name does not + prove an accessible name, role, state, or WCAG conformance claim. +- For xplat topics, emit shared facts once and use `` when Angular differs from the + Web Components implementation or its React/Blazor wrappers. +- Include only verified attributes, events, and state behavior. If source is unavailable or a fact + cannot be resolved, write `‹VERIFY: source fact needed›` or omit it; never infer ARIA behavior from + a component name or a generic HTML pattern. +- Derive the compliance table only from behavior verified in the section and an official product + accessibility statement. Do not generate blanket WCAG/Section 508 compliance claims. + 1. **`### Keyboard Interaction`** — one key → action table, verified against the component's key handlers. Note how the component is reached (Tab) and any condition that removes it from the tab order. diff --git a/.gitattributes b/.gitattributes index 0a30339b0f..ccf35976ff 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ *.md text eol=lf *.mdx text eol=lf -.github/workflows/*.lock.yml linguist-generated=true merge=ours \ No newline at end of file +.github/workflows/*.lock.yml linguist-generated=true \ No newline at end of file diff --git a/.github/agents/agentic-workflows.md b/.github/agents/agentic-workflows.md new file mode 100644 index 0000000000..08c6d9a24f --- /dev/null +++ b/.github/agents/agentic-workflows.md @@ -0,0 +1,233 @@ +--- +name: Agentic Workflows +description: GitHub Agentic Workflows (gh-aw) - Create, debug, and upgrade AI-powered workflows with intelligent prompt routing. +disable-model-invocation: true +--- + +# GitHub Agentic Workflows Agent + +This agent helps you work with **GitHub Agentic Workflows (gh-aw)**, a CLI extension for creating AI-powered workflows in natural language using markdown files. + +## Repository Instructions Overlay + +If `.github/aw/instructions.md` exists, load it with: +@.github/aw/instructions.md + +Precedence: repository overlay instructions override defaults in this agent when they conflict. + +## What This Agent Does + +This is a **dispatcher agent** that routes your request to the appropriate specialized prompt based on your task: + +- **Creating new workflows**: Routes to `create` prompt +- **Updating existing workflows**: Routes to `update` prompt +- **Debugging workflows**: Routes to `debug` prompt +- **Upgrading workflows**: Routes to `upgrade-agentic-workflows` prompt +- **Creating report-generating workflows**: Routes to `report` prompt — consult this whenever the workflow posts status updates, audits, analyses, or any structured output as issues, discussions, or comments +- **Creating shared components**: Routes to `create-shared-agentic-workflow` prompt +- **Fixing Dependabot PRs**: Routes to `dependabot` prompt — use this when Dependabot opens PRs that modify generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`). Never merge those PRs directly; instead update the source `.md` files and rerun `gh aw compile --dependabot` to bundle all fixes +- **Analyzing test coverage**: Routes to `test-coverage` prompt — consult this whenever the workflow reads, analyzes, or reports on test coverage data from PRs or CI runs +- **Rendering ASCII charts in markdown**: Routes to `asciicharts` guide — consult this whenever the workflow needs compact charts that render reliably in GitHub issues, comments, or discussions +- **CLI commands and triggering workflows**: Routes to `cli-commands` guide — consult this whenever the user asks how to run, compile, debug, or manage workflows from the command line, or when they need the MCP tool equivalent of a `gh aw` command +- **Reducing token consumption / cost optimization**: Routes to `token-optimization` guide — consult this whenever the user asks how to reduce token usage, lower costs, speed up workflows, or measure the impact of prompt changes with experiments +- **Choosing workflow architectures and design patterns**: Routes to `patterns` guide — consult this whenever the user asks for strategy, architecture, operating models, or pattern selection for agentic workflows + +Workflows may optionally include: + +- **Project tracking / monitoring** (GitHub Projects updates, status reporting) +- **Orchestration / coordination** (one workflow assigning agents or dispatching and coordinating other workflows) + +## Files This Applies To + +- Workflow files: `.github/workflows/*.md` and `.github/workflows/**/*.md` +- Workflow lock files: `.github/workflows/*.lock.yml` +- Shared components: `.github/workflows/shared/*.md` +- Configuration: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/github-agentic-workflows.md` + +## Problems This Solves + +- **Workflow Creation**: Design secure, validated agentic workflows with proper triggers, tools, and permissions +- **Workflow Debugging**: Analyze logs, identify missing tools, investigate failures, and fix configuration issues +- **Version Upgrades**: Migrate workflows to new gh-aw versions, apply codemods, fix breaking changes +- **Component Design**: Create reusable shared workflow components that wrap MCP servers + +## How to Use + +When you interact with this agent, it will: + +1. **Understand your intent** - Determine what kind of task you're trying to accomplish +2. **Route to the right prompt** - Load the specialized prompt file for your task +3. **Execute the task** - Follow the detailed instructions in the loaded prompt + +## Available Prompts + +> **Note**: The prompt and reference files listed below are located in the [`github/gh-aw`](https://github.com/github/gh-aw) repository and are **not available locally** in this repository. Load them from their public URLs. + +### Create New Workflow +**Load when**: User wants to create a new workflow from scratch, add automation, or design a workflow that doesn't exist yet + +**Prompt file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/create-agentic-workflow.md` + +**Use cases**: +- "Create a workflow that triages issues" +- "I need a workflow to label pull requests" +- "Design a weekly research automation" + +### Update Existing Workflow +**Load when**: User wants to modify, improve, or refactor an existing workflow + +**Prompt file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/update-agentic-workflow.md` + +**Use cases**: +- "Add web-fetch tool to the issue-classifier workflow" +- "Update the PR reviewer to use discussions instead of issues" +- "Improve the prompt for the weekly-research workflow" + +### Debug Workflow +**Load when**: User needs to investigate, audit, debug, or understand a workflow, troubleshoot issues, analyze logs, or fix errors + +**Prompt file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/debug-agentic-workflow.md` + +**Use cases**: +- "Why is this workflow failing?" +- "Analyze the logs for workflow X" +- "Investigate missing tool calls in run #12345" + +### Upgrade Agentic Workflows +**Load when**: User wants to upgrade workflows to a new gh-aw version or fix deprecations + +**Prompt file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/upgrade-agentic-workflows.md` + +**Use cases**: +- "Upgrade all workflows to the latest version" +- "Fix deprecated fields in workflows" +- "Apply breaking changes from the new release" + +### Create a Report-Generating Workflow +**Load when**: The workflow being created or updated produces reports — recurring status updates, audit summaries, analyses, or any structured output posted as a GitHub issue, discussion, or comment + +**Prompt file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/report.md` + +**Use cases**: +- "Create a weekly CI health report" +- "Post a daily security audit to Discussions" +- "Add a status update comment to open PRs" + +### Create Shared Agentic Workflow +**Load when**: User wants to create a reusable workflow component or wrap an MCP server + +**Prompt file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/create-shared-agentic-workflow.md` + +**Use cases**: +- "Create a shared component for Notion integration" +- "Wrap the Slack MCP server as a reusable component" +- "Design a shared workflow for database queries" + +### Fix Dependabot PRs +**Load when**: User needs to close or fix open Dependabot PRs that update dependencies in generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`) + +**Prompt file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/dependabot.md` + +**Use cases**: +- "Fix the open Dependabot PRs for npm dependencies" +- "Bundle and close the Dependabot PRs for workflow dependencies" +- "Update @playwright/test to fix the Dependabot PR" + +### Analyze Test Coverage +**Load when**: The workflow reads, analyzes, or reports test coverage — whether triggered by a PR, a schedule, or a slash command. Always consult this prompt before designing the coverage data strategy. + +**Prompt file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/test-coverage.md` + +**Use cases**: +- "Create a workflow that comments coverage on PRs" +- "Analyze coverage trends over time" +- "Add a coverage gate that blocks PRs below a threshold" + +### CLI Commands Reference +**Load when**: The user asks how to run, compile, debug, or manage workflows from the command line; needs the MCP tool equivalent of a `gh aw` command; or is in a restricted environment (e.g., Copilot Cloud) without direct CLI access. + +**Reference file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/cli-commands.md` + +**Use cases**: +- "How do I trigger workflow X on the main branch?" +- "What's the MCP equivalent of `gh aw logs`?" +- "I'm in Copilot Cloud — how do I compile a workflow?" +- "Show me all available gh aw commands" + +### Token Consumption Optimization +**Load when**: The user asks how to reduce token usage, lower workflow costs, make a workflow faster or cheaper, or measure the impact of prompt or configuration changes. + +**Reference file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/token-optimization.md` + +**Use cases**: +- "How do I reduce the token cost of this workflow?" +- "My workflow is too expensive — how do I optimize it?" +- "How do I compare token usage between two runs?" +- "Should I use gh-proxy or the MCP server?" +- "How do I use sub-agents to reduce costs?" +- "How do I measure the impact of a prompt change?" + +### Workflow Pattern Selection +**Load when**: The user asks for architecture, strategy, operating model selection, or pattern recommendations for building agentic workflows. + +**Reference file**: `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/patterns.md` + +**Use cases**: +- "Which pattern should I use for multi-repo rollout?" +- "How should I structure this workflow architecture?" +- "What pattern fits slash-command triage?" +- "Should this be DispatchOps or DailyOps?" + +## Instructions + +When a user interacts with you: + +1. **Identify the task type** from the user's request +2. **Load the appropriate prompt** from the URLs listed above +3. **Follow the loaded prompt's instructions** exactly +4. **If uncertain**, ask clarifying questions to determine the right prompt + +## Quick Reference + +```bash +# Initialize repository for agentic workflows +gh aw init + +# Generate the lock file for a workflow +gh aw compile [workflow-name] + +# Trigger a workflow on demand (preferred over gh workflow run) +gh aw run # interactive input collection +gh aw run --ref main # run on a specific branch + +# Debug workflow runs +gh aw logs [workflow-name] +gh aw audit + +# Upgrade workflows +gh aw fix --write +gh aw compile --validate +``` + +## Key Features of gh-aw + +- **Natural Language Workflows**: Write workflows in markdown with YAML frontmatter +- **AI Engine Support**: Copilot, Claude, Codex, or custom engines +- **MCP Server Integration**: Connect to Model Context Protocol servers for tools +- **Safe Outputs**: Structured communication between AI and GitHub API +- **Strict Mode**: Security-first validation and sandboxing +- **Shared Components**: Reusable workflow building blocks +- **Repo Memory**: Persistent git-backed storage for agents +- **Sandboxed Execution**: All workflows run in the Agent Workflow Firewall (AWF) sandbox, enabling full `bash` and `edit` tools by default + +## Important Notes + +- Always reference the instructions file at `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/github-agentic-workflows.md` for complete documentation +- Use the MCP tool `agentic-workflows` when running in GitHub Copilot Cloud +- Workflows must be compiled to `.lock.yml` files before running in GitHub Actions +- **Bash tools are enabled by default** - Don't restrict bash commands unnecessarily since workflows are sandboxed by the AWF +- Follow security best practices: minimal permissions, explicit network access, no template injection +- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/network.md` for the full list of valid ecosystem identifiers and domain patterns. +- **Single-file output**: When creating a workflow, produce exactly **one** workflow `.md` file. Do not create separate documentation files (architecture docs, runbooks, usage guides, etc.). If documentation is needed, add a brief `## Usage` section inside the workflow file itself. +- **Triggering runs**: Always use `gh aw run ` to trigger a workflow on demand — not `gh workflow run .lock.yml`. `gh aw run` handles workflow resolution by short name, input parsing and validation, and correct run-tracking for agentic workflows. Use `--ref ` to run on a specific branch. +- **CLI commands reference**: For a complete guide on all `gh aw` commands and their MCP tool equivalents (for restricted environments), see `https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/cli-commands.md` diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index 5c2cc22e2d..e7633ea528 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -10,15 +10,10 @@ "version": "v9.0.0", "sha": "3a2844b7e9c422d3c10d287c895573f7108da1b3" }, - "github/gh-aw-actions/setup-cli@v0.80.9": { - "repo": "github/gh-aw-actions/setup-cli", - "version": "v0.80.9", - "sha": "8c7d04ebf1ece56cd381446125da3e0f6896294a" - }, - "github/gh-aw-actions/setup@v0.80.9": { + "github/gh-aw-actions/setup@v0.88.7": { "repo": "github/gh-aw-actions/setup", - "version": "v0.80.9", - "sha": "8c7d04ebf1ece56cd381446125da3e0f6896294a" + "version": "v0.88.7", + "sha": "5e508589e03a7757a7e05b26e834292f5445bfb6" } } } diff --git a/.github/skills/agentic-workflows/SKILL.md b/.github/skills/agentic-workflows/SKILL.md new file mode 100644 index 0000000000..4c983cc5ac --- /dev/null +++ b/.github/skills/agentic-workflows/SKILL.md @@ -0,0 +1,112 @@ +--- +name: agentic-workflows +description: Route gh-aw workflow design/create/debug/upgrade requests to the right prompts. +--- + +# Agentic Workflows Router + +Use this skill when a user asks to design, create, update, debug, or upgrade GitHub Agentic Workflows in this repository. + +This skill is a dispatcher: identify the task type, load the matching workflow prompt/skill file, and follow it directly. Keep responses concise and ask a clarifying question if the correct prompt is unclear. + +Repository overlay (optional): +- If `.github/aw/instructions.md` exists, load it with `@.github/aw/instructions.md` after loading the matched prompt/skill. +- Precedence: repository overlay instructions override upstream defaults when they conflict. + +Read only the files you need: +Load these files from `github/gh-aw` (they are not available locally). +- `.github/aw/action-container-substitutions.md` +- `.github/aw/agent-runtime-instructions.md` +- `.github/aw/agentic-chat.md` +- `.github/aw/agentic-workflows-mcp.md` +- `.github/aw/asciicharts.md` +- `.github/aw/campaign.md` +- `.github/aw/charts-trending.md` +- `.github/aw/charts.md` +- `.github/aw/cli-commands.md` +- `.github/aw/compat.md` +- `.github/aw/configure-agentic-engine.md` +- `.github/aw/context.md` +- `.github/aw/create-agentic-workflow-trigger-details.md` +- `.github/aw/create-agentic-workflow.md` +- `.github/aw/create-shared-agentic-workflow.md` +- `.github/aw/debug-agentic-workflow.md` +- `.github/aw/dependabot.md` +- `.github/aw/deployment-status.md` +- `.github/aw/designer-mappings.md` +- `.github/aw/designer.md` +- `.github/aw/drive-memory.md` +- `.github/aw/enclaves.md` +- `.github/aw/evals.md` +- `.github/aw/experiments.md` +- `.github/aw/github-agentic-workflows.md` +- `.github/aw/github-mcp-server-pagination.md` +- `.github/aw/github-mcp-server-tools.md` +- `.github/aw/github-mcp-server.md` +- `.github/aw/instructions.md` +- `.github/aw/intent.md` +- `.github/aw/jobs.md` +- `.github/aw/linter-workflows.md` +- `.github/aw/llms.md` +- `.github/aw/loop.md` +- `.github/aw/lsp.md` +- `.github/aw/maintainer.md` +- `.github/aw/mcp-clis.md` +- `.github/aw/memory-stateful-patterns.md` +- `.github/aw/memory.md` +- `.github/aw/messages.md` +- `.github/aw/multi-agent-research.md` +- `.github/aw/network.md` +- `.github/aw/optimize-agentic-workflow.md` +- `.github/aw/patterns.md` +- `.github/aw/playwright.md` +- `.github/aw/pr-reviewer.md` +- `.github/aw/release-workflow.md` +- `.github/aw/report.md` +- `.github/aw/reuse.md` +- `.github/aw/safe-outputs-automation.md` +- `.github/aw/safe-outputs-content.md` +- `.github/aw/safe-outputs-management.md` +- `.github/aw/safe-outputs-runtime.md` +- `.github/aw/safe-outputs.md` +- `.github/aw/serena-tool.md` +- `.github/aw/shared-safe-jobs.md` +- `.github/aw/skills.md` +- `.github/aw/subagents.md` +- `.github/aw/syntax-agentic.md` +- `.github/aw/syntax-core.md` +- `.github/aw/syntax-engine.md` +- `.github/aw/syntax-tools-imports.md` +- `.github/aw/syntax.md` +- `.github/aw/test-coverage.md` +- `.github/aw/test-expression.md` +- `.github/aw/token-optimization-caching-budgets.md` +- `.github/aw/token-optimization-observability.md` +- `.github/aw/token-optimization.md` +- `.github/aw/triggers.md` +- `.github/aw/update-agentic-workflow.md` +- `.github/aw/upgrade-agentic-workflows.md` +- `.github/aw/visual-regression.md` +- `.github/aw/workflow-constraints.md` +- `.github/aw/workflow-editing.md` +- `.github/aw/workflow-patterns.md` + +After loading the matching workflow prompt or skill, follow it directly: +- Design workflows from scratch via interview: `.github/aw/designer.md` +- Create new workflows: `.github/aw/create-agentic-workflow.md` +- Configure or add declarative engines: `.github/aw/configure-agentic-engine.md` +- Update existing workflows: `.github/aw/update-agentic-workflow.md` +- Debug, audit, or investigate workflows: `.github/aw/debug-agentic-workflow.md` +- Upgrade workflows and fix deprecations: `.github/aw/upgrade-agentic-workflows.md` +- Create shared components or MCP wrappers: `.github/aw/create-shared-agentic-workflow.md` +- Create report-generating workflows: `.github/aw/report.md` +- Fix Dependabot manifest PRs: `.github/aw/dependabot.md` +- Analyze coverage workflows: `.github/aw/test-coverage.md` +- Render compact markdown charts: `.github/aw/asciicharts.md` +- Map CLI commands to MCP usage: `.github/aw/cli-commands.md` +- Choose workflow architecture and patterns: `.github/aw/patterns.md` +- Optimize token usage and cost: `.github/aw/token-optimization.md` +- Design long-running multi-agent research workflows: `.github/aw/multi-agent-research.md` +- Add skills or agent plugins requested by the user (`skills:` / `plugins:` frontmatter, never on-the-fly installs): `.github/aw/skills.md` + +When the task involves OTEL, OTLP, traces, observability backends, or telemetry-driven analysis, also read and follow `skills/otel-queries/SKILL.md` after loading the matching workflow prompt or skill. diff --git a/.github/workflows/_cd-deploy.yml b/.github/workflows/_cd-deploy.yml index e964548995..2acf5a50b2 100644 --- a/.github/workflows/_cd-deploy.yml +++ b/.github/workflows/_cd-deploy.yml @@ -32,7 +32,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: ref: ${{ inputs.target_ref }} clean: true @@ -40,7 +40,7 @@ jobs: fetch-depth: 0 - name: Setup Node.js 24.x - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: '24.x' @@ -59,7 +59,7 @@ jobs: cd ../.. - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: igniteui-docs-${{ inputs.platform }}-${{ inputs.locale }} path: ${{ env.BUILD_TYPE }}_${{ inputs.platform }}_${{ inputs.locale }}.zip diff --git a/.github/workflows/agentics-maintenance.yml b/.github/workflows/agentics-maintenance.yml deleted file mode 100644 index 94f4fc4932..0000000000 --- a/.github/workflows/agentics-maintenance.yml +++ /dev/null @@ -1,614 +0,0 @@ -# This file was automatically generated by pkg/workflow/maintenance_workflow.go (v0.80.9). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md -# -# ___ _ _ -# / _ \ | | (_) -# | |_| | __ _ ___ _ __ | |_ _ ___ -# | _ |/ _` |/ _ \ '_ \| __| |/ __| -# | | | | (_| | __/ | | | |_| | (__ -# \_| |_/\__, |\___|_| |_|\__|_|\___| -# __/ | -# _ _ |___/ -# | | | | / _| | -# | | | | ___ _ __ _ __| |_| | _____ ____ -# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| -# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ -# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ -# -# -# To regenerate this workflow, run: -# gh aw compile -# Not all edits will cause changes to this file. -# -# For more information: https://github.github.com/gh-aw/introduction/overview/ -# -# This file defines the generated agentic maintenance workflow for this repository. -# It runs scheduled cleanup for expiring safe outputs and supports manual maintenance operations. -# -# This workflow is generated automatically when workflows use expiring safe outputs -# or when repository maintenance features are enabled in .github/workflows/aw.json. -# -# To disable maintenance workflow generation, set in .github/workflows/aw.json: -# {"maintenance": false} -# -# Agentic maintenance docs: -# https://github.github.com/gh-aw/reference/ephemerals/#manual-maintenance-operations -# -name: Agentic Maintenance - -on: - schedule: - - cron: "37 0 * * *" # Daily (based on minimum expires: 30 days) - workflow_dispatch: - inputs: - operation: - description: 'Optional maintenance operation to run' - required: false - type: choice - default: '' - options: - - '' - - 'disable' - - 'enable' - - 'update' - - 'upgrade' - - 'safe_outputs' - - 'create_labels' - - 'activity_report' - - 'close_agentic_workflows_issues' - - 'clean_cache_memories' - - 'update_pull_request_branches' - - 'validate' - - 'forecast' - run_url: - description: 'Run URL or run ID to replay safe outputs from (e.g. https://github.com/owner/repo/actions/runs/12345 or 12345). Required when operation is safe_outputs.' - required: false - type: string - default: '' - workflow_call: - inputs: - operation: - description: 'Optional maintenance operation to run (disable, enable, update, upgrade, safe_outputs, create_labels, activity_report, close_agentic_workflows_issues, clean_cache_memories, update_pull_request_branches, validate, forecast)' - required: false - type: string - default: '' - run_url: - description: 'Run URL or run ID to replay safe outputs from (e.g. https://github.com/owner/repo/actions/runs/12345 or 12345). Required when operation is safe_outputs.' - required: false - type: string - default: '' - outputs: - operation_completed: - description: 'The maintenance operation that was completed (empty when none ran or a scheduled job ran)' - value: ${{ jobs.run_operation.outputs.operation || inputs.operation }} - applied_run_url: - description: 'The run URL that safe outputs were applied from' - value: ${{ jobs.apply_safe_outputs.outputs.run_url }} - -permissions: {} - -jobs: - close-expired-entities: - if: ${{ (!(github.event.repository.fork)) && github.event_name != 'push' && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '') }} - runs-on: ubuntu-slim - permissions: - discussions: write - issues: write - pull-requests: write - steps: - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Close expired discussions - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/close_expired_discussions.cjs'); - await main(); - - - name: Close expired issues - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/close_expired_issues.cjs'); - await main(); - - - name: Close expired pull requests - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/close_expired_pull_requests.cjs'); - await main(); - - cleanup-cache-memory: - if: ${{ (!(github.event.repository.fork)) && github.event_name != 'push' && (github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call' || inputs.operation == '' || inputs.operation == 'clean_cache_memories') }} - runs-on: ubuntu-slim - permissions: - actions: write - steps: - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Cleanup outdated cache-memory entries - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/cleanup_cache_memory.cjs'); - await main(); - - run_operation: - if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation != '' && inputs.operation != 'safe_outputs' && inputs.operation != 'create_labels' && inputs.operation != 'activity_report' && inputs.operation != 'close_agentic_workflows_issues' && inputs.operation != 'clean_cache_memories' && inputs.operation != 'update_pull_request_branches' && inputs.operation != 'validate' && inputs.operation != 'forecast' && (!(github.event.repository.fork)) }} - runs-on: ubuntu-slim - permissions: - actions: write - contents: write - pull-requests: write - outputs: - operation: ${{ steps.record.outputs.operation }} - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Check admin/maintainer permissions - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs'); - await main(); - - - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - version: v0.80.9 - - - name: Run operation - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_AW_OPERATION: ${{ inputs.operation }} - GH_AW_CMD_PREFIX: gh aw - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/run_operation_update_upgrade.cjs'); - await main(); - - - name: Record outputs - id: record - env: - GH_AW_OPERATION: ${{ inputs.operation }} - run: echo "operation=$GH_AW_OPERATION" >> "$GITHUB_OUTPUT" - - update_pull_request_branches: - if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'update_pull_request_branches' && (!(github.event.repository.fork)) }} - runs-on: ubuntu-slim - permissions: - contents: write - pull-requests: write - steps: - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Check admin/maintainer permissions - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs'); - await main(); - - - name: Update pull request branches - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/update_pull_request_branches.cjs'); - await main(); - - apply_safe_outputs: - if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'safe_outputs' && (!(github.event.repository.fork)) }} - runs-on: ubuntu-slim - permissions: - actions: read - contents: write - discussions: write - issues: write - pull-requests: write - outputs: - run_url: ${{ steps.record.outputs.run_url }} - steps: - - name: Checkout actions folder - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - sparse-checkout: | - actions - persist-credentials: false - - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Check admin/maintainer permissions - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs'); - await main(); - - - name: Apply Safe Outputs - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_AW_RUN_URL: ${{ inputs.run_url }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/apply_safe_outputs_replay.cjs'); - await main(); - - - name: Record outputs - id: record - env: - GH_AW_RUN_URL: ${{ inputs.run_url }} - run: echo "run_url=$GH_AW_RUN_URL" >> "$GITHUB_OUTPUT" - - create_labels: - if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'create_labels' && (!(github.event.repository.fork)) }} - runs-on: ubuntu-slim - permissions: - contents: read - issues: write - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Check admin/maintainer permissions - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs'); - await main(); - - - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - version: v0.80.9 - - - name: Create missing labels - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - GH_AW_CMD_PREFIX: gh aw - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/create_labels.cjs'); - await main(); - - activity_report: - if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'activity_report' && (!(github.event.repository.fork)) }} - runs-on: ubuntu-slim - timeout-minutes: 120 - permissions: - actions: read - contents: read - issues: write - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Check admin/maintainer permissions - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs'); - await main(); - - - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - version: v0.80.9 - - - name: Restore activity report logs cache - id: activity_report_logs_cache - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - with: - path: ./.cache/gh-aw/activity-report-logs - key: ${{ runner.os }}-activity-report-logs-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }} - restore-keys: | - ${{ runner.os }}-activity-report-logs-${{ github.repository }}- - ${{ runner.os }}-activity-report-logs- - - name: Download activity report logs - timeout-minutes: 20 - shell: bash - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_AW_CMD_PREFIX: gh aw - run: | - ${GH_AW_CMD_PREFIX} logs \ - --repo "${{ github.repository }}" \ - --start-date -1w \ - --count 500 \ - --output ./.cache/gh-aw/activity-report-logs \ - --format markdown \ - --report-file ./.cache/gh-aw/activity-report-logs/report.md - - - name: Save activity report logs cache - if: ${{ always() }} - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - with: - path: ./.cache/gh-aw/activity-report-logs - key: ${{ steps.activity_report_logs_cache.outputs.cache-primary-key }} - - - name: Generate activity report issue - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const fs = require('node:fs'); - const reportPath = './.cache/gh-aw/activity-report-logs/report.md'; - if (!fs.existsSync(reportPath)) { - core.warning('Activity report markdown not found at ' + reportPath + '; skipping issue creation.'); - return; - } - let reportBody = ''; - try { - reportBody = fs.readFileSync(reportPath, 'utf8').trim(); - } catch (error) { - core.warning('Failed to read activity report markdown at ' + reportPath + ': ' + error.message); - return; - } - if (!reportBody) { - core.warning('Activity report markdown is empty at ' + reportPath + '; skipping issue creation.'); - return; - } - const repoSlug = context.repo.owner + '/' + context.repo.repo; - const body = [ - '### Agentic workflow activity report', - '', - 'Repository: ' + repoSlug, - 'Generated at: ' + new Date().toISOString(), - '', - reportBody, - ].join('\n'); - const createdIssue = await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: '[aw] agentic status report', - body, - labels: ['agentic-workflows'], - }); - core.info('Created issue #' + createdIssue.data.number + ': ' + createdIssue.data.html_url); - - forecast_report: - if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'forecast' && (!(github.event.repository.fork)) }} - runs-on: ubuntu-slim - timeout-minutes: 60 - permissions: - actions: read - contents: read - issues: write - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Check admin/maintainer permissions - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs'); - await main(); - - - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - version: v0.80.9 - - - name: Restore forecast report logs cache - id: forecast_report_logs_cache - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - with: - path: ./.github/aw/logs - key: ${{ runner.os }}-forecast-report-logs-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }} - restore-keys: | - ${{ runner.os }}-forecast-report-logs-${{ github.repository }}- - ${{ runner.os }}-forecast-report-logs- - - - name: Generate forecast report - id: generate_forecast_report - timeout-minutes: 30 - shell: bash - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DEBUG: "*" - GH_AW_CMD_PREFIX: gh aw - run: | - mkdir -p ./.cache/gh-aw/forecast - set +e - ${GH_AW_CMD_PREFIX} forecast --repo "${{ github.repository }}" --timeout 30 --verbose --json > ./.cache/gh-aw/forecast/report.json - forecast_exit_code=$? - set -e - if [ "${forecast_exit_code}" -eq 124 ]; then - echo '{"outcome":"timeout","message":"Forecast computation timed out after 30 minutes."}' > ./.cache/gh-aw/forecast/error.json - echo "::error::Forecast computation timed out after 30 minutes." - exit 1 - fi - if [ "${forecast_exit_code}" -ne 0 ]; then - echo '{"outcome":"error","message":"Forecast computation failed before producing a report."}' > ./.cache/gh-aw/forecast/error.json - echo "::error::Forecast computation failed with exit code ${forecast_exit_code}." - exit 1 - fi - - - name: Debug forecast logs folder - if: ${{ always() }} - shell: bash - run: | - if [ ! -d ./.github/aw/logs ]; then - echo "Logs directory not found: ./.github/aw/logs" - exit 0 - fi - echo "Files under ./.github/aw/logs:" - find ./.github/aw/logs -type f | sort - - - name: Save forecast report logs cache - if: ${{ always() }} - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - with: - path: ./.github/aw/logs - key: ${{ runner.os }}-forecast-report-logs-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }} - - - name: Generate forecast issue - if: ${{ always() }} - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - FORECAST_STEP_OUTCOME: ${{ steps.generate_forecast_report.outcome }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/create_forecast_issue.cjs'); - await main(); - - close_agentic_workflows_issues: - if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'close_agentic_workflows_issues' && (!(github.event.repository.fork)) }} - runs-on: ubuntu-slim - permissions: - issues: write - steps: - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Check admin/maintainer permissions - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs'); - await main(); - - - name: Close no-repro agentic-workflows issues - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/close_agentic_workflows_issues.cjs'); - await main(); - - validate_workflows: - if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'validate' && (!(github.event.repository.fork)) }} - runs-on: ubuntu-latest - permissions: - contents: read - issues: write - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - name: Setup Scripts - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - destination: ${{ runner.temp }}/gh-aw/actions - - - name: Check admin/maintainer permissions - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_team_member.cjs'); - await main(); - - - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 - with: - version: v0.80.9 - - - name: Validate workflows and file issue on findings - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - GH_AW_CMD_PREFIX: gh aw - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/run_validate_workflows.cjs'); - await main(); diff --git a/.github/workflows/check-relative-links.yml b/.github/workflows/check-relative-links.yml index a8779bf886..20ca856ea6 100644 --- a/.github/workflows/check-relative-links.yml +++ b/.github/workflows/check-relative-links.yml @@ -6,20 +6,16 @@ permissions: on: pull_request: branches: [master, vnext] - paths: - - 'docs/**/*.mdx' - - 'docs/**/*.md' - - 'docs/*/scripts/**' - - 'scripts/check-relative-links*.mjs' - - 'package.json' + push: + branches: [master, vnext] jobs: check-relative-links: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v7 with: node-version: 24 cache: 'npm' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5efe8d8f1..743e92dafa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,10 +17,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Use Node.js 24.x - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: 24 cache: 'npm' @@ -28,9 +28,15 @@ jobs: - name: Install dependencies run: npm ci + # DOCS_TOC_STRICT fails the build when a toc.json entry points at a + # missing file, instead of silently dropping it from the sidebar. - name: Build ${{ matrix.platform }} run: npm run xplat:build:${{ matrix.platform }} + env: + DOCS_TOC_STRICT: 'true' - name: Build Angular Unique if: matrix.platform == 'angular' run: npm run angular:build + env: + DOCS_TOC_STRICT: 'true' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ad81c2c64b..32baa04bcc 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,9 +18,9 @@ jobs: llms-metadata: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v7 with: node-version: 24 @@ -30,11 +30,11 @@ jobs: markdown-lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v7 with: node-version: 24 cache: 'npm' @@ -69,11 +69,11 @@ jobs: spellcheck: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v7 with: node-version: 24 cache: 'npm' diff --git a/.github/workflows/pr-stale.yml b/.github/workflows/pr-stale.yml index 672e059b4c..7015be9522 100644 --- a/.github/workflows/pr-stale.yml +++ b/.github/workflows/pr-stale.yml @@ -11,7 +11,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@v9 # Use the actions/stale action + - uses: actions/stale@v11 # Use the actions/stale action with: remove-pr-stale-when-updated: true days-before-stale: 30 diff --git a/.github/workflows/sync-jp-docs-angular.lock.yml b/.github/workflows/sync-jp-docs-angular.lock.yml index c41596c78b..d0940270eb 100644 --- a/.github/workflows/sync-jp-docs-angular.lock.yml +++ b/.github/workflows/sync-jp-docs-angular.lock.yml @@ -1,15 +1,15 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"3d5f0dacbdf6a09d9eb9a70984cecad606753a548e4c07519293fe69c33b0b8f","body_hash":"1752465b42275ea9ec5301dd3a5b9cd0de772e35c435c62e61924cbc83925732","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.63"}} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/cache/save","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} -# This file was automatically generated by gh-aw (v0.80.9). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"3d5f0dacbdf6a09d9eb9a70984cecad606753a548e4c07519293fe69c33b0b8f","body_hash":"8b0360a1ea95d991f2cb01853b40156ecdac3abba53b58783a3660fe58fbd92b","compiler_version":"v0.88.7","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.80"}} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_DEFAULT_OTLP_HEADERS","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"5e508589e03a7757a7e05b26e834292f5445bfb6","version":"v0.88.7"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.28.14","digest":"sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.28.14@sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14","digest":"sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14@sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.28.14","digest":"sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.28.14@sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.18","digest":"sha256:85b940556a8faa4e1fdbef124bfd75f2c4ebd855a10b88a1c3b6f3e97f6f1a53","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.18@sha256:85b940556a8faa4e1fdbef124bfd75f2c4ebd855a10b88a1c3b6f3e97f6f1a53"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0daa8971fa4732b647150cb6524a6b0804b68d5d24f6f58b5dd1af23bd63fb23","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0daa8971fa4732b647150cb6524a6b0804b68d5d24f6f58b5dd1af23bd63fb23"},{"image":"ghcr.io/github/github-mcp-server:v1.11.0","digest":"sha256:fbec75de11c255213fa08d80fb166abe73d851fff631c51c0079872967720699","pinned_image":"ghcr.io/github/github-mcp-server:v1.11.0@sha256:fbec75de11c255213fa08d80fb166abe73d851fff631c51c0079872967720699"}],"mcp_servers":[{"name":"github","tools":["get_commit","get_file_contents","get_latest_release","get_me","get_pull_request","get_pull_request_comments","get_pull_request_diff","get_pull_request_files","get_pull_request_review_comments","get_pull_request_reviews","get_pull_request_status","get_release_by_tag","get_tag","issue_read","list_branches","list_commits","list_issue_types","list_issues","list_pull_requests","list_releases","list_starred_repositories","list_tags","pull_request_read","search_code","search_issues","search_pull_requests","search_repositories"]},{"name":"safeoutputs","tools":["create_pull_request","missing_data","missing_tool","noop"]}]} +# This file was automatically generated by gh-aw (v0.88.7). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # -# ___ _ _ -# / _ \ | | (_) -# | |_| | __ _ ___ _ __ | |_ _ ___ +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ # | _ |/ _` |/ _ \ '_ \| __| |/ __| -# | | | | (_| | __/ | | | |_| | (__ +# | | | | (_| | __/ | | | |_| | (__ # \_| |_/\__, |\___|_| |_|\__|_|\___| # __/ | -# _ _ |___/ +# _ _ |___/ # | | | | / _| | # | | | | ___ _ __ _ __| |_| | _____ ____ # | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| @@ -28,36 +28,37 @@ # Secrets used: # - COPILOT_GITHUB_TOKEN # - GH_AW_CI_TRIGGER_TOKEN +# - GH_AW_DEFAULT_OTLP_HEADERS # - GH_AW_GITHUB_MCP_SERVER_TOKEN # - GH_AW_GITHUB_TOKEN # - GITHUB_TOKEN # # Custom actions used: -# - actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 -# - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 +# - actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 +# - actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 -# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 +# - actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 +# - github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6 -# - ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96 -# - ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7 -# - ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b -# - ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036 +# - ghcr.io/github/gh-aw-firewall/agent:0.28.14@sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14@sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5 +# - ghcr.io/github/gh-aw-firewall/squid:0.28.14@sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5 +# - ghcr.io/github/gh-aw-mcpg:v0.4.18@sha256:85b940556a8faa4e1fdbef124bfd75f2c4ebd855a10b88a1c3b6f3e97f6f1a53 +# - ghcr.io/github/gh-aw-node@sha256:0daa8971fa4732b647150cb6524a6b0804b68d5d24f6f58b5dd1af23bd63fb23 +# - ghcr.io/github/github-mcp-server:v1.11.0@sha256:fbec75de11c255213fa08d80fb166abe73d851fff631c51c0079872967720699 name: "Sync Japanese Documentation (Angular)" on: push: branches: - - vnext + - vnext paths: - - docs/angular/src/content/en/** + - docs/angular/src/content/en/** workflow_dispatch: inputs: aw_context: @@ -70,9 +71,18 @@ permissions: {} concurrency: group: "gh-aw-${{ github.workflow }}-${{ github.ref || github.run_id }}" + queue: max run-name: "Sync Japanese Documentation (Angular)" +env: + OTEL_EXPORTER_OTLP_ENDPOINT: ${{ vars.GH_AW_DEFAULT_OTLP_ENDPOINT }} + OTEL_SERVICE_NAME: gh-aw.sync-jp-docs-angular + OTEL_RESOURCE_ATTRIBUTES: 'gh-aw.workflow.name=Sync%20Japanese%20Documentation%20%28Angular%29,gh-aw.repository=${{ github.repository }},gh-aw.run.id=${{ github.run_id }},github.run_id=${{ github.run_id }},gh-aw.engine.id=copilot' + OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }} + GH_AW_OTLP_ENDPOINTS: '[{"url":"${{ vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}","headers":"${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}"}]' + GH_AW_OTLP_IF_MISSING: ignore + jobs: activation: needs: pre_activation @@ -83,15 +93,18 @@ jobs: contents: read env: GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }} + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} outputs: comment_id: "" comment_repo: "" daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_guardrail_status: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_guardrail_status || '' }} daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} + oauth_token_check_failed: ${{ steps.check-oauth-tokens.outputs.oauth_token_check_failed == 'true' }} secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} setup-span-id: ${{ steps.setup.outputs.span-id }} @@ -100,7 +113,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -110,40 +123,45 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-angular.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" + - name: Mask OTLP telemetry headers + run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" - name: Generate agentic run info id: generate_aw_info env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" - GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AGENT_VERSION: "1.0.63" - GH_AW_INFO_CLI_VERSION: "v0.80.9" + GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }} + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AGENT_VERSION: "1.0.80" + GH_AW_INFO_CLI_VERSION: "v0.88.7" GH_AW_INFO_WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" + GH_AW_INFO_AGENT_RUNTIME: "" GH_AW_COMPILED_STRICT: "true" uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); + const { main } = require(path.join(actionsDir, 'generate_aw_info.cjs')); await main(core, context); - name: Restore daily AIC usage cache id: restore-daily-aic-cache if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} continue-on-error: true - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: agentic-workflow-usage-syncjpdocsangular-${{ github.run_id }} restore-keys: agentic-workflow-usage-syncjpdocsangular- @@ -159,9 +177,11 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/restore_aic_usage_cache_fallback.cjs'); + const { main } = require(path.join(actionsDir, 'restore_aic_usage_cache_fallback.cjs')); await main(); - name: Check daily workflow token guardrail id: daily-effective-workflow-guardrail @@ -179,37 +199,43 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_daily_aic_workflow_guardrail.cjs'); + const { main } = require(path.join(actionsDir, 'check_daily_aic_workflow_guardrail.cjs')); await main(); - name: Validate COPILOT_GITHUB_TOKEN secret id: validate-secret run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default env: COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + - name: Check for OAuth tokens + id: check-oauth-tokens + run: bash "${RUNNER_TEMP}/gh-aw/actions/check_oauth_tokens.sh" + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - name: Checkout .github and .agents folders - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false sparse-checkout: | .github .agents - .antigravity .claude .codex - .crush .gemini - .opencode .pi sparse-checkout-cone-mode: true fetch-depth: 1 - name: Save agent config folders for base branch restoration env: - GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" - # poutine:ignore untrusted_checkout_exec - run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh" + GH_AW_AGENT_FOLDERS: ".agents .github" + GH_AW_AGENT_FILES: "AGENTS.md" + run: | + bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh" - name: Check workflow lock file id: check-lock-file uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -218,24 +244,34 @@ jobs: GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs'); + const { main } = require(path.join(actionsDir, 'check_workflow_timestamp_api.cjs')); await main(); - name: Check compile-agentic version uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_COMPILED_VERSION: "v0.80.9" + GH_AW_COMPILED_VERSION: "v0.88.7" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_version_updates.cjs'); + const { main } = require(path.join(actionsDir, 'check_version_updates.cjs')); await main(); + - name: Log runtime features + if: ${{ contains(toJSON(vars), '"GH_AW_RUNTIME_FEATURES":') }} + run: bash "${RUNNER_TEMP}/gh-aw/actions/log_runtime_features_summary.sh" - name: Create prompt with built-in context + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_ACTIONS_DIR: ${{ runner.temp }}/gh-aw/actions + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_PROMPT_CONFIG: "{\"items\":[{\"content_env\":\"GH_AW_PROMPT_CONTENT_0000\"},{\"file\":\"xpia.md\"},{\"file\":\"temp_folder_prompt.md\"},{\"file\":\"markdown.md\"},{\"file\":\"safe_outputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0001\"},{\"file\":\"safe_outputs_create_pull_request.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0002\"},{\"file\":\"mcp_cli_tools_with_safeoutputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0003\"},{\"file\":\"github_mcp_tools_with_safeoutputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0004\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0005\"}]}" GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} @@ -244,77 +280,35 @@ jobs: GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - # poutine:ignore untrusted_checkout_exec - run: | - bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" - { - cat << 'GH_AW_PROMPT_be9ff8cc0bb668a4_EOF' - - GH_AW_PROMPT_be9ff8cc0bb668a4_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" - cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" - cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" - cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_be9ff8cc0bb668a4_EOF' - - Tools: create_pull_request, missing_tool, missing_data, noop - GH_AW_PROMPT_be9ff8cc0bb668a4_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_be9ff8cc0bb668a4_EOF' - - GH_AW_PROMPT_be9ff8cc0bb668a4_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_be9ff8cc0bb668a4_EOF' - - The following GitHub context information is available for this workflow: - {{#if github.actor}} - - **actor**: __GH_AW_GITHUB_ACTOR__ - {{/if}} - {{#if github.repository}} - - **repository**: __GH_AW_GITHUB_REPOSITORY__ - {{/if}} - {{#if github.workspace}} - - **workspace**: __GH_AW_GITHUB_WORKSPACE__ - {{/if}} - {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}} - - **issue-number**: #__GH_AW_EXPR_802A9F6A__ - {{/if}} - {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}} - - **discussion-number**: #__GH_AW_EXPR_1A3A194A__ - {{/if}} - {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}} - - **pull-request-number**: #__GH_AW_EXPR_463A214A__ - {{/if}} - {{#if github.event.comment.id || github.aw.context.comment_id}} - - **comment-id**: __GH_AW_EXPR_FF1D34CE__ - {{/if}} - {{#if github.run_id}} - - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ - {{/if}} - - - GH_AW_PROMPT_be9ff8cc0bb668a4_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_be9ff8cc0bb668a4_EOF' - - {{#runtime-import .github/workflows/sync-jp-docs-angular.md}} - GH_AW_PROMPT_be9ff8cc0bb668a4_EOF - } > "$GH_AW_PROMPT" + GH_AW_PROMPT_CONTENT_0000: "\n" + GH_AW_PROMPT_CONTENT_0001: "\nTools: create_pull_request, missing_tool, missing_data, noop\n" + GH_AW_PROMPT_CONTENT_0002: "\n" + GH_AW_PROMPT_CONTENT_0003: "\nThe following GitHub context information is available for this workflow:\n{{#if github.actor}}\n- **actor**: __GH_AW_GITHUB_ACTOR__\n{{/if}}\n{{#if github.repository}}\n- **repository**: __GH_AW_GITHUB_REPOSITORY__\n{{/if}}\n{{#if github.workspace}}\n- **workspace**: __GH_AW_GITHUB_WORKSPACE__\n{{/if}}\n{{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}}\n- **issue-number**: #__GH_AW_EXPR_802A9F6A__\n{{/if}}\n{{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}}\n- **discussion-number**: #__GH_AW_EXPR_1A3A194A__\n{{/if}}\n{{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}}\n- **pull-request-number**: #__GH_AW_EXPR_463A214A__\n{{/if}}\n{{#if github.event.comment.id || github.aw.context.comment_id}}\n- **comment-id**: __GH_AW_EXPR_FF1D34CE__\n{{/if}}\n{{#if github.run_id}}\n- **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__\n{{/if}}\n\n\n" + GH_AW_PROMPT_CONTENT_0004: "\n" + GH_AW_PROMPT_CONTENT_0005: "{{#runtime-import .github/workflows/sync-jp-docs-angular.md}}\n" + with: + script: | + const { setupGlobals } = require(process.env.GH_AW_ACTIONS_DIR + '/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(process.env.GH_AW_ACTIONS_DIR + '/create_prompt.cjs'); + await main(core); - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt GH_AW_ENGINE_ID: "copilot" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs'); + const { main } = require(path.join(actionsDir, 'interpolate_prompt.cjs')); await main(); - name: Substitute placeholders uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} @@ -323,15 +317,17 @@ jobs: GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools' + GH_AW_MCP_CLI_SERVERS_LIST: "- `github` — run `github --help` to see available tools\n- `safeoutputs` — run `safeoutputs --help` to see available tools" GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }} with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - - const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs'); - + + const substitutePlaceholders = require(path.join(actionsDir, 'substitute_placeholders.cjs')); + // Call the substitution function return await substitutePlaceholders({ file: process.env.GH_AW_PROMPT, @@ -350,16 +346,20 @@ jobs: }); - name: Validate prompt placeholders env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - # poutine:ignore untrusted_checkout_exec - run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh" + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt + run: | + bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh" - name: Print prompt env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - # poutine:ignore untrusted_checkout_exec - run: bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh" + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt + run: | + bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh" + - name: Stage prompt files for artifact upload + run: | + mkdir -p /tmp/gh-aw/aw-prompts + cp -a "${RUNNER_TEMP}/gh-aw/aw-prompts/." /tmp/gh-aw/aw-prompts/ - name: Upload activation artifact - if: success() + if: success() || failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: activation @@ -384,12 +384,20 @@ jobs: permissions: actions: read contents: read + timeout-minutes: 60 env: DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} GH_AW_ASSETS_ALLOWED_EXTS: "" GH_AW_ASSETS_BRANCH: "" GH_AW_ASSETS_MAX_SIZE_KB: 0 GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + GH_AW_PR_HEAD_BASE_BRANCH: "" + GH_AW_PR_HEAD_BASE_PR_NUMBER: "" + GH_AW_PR_HEAD_BASE_REF: "" + GH_AW_PR_HEAD_BASE_REPO: "" + GH_AW_PR_HEAD_BASE_SHA: "" + GH_AW_PR_HEAD_REPO: "" + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} GH_AW_WORKFLOW_ID_SANITIZED: syncjpdocsangular outputs: agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }} @@ -399,8 +407,13 @@ jobs: checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} has_patch: ${{ steps.collect_output.outputs.has_patch }} + http_400_response_error: ${{ steps.detect-agent-errors.outputs.http_400_response_error || 'false' }} inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }} + invocation_cap_exceeded: ${{ steps.detect-agent-errors.outputs.invocation_cap_exceeded || 'false' }} + max_cache_misses_exceeded: ${{ steps.detect-agent-errors.outputs.max_cache_misses_exceeded || 'false' }} mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }} + missing_model_pricing_error: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_error || 'false' }} + missing_model_pricing_model_name: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_model_name || '' }} model: ${{ needs.activation.outputs.model }} model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} @@ -408,11 +421,12 @@ jobs: setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} + shell_expansion_guard_rejected: ${{ steps.detect-agent-errors.outputs.shell_expansion_guard_rejected || 'false' }} unknown_model_ai_credits: ${{ steps.parse-mcp-gateway.outputs.unknown_model_ai_credits || 'false' }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -421,19 +435,28 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-angular.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths + env: + GH_AW_RUNNER_TOOL_CACHE: ${{ runner.tool_cache }} run: | + if [ -z "${RUNNER_TOOL_CACHE:-}" ]; then + echo "RUNNER_TOOL_CACHE=${GH_AW_RUNNER_TOOL_CACHE}" >> "$GITHUB_ENV" + fi { echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl" echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json" } >> "$GITHUB_OUTPUT" + - name: Mask OTLP telemetry headers + run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" + - name: Check OTLP telemetry configuration + run: bash "${RUNNER_TEMP}/gh-aw/actions/check_otlp_default_credentials.sh" - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Create gh-aw temp directory @@ -442,6 +465,11 @@ jobs: run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} + - name: Download activation artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: activation + path: /tmp/gh-aw - name: Configure Git credentials env: GITHUB_REPOSITORY: ${{ github.repository }} @@ -458,16 +486,19 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); + const { main } = require(path.join(actionsDir, 'checkout_pr_branch.cjs')); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.63 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" env: GH_HOST: github.com + GH_AW_COMPILED_VERSION: v0.88.7 - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.7 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.14 --rootless - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -476,18 +507,15 @@ jobs: GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} with: script: | - const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const determineAutomaticLockdown = require(path.join(actionsDir, 'determine_automatic_lockdown.cjs')); await determineAutomaticLockdown(github, context, core); - - name: Download activation artifact - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: activation - path: /tmp/gh-aw - name: Restore agent config folders from base branch if: steps.checkout-pr.outcome == 'success' env: - GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .github" + GH_AW_AGENT_FILES: "AGENTS.md" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh" - name: Restore inline sub-agents from activation artifact env: @@ -499,15 +527,26 @@ jobs: GH_AW_SKILL_DIR: ".github/skills" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6 ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96 ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036 - - name: Generate Safe Outputs Config + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.14@sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14@sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5 ghcr.io/github/gh-aw-firewall/squid:0.28.14@sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5 ghcr.io/github/gh-aw-mcpg:v0.4.18@sha256:85b940556a8faa4e1fdbef124bfd75f2c4ebd855a10b88a1c3b6f3e97f6f1a53 ghcr.io/github/gh-aw-node@sha256:0daa8971fa4732b647150cb6524a6b0804b68d5d24f6f58b5dd1af23bd63fb23 ghcr.io/github/github-mcp-server:v1.11.0@sha256:fbec75de11c255213fa08d80fb166abe73d851fff631c51c0079872967720699 + - name: Prepare Safe Outputs Directories run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_7e98029480883c79_EOF' - {"create_pull_request":{"base_branch":"vnext","draft":false,"if_no_changes":"ignore","labels":["translation","japanese","automation"],"max":1,"max_patch_files":100,"max_patch_size":4096,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[jp-sync] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_7e98029480883c79_EOF + - name: Generate Safe Outputs Config + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + GH_AW_FILE_ROOT: "${{ runner.temp }}/gh-aw" + GH_AW_FILE_CONFIG: "{\"files\":[{\"path\":\"safeoutputs/config.json\",\"content_env\":\"GH_AW_SAFE_OUTPUTS_CONFIG\"}]}" + GH_AW_SAFE_OUTPUTS_CONFIG: "{\"create_pull_request\":{\"base_branch\":\"vnext\",\"draft\":false,\"if_no_changes\":\"ignore\",\"labels\":[\"translation\",\"japanese\",\"automation\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[jp-sync] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"report_incomplete\":{}}" + with: + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'create_files.cjs')); + await main(); - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -540,6 +579,12 @@ jobs: "sanitize": true, "maxLength": 256 }, + "dependencies": { + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 256 + }, "draft": { "type": "boolean" }, @@ -553,6 +598,18 @@ jobs: "type": "string", "maxLength": 256 }, + "stack_position": { + "optionalPositiveInteger": true + }, + "stack_root": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "temporary_id": { + "type": "string", + "pattern": "^#?aw_[A-Za-z0-9_]{3,12}$" + }, "title": { "required": true, "type": "string", @@ -638,16 +695,20 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_safe_outputs_tools.cjs'); + const { main } = require(path.join(actionsDir, 'generate_safe_outputs_tools.cjs')); await main(); - name: Start MCP Gateway id: start-mcp-gateway env: + GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST: ${{ vars.GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST || 'true' }} GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }} GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }} + GH_AW_SINK_VISIBILITY: ${{ steps.determine-automatic-lockdown.outputs.visibility }} GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} @@ -655,41 +716,49 @@ jobs: run: | set -eo pipefail mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config" - + if [ -n "${GITHUB_EVENT_PATH:-}" ] && [ -r "${GITHUB_EVENT_PATH}" ]; then + GH_AW_SAFEOUTPUTS_EVENT_PATH="${RUNNER_TEMP}/gh-aw/safeoutputs/github_event.json" + cp "${GITHUB_EVENT_PATH}" "${GH_AW_SAFEOUTPUTS_EVENT_PATH}" + export GITHUB_EVENT_PATH="${GH_AW_SAFEOUTPUTS_EVENT_PATH}" + fi + # Export gateway environment variables for MCP config and gateway script export MCP_GATEWAY_PORT="8080" - export MCP_GATEWAY_DOMAIN="host.docker.internal" + export MCP_GATEWAY_DOMAIN="awmg-mcpg" export MCP_GATEWAY_HOST_DOMAIN="localhost" - MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${MCP_GATEWAY_API_KEY}" - export MCP_GATEWAY_API_KEY + MCP_GATEWAY_AGENT_ID=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${MCP_GATEWAY_AGENT_ID}" + export MCP_GATEWAY_AGENT_ID export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" + export MCP_GATEWAY_ALLOWED_MOUNT_ROOTS="${GITHUB_WORKSPACE}:rw,${RUNNER_TEMP}/gh-aw:ro,${RUNNER_TEMP}/gh-aw/safeoutputs:rw,/opt:ro,/tmp:rw,/usr/bin/gh:ro" + export GH_AW_PR_HEAD_BASE_BRANCH="${GH_AW_PR_HEAD_BASE_BRANCH:-}" + export GH_AW_PR_HEAD_BASE_SHA="${GH_AW_PR_HEAD_BASE_SHA:-}" + export GH_AW_PR_HEAD_BASE_REPO="${GH_AW_PR_HEAD_BASE_REPO:-}" + export GH_AW_PR_HEAD_BASE_PR_NUMBER="${GH_AW_PR_HEAD_BASE_PR_NUMBER:-}" + export GH_AW_PR_HEAD_BASE_REF="${GH_AW_PR_HEAD_BASE_REF:-}" + export GH_AW_PR_HEAD_REPO="${GH_AW_PR_HEAD_REPO:-}" export DEBUG="*" - + export GH_AW_ENGINE="copilot" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') - case "${DOCKER_HOST:-}" in - unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;; - /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;; - * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; - esac - DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --name awmg-mcpg --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.3.27' - + source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh" + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 127.0.0.1:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_AGENT_ID -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_PR_HEAD_BASE_BRANCH -e GH_AW_PR_HEAD_BASE_SHA -e GH_AW_PR_HEAD_BASE_REPO -e GH_AW_PR_HEAD_BASE_PR_NUMBER -e GH_AW_PR_HEAD_BASE_REF -e GH_AW_PR_HEAD_REPO -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GH_AW_SINK_VISIBILITY -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -e RUNNER_TOOL_CACHE -e MCP_GATEWAY_ALLOWED_MOUNT_ROOTS -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.4.18' + mkdir -p "$HOME/.copilot" GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_c70c556baaebe8bb_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_46604863f3d8e286_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.4.0", + "container": "ghcr.io/github/github-mcp-server:v1.11.0", "env": { - "GITHUB_HOST": "\${GITHUB_SERVER_URL}", - "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", + "GITHUB_FEATURES": "fields_param", + "GITHUB_HOST": "${GITHUB_SERVER_URL}", + "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_MCP_SERVER_TOKEN}", "GITHUB_READ_ONLY": "1", "GITHUB_TOOLSETS": "context,repos,issues,pull_requests" }, @@ -717,7 +786,17 @@ jobs: "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}", "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}", "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}", + "GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST": "\${GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST}", + "GH_AW_PR_HEAD_BASE_BRANCH": "\${GH_AW_PR_HEAD_BASE_BRANCH}", + "GH_AW_PR_HEAD_BASE_SHA": "\${GH_AW_PR_HEAD_BASE_SHA}", + "GH_AW_PR_HEAD_BASE_REPO": "\${GH_AW_PR_HEAD_BASE_REPO}", + "GH_AW_PR_HEAD_BASE_PR_NUMBER": "\${GH_AW_PR_HEAD_BASE_PR_NUMBER}", + "GH_AW_PR_HEAD_BASE_REF": "\${GH_AW_PR_HEAD_BASE_REF}", + "GH_AW_PR_HEAD_REPO": "\${GH_AW_PR_HEAD_REPO}", + "GITHUB_EVENT_NAME": "\${GITHUB_EVENT_NAME}", + "GITHUB_EVENT_PATH": "\${GITHUB_EVENT_PATH}", "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}", + "GITHUB_SHA": "\${GITHUB_SHA}", "GITHUB_TOKEN": "\${GITHUB_TOKEN}", "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}", "RUNNER_TEMP": "\${RUNNER_TEMP}" @@ -726,7 +805,8 @@ jobs: "write-sink": { "accept": [ "*" - ] + ], + "sink-visibility": "${GH_AW_SINK_VISIBILITY}" } } } @@ -734,24 +814,32 @@ jobs: "gateway": { "port": $MCP_GATEWAY_PORT, "domain": "${MCP_GATEWAY_DOMAIN}", - "apiKey": "${MCP_GATEWAY_API_KEY}", - "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" + "agentId": "${MCP_GATEWAY_AGENT_ID}", + "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}", + "startupTimeout": 120, + "opentelemetry": { + "endpoint": "${OTEL_EXPORTER_OTLP_ENDPOINT}", + "traceId": "${GITHUB_AW_OTEL_TRACE_ID}", + "spanId": "${GITHUB_AW_OTEL_PARENT_SPAN_ID}" + } } } - GH_AW_MCP_CONFIG_c70c556baaebe8bb_EOF + GH_AW_MCP_CONFIG_46604863f3d8e286_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true env: - MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }} MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }} MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io); - const { main } = require('${{ runner.temp }}/gh-aw/actions/mount_mcp_as_cli.cjs'); + const { main } = require(path.join(actionsDir, 'mount_mcp_as_cli.cjs')); await main(); - name: Clean credentials continue-on-error: true @@ -780,6 +868,7 @@ jobs: # --allow-tool shell(git rm:*) # --allow-tool shell(git status) # --allow-tool shell(git switch:*) + # --allow-tool shell(github:*) # --allow-tool shell(grep) # --allow-tool shell(head) # --allow-tool shell(ls) @@ -797,40 +886,41 @@ jobs: run: | set -o pipefail printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt - trap 'rm -f "$HOME/.copilot/settings.json"' EXIT + trap 'gh_aw_exit_code=$?; mkdir -p /tmp/gh-aw >/dev/null 2>&1 || true; printf "%s" "$gh_aw_exit_code" > /tmp/gh-aw/agent_execution_exit_code.txt || true; rm -f "$HOME/.copilot/settings.json"; if [ "$gh_aw_exit_code" -ne 0 ]; then echo "::error::Agent execution exited with code $gh_aw_exit_code"; fi' EXIT mkdir -p "$HOME/.copilot" printf '%s' '{"builtInAgents":{"rubberDuck":false}}' > "$HOME/.copilot/settings.json" export XDG_CONFIG_HOME="$HOME" export GH_AW_MCP_CONFIG="$HOME/.copilot/mcp-config.json" + GH_AW_COPILOT_SRC="$(command -v copilot 2>/dev/null || true)" + if [ -z "$GH_AW_COPILOT_SRC" ] || [ ! -x "$GH_AW_COPILOT_SRC" ]; then + echo "GitHub Copilot CLI executable not found on PATH after installation" >&2 + exit 127 + fi + GH_AW_COPILOT_BIN="${RUNNER_TEMP}/gh-aw/bin/copilot" + mkdir -p "${RUNNER_TEMP}/gh-aw/bin" + if [ "$GH_AW_COPILOT_SRC" != "$GH_AW_COPILOT_BIN" ]; then + cp "$GH_AW_COPILOT_SRC" "$GH_AW_COPILOT_BIN" + fi + chmod 755 "$GH_AW_COPILOT_BIN" + touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}" - printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.7/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"github.com\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"keyserver.ubuntu.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"raw.githubusercontent.com\",\"registry.npmjs.org\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"telemetry.enterprise.githubcopilot.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.5\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.7,squid=sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96,agent=sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c,api-proxy=sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6,cli-proxy=sha256:4757f198a3fa20f88bdbe70be7ae1a05f127d9c0a9e96a5d6460ef40c08fc83d\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then + GH_AW_MAX_AI_CREDITS="1000" + fi + printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.14/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"json-schema.org\",\"json.schemastore.org\",\"keyserver.ubuntu.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\"],\"isolation\":true,\"topologyAttach\":[\"awmg-mcpg\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.14,squid=sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5,agent=sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98,api-proxy=sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5,cli-proxy=sha256:3a379c5e96e29499c815e9dd2a71334d01c326a9b73991c76544fda9cae35c34\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" GH_AW_DOCKER_HOST="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then GH_AW_DOCKER_HOST="${DOCKER_HOST}" fi - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" - python3 - <<'PY' - import json,os,subprocess as sp - from pathlib import Path - try: - p=Path(os.environ["RUNNER_TEMP"])/"gh-aw"/"awf-config.json" - c=json.loads(p.read_text()) - c["chroot"]={"binariesSourcePath":"/tmp/gh-aw","identity":{"user":sp.check_output(["id","-un"],text=True).strip(),"uid":int(sp.check_output(["id","-u"],text=True)),"gid":int(sp.check_output(["id","-g"],text=True)),"home":"/tmp/gh-aw/home"}} - out=json.dumps(c,separators=(",",":"),ensure_ascii=False)+"\n" - p.write_text(out) - Path("/tmp/gh-aw/awf-config.json").write_text(out) - except Exception as e: - raise SystemExit(f"chroot config patch failed: {e}") from e - PY + GH_AW_CHROOT_BINARIES_SOURCE_PATH="${RUNNER_TEMP}/gh-aw" GH_AW_CHROOT_IDENTITY_HOME="${RUNNER_TEMP}/gh-aw/home" node "${RUNNER_TEMP}/gh-aw/actions/patch_awf_chroot_config.cjs" fi GH_AW_TOOL_CACHE_MOUNT="" GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}" @@ -839,22 +929,28 @@ jobs: GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" fi fi - # shellcheck disable=SC1003,SC2086 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; export PATH="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(find)'\'' --allow-tool '\''shell(git add:*)'\'' --allow-tool '\''shell(git branch:*)'\'' --allow-tool '\''shell(git checkout:*)'\'' --allow-tool '\''shell(git commit:*)'\'' --allow-tool '\''shell(git diff --name-only)'\'' --allow-tool '\''shell(git diff)'\'' --allow-tool '\''shell(git log)'\'' --allow-tool '\''shell(git merge:*)'\'' --allow-tool '\''shell(git rm:*)'\'' --allow-tool '\''shell(git status)'\'' --allow-tool '\''shell(git switch:*)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(node)'\'' --allow-tool '\''shell(printf)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + # shellcheck disable=SC1003,SC2016,SC2086 + GH_AW_AWF_ENGINE_NAME=copilot \ + GH_AW_AWF_HARNESS_MARKER='[copilot-harness]' \ + GH_AW_AWF_LOG_FILE=/tmp/gh-aw/agent-stdio.log \ + GH_AW_AWF_ATTEMPT_LOG_NAME=copilot \ + bash "${RUNNER_TEMP}/gh-aw/actions/run_awf_with_startup_retries.sh" -- \ + awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_AGENT_ID --mount /tmp/gh-aw:/tmp/gh-aw:rw --log-level info --skip-pull \ + -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" "${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs" "${RUNNER_TEMP}/gh-aw/bin/copilot" --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(find)'\'' --allow-tool '\''shell(git add:*)'\'' --allow-tool '\''shell(git branch:*)'\'' --allow-tool '\''shell(git checkout:*)'\'' --allow-tool '\''shell(git commit:*)'\'' --allow-tool '\''shell(git diff --name-only)'\'' --allow-tool '\''shell(git diff)'\'' --allow-tool '\''shell(git log)'\'' --allow-tool '\''shell(git merge:*)'\'' --allow-tool '\''shell(git rm:*)'\'' --allow-tool '\''shell(git status)'\'' --allow-tool '\''shell(git switch:*)'\'' --allow-tool '\''shell(github:*)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(node)'\'' --allow-tool '\''shell(printf)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }} + GH_AW_LLM_PROVIDER: github GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }} GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_TIMEOUT_MINUTES: 30 - GH_AW_VERSION: v0.80.9 + GH_AW_VERSION: v0.88.7 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -874,7 +970,18 @@ jobs: if: always() id: detect-agent-errors continue-on-error: true - run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs" + env: + GH_AW_AGENTIC_EXECUTION_OUTCOME: ${{ steps.agentic_execution.outcome }} + GH_AW_ENGINE_STEP_TIMEOUT_MINUTES: 30 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'detect_agent_errors.cjs')); + await main(); - name: Configure Git credentials env: GITHUB_REPOSITORY: ${{ github.repository }} @@ -890,7 +997,7 @@ jobs: continue-on-error: true env: MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} - MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }} GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} run: | bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID" @@ -899,9 +1006,11 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); + const { main } = require(path.join(actionsDir, 'redact_secrets.cjs')); await main(); env: GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' @@ -925,25 +1034,30 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_ALLOWED_DOMAINS: "api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs'); + const { main } = require(path.join(actionsDir, 'collect_ndjson_output.cjs')); await main(); - name: Parse agent logs for step summary if: always() uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs'); + const { main } = require(path.join(actionsDir, 'parse_copilot_log.cjs')); await main(); - name: Parse MCP Gateway logs for step summary if: always() @@ -951,34 +1065,29 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs'); + const { main } = require(path.join(actionsDir, 'parse_mcp_gateway_log.cjs')); await main(); - name: Print firewall logs if: always() continue-on-error: true env: AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs - run: | - # Fix permissions on firewall logs/audit dirs so they can be uploaded as artifacts - # AWF runs with sudo, creating files owned by root - sudo chmod -R a+rX /tmp/gh-aw/sandbox/firewall 2>/dev/null || true - # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) - if command -v awf &> /dev/null; then - awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" - else - echo 'AWF binary not installed, skipping firewall log summary' - fi + run: bash "${RUNNER_TEMP}/gh-aw/actions/print_firewall_logs.sh" --rootless - name: Parse token usage for step summary if: always() continue-on-error: true uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs'); + const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs')); await main(); - name: Print AWF reflect summary if: always() @@ -986,16 +1095,41 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/awf_reflect_summary.cjs'); + const { main } = require(path.join(actionsDir, 'awf_reflect_summary.cjs')); await main(); + - name: Generate observability summary + if: always() + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'generate_observability_summary.cjs')); + await main(core); - name: Write agent output placeholder if missing if: always() run: | if [ ! -f /tmp/gh-aw/agent_output.json ]; then echo '{"items":[]}' > /tmp/gh-aw/agent_output.json fi + # Small dedicated copy of the agent output so safe-output processing + # survives a failed or timed-out upload of the larger agent artifact + - name: Upload agent output fallback artifact + if: always() + continue-on-error: true + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: agent-output-fallback + path: | + /tmp/gh-aw/agent_output.json + /tmp/gh-aw/safeoutputs.jsonl + if-no-files-found: ignore - name: Upload agent artifacts if: always() continue-on-error: true @@ -1010,8 +1144,9 @@ jobs: /tmp/gh-aw/agent_usage.json /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/pre-agent-audit.txt - /tmp/gh-aw/agent/ /tmp/gh-aw/github_rate_limits.jsonl + /tmp/gh-aw/otel.jsonl + /tmp/gh-aw/otlp-export-errors.jsonl /tmp/gh-aw/safeoutputs.jsonl /tmp/gh-aw/agent_output.json /tmp/gh-aw/aw-*.patch @@ -1030,9 +1165,11 @@ jobs: - safe_outputs if: > always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' || - needs.activation.outputs.stale_lock_file_failed == 'true' || needs.activation.outputs.daily_ai_credits_exceeded == 'true') + needs.activation.outputs.oauth_token_check_failed == 'true' || needs.activation.outputs.stale_lock_file_failed == 'true' || + needs.activation.outputs.secret_verification_result == 'failed' || needs.activation.outputs.daily_ai_credits_exceeded == 'true') runs-on: ubuntu-slim permissions: + actions: read contents: write issues: write pull-requests: write @@ -1040,6 +1177,8 @@ jobs: group: "gh-aw-conclusion-sync-jp-docs-angular" cancel-in-progress: false queue: max + env: + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} outputs: incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1048,7 +1187,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1057,15 +1196,16 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-angular.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: agent + pattern: "{agent,agent-output-fallback}" + merge-multiple: true path: /tmp/gh-aw/ - name: Setup agent output environment variable id: setup-agent-output-env @@ -1073,32 +1213,29 @@ jobs: run: | mkdir -p /tmp/gh-aw/ find "/tmp/gh-aw/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + if [ -f "/tmp/gh-aw/agent_output.json" ]; then + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + fi + - name: Download detection artifact + id: download-detection-artifact + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: detection + path: /tmp/gh-aw/threat-detection/ + - name: Download Safe Outputs Items Manifest + id: download-safe-outputs-manifest + if: always() + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: safe-outputs-items + merge-multiple: true + path: /tmp/gh-aw/ - name: Collect usage artifact files if: always() continue-on-error: true - run: | - mkdir -p /tmp/gh-aw/usage/agent /tmp/gh-aw/usage/detection - echo "Usage artifact source file status:" - for file in /tmp/gh-aw/aw_info.json /tmp/gh-aw/aw-info.jsonl /tmp/gh-aw/agent_usage.jsonl /tmp/gh-aw/detection_usage.jsonl /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/threat-detection/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/threat-detection/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/threat-detection/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl; do - [ -f "$file" ] && echo "FOUND: $file" || echo "MISSING: $file" - done - [ -f /tmp/gh-aw/aw_info.json ] && cp /tmp/gh-aw/aw_info.json /tmp/gh-aw/usage/aw_info.json || true - [ -f /tmp/gh-aw/aw-info.jsonl ] && cp /tmp/gh-aw/aw-info.jsonl /tmp/gh-aw/usage/aw-info.jsonl || true - [ -f /tmp/gh-aw/agent_usage.jsonl ] && cp /tmp/gh-aw/agent_usage.jsonl /tmp/gh-aw/usage/agent_usage.jsonl || true - [ -f /tmp/gh-aw/detection_usage.jsonl ] && cp /tmp/gh-aw/detection_usage.jsonl /tmp/gh-aw/usage/detection_usage.jsonl || true - [ -f /tmp/gh-aw/github_rate_limits.jsonl ] && cp /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/usage/github_rate_limits.jsonl || true - [ -f /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl || true - [ -f /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl || true - [ -f /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl || true - [ -f /tmp/gh-aw/threat-detection/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/threat-detection/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl || true - [ -f /tmp/gh-aw/threat-detection/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/threat-detection/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl || true - [ -f /tmp/gh-aw/threat-detection/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/threat-detection/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl || true - [ -f /tmp/gh-aw/usage/agent/token_usage.jsonl ] || : > /tmp/gh-aw/usage/agent/token_usage.jsonl - [ -f /tmp/gh-aw/usage/detection/token_usage.jsonl ] || : > /tmp/gh-aw/usage/detection/token_usage.jsonl - mkdir -p /tmp/gh-aw/usage/activity - node ${{ runner.temp }}/gh-aw/actions/generate_usage_activity_summary.cjs - find /tmp/gh-aw/usage -type f -print | sort + run: bash "${RUNNER_TEMP}/gh-aw/actions/collect_usage_artifact_files.sh" - name: Upload usage artifact if: always() continue-on-error: true @@ -1108,8 +1245,12 @@ jobs: path: | /tmp/gh-aw/usage/aw_info.json /tmp/gh-aw/usage/aw-info.jsonl + /tmp/gh-aw/usage/agent_usage.json /tmp/gh-aw/usage/agent_usage.jsonl /tmp/gh-aw/usage/detection_usage.jsonl + /tmp/gh-aw/usage/evals.jsonl + /tmp/gh-aw/usage/graders/grader_manifest.json + /tmp/gh-aw/usage/graders/grader_results.json /tmp/gh-aw/usage/github_rate_limits.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl @@ -1119,7 +1260,7 @@ jobs: id: restore-daily-aic-cache-conclusion if: always() continue-on-error: true - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: agentic-workflow-usage-syncjpdocsangular-${{ github.run_id }} restore-keys: agentic-workflow-usage-syncjpdocsangular- @@ -1132,15 +1273,17 @@ jobs: with: github-token: ${{ github.token }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context); - const { main } = require('${{ runner.temp }}/gh-aw/actions/write_daily_aic_usage_cache.cjs'); + const { main } = require(path.join(actionsDir, 'write_daily_aic_usage_cache.cjs')); await main(); - name: Save daily AIC usage cache id: save-daily-aic-cache if: always() continue-on-error: true - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: agentic-workflow-usage-syncjpdocsangular-${{ github.run_id }} path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl @@ -1164,7 +1307,7 @@ jobs: GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sync-jp-docs-angular.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_NOOP_REPORT_AS_ISSUE: "true" + GH_AW_NOOP_REPORT_AS_ISSUE: "false" GH_AW_AIC: ${{ needs.agent.outputs.aic }} GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }} GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }} @@ -1172,9 +1315,11 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs'); + const { main } = require(path.join(actionsDir, 'handle_noop_message.cjs')); await main(); - name: Log detection run id: detection_runs @@ -1189,9 +1334,11 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_detection_runs.cjs'); + const { main } = require(path.join(actionsDir, 'handle_detection_runs.cjs')); await main(); - name: Record missing tool id: missing_tool @@ -1204,9 +1351,11 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs'); + const { main } = require(path.join(actionsDir, 'missing_tool.cjs')); await main(); - name: Record incomplete id: report_incomplete @@ -1219,9 +1368,11 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/report_incomplete_handler.cjs'); + const { main } = require(path.join(actionsDir, 'report_incomplete_handler.cjs')); await main(); - name: Handle agent failure id: handle_agent_failure @@ -1234,9 +1385,10 @@ jobs: GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "sync-jp-docs-angular" - GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "168" + GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "0" GH_AW_ENGINE_ID: "copilot" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} + GH_AW_ENGINE_SECRET_FAILURE_MESSAGE: "**Alternative**: If your organization has a Copilot subscription, you can avoid the need for a personal access token by adding a top-level `permissions` block to your workflow file. This enables Copilot inference through the org using the built-in GitHub Actions token.\n\n```yaml\npermissions:\n copilot-requests: write\n```\n\nSee: https://github.github.com/gh-aw/reference/engines/#github-copilot-default" GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }} GH_AW_AI_CREDITS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.ai_credits_rate_limit_error || 'false' }} @@ -1248,10 +1400,16 @@ jobs: GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }} + GH_AW_HTTP_400_RESPONSE_ERROR: ${{ needs.agent.outputs.http_400_response_error }} + GH_AW_MAX_CACHE_MISSES_EXCEEDED: ${{ needs.agent.outputs.max_cache_misses_exceeded }} + GH_AW_MISSING_MODEL_PRICING_ERROR: ${{ needs.agent.outputs.missing_model_pricing_error }} + GH_AW_MISSING_MODEL_PRICING_MODEL_NAME: ${{ needs.agent.outputs.missing_model_pricing_model_name }} + GH_AW_SHELL_EXPANSION_GUARD_REJECTED: ${{ needs.agent.outputs.shell_expansion_guard_rejected }} GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com" GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }} GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }} GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} + GH_AW_OAUTH_TOKEN_CHECK_FAILED: ${{ needs.activation.outputs.oauth_token_check_failed }} GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }} GH_AW_DAILY_AI_CREDITS_TOTAL_EFFECTIVE_TOKENS: ${{ needs.activation.outputs.daily_ai_credits_total_effective_tokens }} @@ -1264,20 +1422,43 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'handle_agent_failure.cjs')); + await main(); + - name: Report failed jobs + id: report_failed_jobs + if: always() + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sync-jp-docs-angular.md" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_REPORT_FAILED_JOBS: "true" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs'); + const { main } = require(path.join(actionsDir, 'report_failed_jobs.cjs')); await main(); detection: needs: - activation - agent - if: > - always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true') + if: always() && needs.agent.result != 'skipped' runs-on: ubuntu-latest permissions: contents: read + timeout-minutes: 10 + env: + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} outputs: aic: ${{ steps.parse_detection_token_usage.outputs.aic }} detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} @@ -1286,7 +1467,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1295,15 +1476,22 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-angular.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" + - name: Download activation artifact + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: activation + path: /tmp/gh-aw - name: Download agent output artifact id: download-agent-output continue-on-error: true uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: agent + pattern: "{agent,agent-output-fallback}" + merge-multiple: true path: /tmp/gh-aw/ - name: Setup agent output environment variable id: setup-agent-output-env @@ -1311,10 +1499,12 @@ jobs: run: | mkdir -p /tmp/gh-aw/ find "/tmp/gh-aw/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + if [ -f "/tmp/gh-aw/agent_output.json" ]; then + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + fi - name: Checkout repository for patch context if: needs.agent.outputs.has_patch == 'true' - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false # --- Threat Detection --- @@ -1323,7 +1513,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6 ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.14@sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14@sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5 ghcr.io/github/gh-aw-firewall/squid:0.28.14@sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5 - name: Check if detection needed id: detection_guard if: always() @@ -1347,21 +1537,7 @@ jobs: - name: Prepare threat detection files if: always() && steps.detection_guard.outputs.run_detection == 'true' run: | - mkdir -p /tmp/gh-aw/threat-detection/aw-prompts - rm -f /tmp/gh-aw/agent_usage.json - cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true - if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then - echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context." - fi - cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true - for f in /tmp/gh-aw/aw-*.patch; do - [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true - done - for f in /tmp/gh-aw/aw-*.bundle; do - [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true - done - echo "Prepared threat detection files:" - ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + bash "${RUNNER_TEMP}/gh-aw/actions/prepare_threat_detection_files.sh" - name: Setup threat detection if: always() && steps.detection_guard.outputs.run_detection == 'true' uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1369,83 +1545,57 @@ jobs: WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" WORKFLOW_DESCRIPTION: "Monitors pushes to the vnext branch and keeps the Japanese documentation (docs/angular/src/content/jp) in sync with changes made to the English documentation (docs/angular/src/content/en). For each modified English file, the agent translates the updated content into Japanese and creates a pull request with the changes." HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" + GH_AW_DETECTION_SKIP_PROMPT_SUMMARY: "true" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs'); + const { main } = require(path.join(actionsDir, 'setup_threat_detection.cjs')); await main(); - name: Ensure threat-detection directory and log if: always() && steps.detection_guard.outputs.run_detection == 'true' run: | mkdir -p /tmp/gh-aw/threat-detection touch /tmp/gh-aw/threat-detection/detection.log + - name: Install AWF binary + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.14 --rootless - name: Setup Node.js - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '24' package-manager-cache: false - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.63 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" env: GH_HOST: github.com - - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.7 - - name: Execute GitHub Copilot CLI + GH_AW_COMPILED_VERSION: v0.88.7 + - name: Install threat-detect binary if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true - id: detection_agentic_execution - # Copilot CLI tool arguments (sorted): - timeout-minutes: 20 run: | - set -o pipefail - printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt - trap 'rm -f "$HOME/.copilot/settings.json"' EXIT - mkdir -p "$HOME/.copilot" - printf '%s' '{"builtInAgents":{"rubberDuck":false}}' > "$HOME/.copilot/settings.json" - export XDG_CONFIG_HOME="$HOME" - touch /tmp/gh-aw/agent-step-summary.md - GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) - export GH_AW_NODE_BIN - export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" - (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) - GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-400}" - printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.7/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"github.com\",\"host.docker.internal\",\"registry.npmjs.org\",\"telemetry.enterprise.githubcopilot.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5},\"container\":{\"imageTag\":\"0.27.7,squid=sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96,agent=sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c,api-proxy=sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6,cli-proxy=sha256:4757f198a3fa20f88bdbe70be7ae1a05f127d9c0a9e96a5d6460ef40c08fc83d\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" - cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json - export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" - GH_AW_DOCKER_HOST="" - if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then - GH_AW_DOCKER_HOST="${DOCKER_HOST}" - fi - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" - if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" - _GH_AW_CHROOT_JSON=$(jq -c --arg src /tmp/gh-aw --arg user "$(id -un)" --argjson uid "$(id -u)" --argjson gid "$(id -g)" --arg home /tmp/gh-aw/home '.chroot={"binariesSourcePath":$src,"identity":{"user":$user,"uid":$uid,"gid":$gid,"home":$home}}' "${RUNNER_TEMP}/gh-aw/awf-config.json") || { echo "chroot config patch failed" >&2; exit 1; } - printf '%s\n' "$_GH_AW_CHROOT_JSON" > "${RUNNER_TEMP}/gh-aw/awf-config.json" - printf '%s\n' "$_GH_AW_CHROOT_JSON" > "/tmp/gh-aw/awf-config.json" - fi - GH_AW_TOOL_CACHE_MOUNT="" - GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}" - if [ -d "$GH_AW_TOOL_CACHE" ]; then - if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then - GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" - fi - fi - # shellcheck disable=SC1003,SC2086 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'set +o histexpand; : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; export PATH="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + bash "${RUNNER_TEMP}/gh-aw/actions/install_threat_detect_binary.sh" v0.5.1 + - name: Execute threat detection with AWF + id: detection_agentic_execution + if: always() && steps.detection_guard.outputs.run_detection == 'true' + continue-on-error: true + timeout-minutes: 10 env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} + COPILOT_MODEL: detection + GH_AW_HARNESS_MAX_RETRIES: 0 + GH_AW_LLM_PROVIDER: github GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }} GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_TIMEOUT_MINUTES: 20 - GH_AW_VERSION: v0.80.9 + GH_AW_TIMEOUT_MINUTES: 10 + GH_AW_VERSION: v0.88.7 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -1460,61 +1610,110 @@ jobs: GIT_COMMITTER_NAME: github-actions[bot] RUNNER_TEMP: ${{ runner.temp }} TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }} - - name: Parse threat detection token usage for step summary - id: parse_detection_token_usage - if: always() + WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" + WORKFLOW_DESCRIPTION: "Monitors pushes to the vnext branch and keeps the Japanese documentation (docs/angular/src/content/jp) in sync with changes made to the English documentation (docs/angular/src/content/en). For each modified English file, the agent translates the updated content into Japanese and creates a pull request with the changes." + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" + run: | + set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt + GH_AW_COPILOT_SRC="$(command -v copilot 2>/dev/null || true)" + if [ -z "$GH_AW_COPILOT_SRC" ] || [ ! -x "$GH_AW_COPILOT_SRC" ]; then + echo "GitHub Copilot CLI executable not found on PATH after installation" >&2 + exit 127 + fi + GH_AW_COPILOT_BIN="${RUNNER_TEMP}/gh-aw/bin/copilot" + mkdir -p "${RUNNER_TEMP}/gh-aw/bin" + if [ "$GH_AW_COPILOT_SRC" != "$GH_AW_COPILOT_BIN" ]; then + cp "$GH_AW_COPILOT_SRC" "$GH_AW_COPILOT_BIN" + fi + chmod 755 "$GH_AW_COPILOT_BIN" + + (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) + GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-400}" + if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then + GH_AW_MAX_AI_CREDITS="400" + fi + printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.14/awf-config.schema.json\",\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.14,squid=sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5,agent=sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98,api-proxy=sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5,cli-proxy=sha256:3a379c5e96e29499c815e9dd2a71334d01c326a9b73991c76544fda9cae35c34\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" + GH_AW_DOCKER_HOST="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST="${DOCKER_HOST}" + fi + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + _GH_AW_CHROOT_JSON=$(jq -c --arg src "${RUNNER_TEMP}/gh-aw" --arg user "$(id -un)" --argjson uid "$(id -u)" --argjson gid "$(id -g)" --arg home "${RUNNER_TEMP}/gh-aw/home" '.chroot={"binariesSourcePath":$src,"identity":{"user":$user,"uid":$uid,"gid":$gid,"home":$home}}' "${RUNNER_TEMP}/gh-aw/awf-config.json") || { echo "chroot config patch failed" >&2; exit 1; } + printf '%s\n' "$_GH_AW_CHROOT_JSON" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + fi + GH_AW_TOOL_CACHE_MOUNT="" + GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}" + if [ -d "$GH_AW_TOOL_CACHE" ]; then + if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then + GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" + fi + fi + # shellcheck disable=SC1003,SC2016,SC2086 + awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env COPILOT_GITHUB_TOKEN --mount /tmp/gh-aw:/tmp/gh-aw:rw --mount /tmp/gh-aw/threat-detection:/tmp/gh-aw/threat-detection:rw --log-level info --skip-pull \ + -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && threat-detect --engine copilot --output /tmp/gh-aw/threat-detection/detection_result.json /tmp/gh-aw/threat-detection' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + - name: Render detection log + if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - GH_AW_TOKEN_USAGE_SUMMARY_TITLE: Threat Detection Token Usage with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs'); + const { main } = require(path.join(actionsDir, 'render_detection_log.cjs')); await main(); - - name: Upload threat detection log + - name: Copy detection firewall logs + if: always() && steps.detection_guard.outputs.run_detection == 'true' + continue-on-error: true + run: | + mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall + if [ -d /tmp/gh-aw/sandbox/firewall/logs ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/logs && cp -r /tmp/gh-aw/sandbox/firewall/logs/. /tmp/gh-aw/threat-detection/sandbox/firewall/logs/; fi + if [ -d /tmp/gh-aw/sandbox/firewall/audit ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/audit && cp -r /tmp/gh-aw/sandbox/firewall/audit/. /tmp/gh-aw/threat-detection/sandbox/firewall/audit/; fi + - name: Upload threat detection artifact if: always() && steps.detection_guard.outputs.run_detection == 'true' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: detection - path: /tmp/gh-aw/threat-detection/detection.log + path: | + /tmp/gh-aw/threat-detection/detection_result.json + /tmp/gh-aw/threat-detection/sandbox/firewall/logs/ + /tmp/gh-aw/threat-detection/sandbox/firewall/audit/ if-no-files-found: ignore - - name: Parse and conclude threat detection - id: detection_conclusion + - name: Parse threat detection token usage for step summary + id: parse_detection_token_usage if: always() continue-on-error: true uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + GH_AW_TOKEN_USAGE_SUMMARY_TITLE: Threat Detection Token Usage + with: + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs')); + await main(); + - name: Conclude threat detection + id: detection_conclusion + if: always() + continue-on-error: true env: RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }} GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" - with: - script: | - try { - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); - await main(); - } catch (loadErr) { - const continueOnError = process.env.GH_AW_DETECTION_CONTINUE_ON_ERROR !== 'false'; - const detectionExecutionFailed = process.env.DETECTION_AGENTIC_EXECUTION_OUTCOME === 'failure'; - const msg = 'ERR_SYSTEM: \u274C Unexpected error loading threat detection module: ' + (loadErr && loadErr.message ? loadErr.message : String(loadErr)); - core.error(msg); - core.setOutput('reason', 'parse_error'); - if (continueOnError && !detectionExecutionFailed) { - core.warning('\u26A0\uFE0F ' + msg); - core.setOutput('conclusion', 'warning'); - core.setOutput('success', 'false'); - } else { - core.setOutput('conclusion', 'failure'); - core.setOutput('success', 'false'); - core.setFailed(msg); - } - } + run: | + bash "${RUNNER_TEMP}/gh-aw/actions/conclude_threat_detection.sh" /tmp/gh-aw/threat-detection/detection_result.json pre_activation: runs-on: ubuntu-slim + env: + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} outputs: activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} matched_command: '' @@ -1524,15 +1723,15 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-angular.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" - name: Check team membership for workflow id: check_membership @@ -1542,9 +1741,11 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_membership.cjs'); + const { main } = require(path.join(actionsDir, 'check_membership.cjs')); await main(); safe_outputs: @@ -1569,7 +1770,7 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} - GH_AW_ENGINE_VERSION: "1.0.63" + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }} GH_AW_WORKFLOW_ID: "sync-jp-docs-angular" GH_AW_WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" @@ -1581,12 +1782,20 @@ jobs: create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} created_pr_number: ${{ steps.process_safe_outputs.outputs.created_pr_number }} created_pr_url: ${{ steps.process_safe_outputs.outputs.created_pr_url }} + process_safe_outputs_items_applied: ${{ steps.process_safe_outputs.outputs.items_applied }} + process_safe_outputs_items_cancelled: ${{ steps.process_safe_outputs.outputs.items_cancelled }} + process_safe_outputs_items_deferred: ${{ steps.process_safe_outputs.outputs.items_deferred }} + process_safe_outputs_items_failed: ${{ steps.process_safe_outputs.outputs.items_failed }} + process_safe_outputs_items_skipped: ${{ steps.process_safe_outputs.outputs.items_skipped }} + process_safe_outputs_items_succeeded: ${{ steps.process_safe_outputs.outputs.items_succeeded }} + process_safe_outputs_items_warnings: ${{ steps.process_safe_outputs.outputs.items_warnings }} process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} + process_safe_outputs_status: ${{ steps.process_safe_outputs.outputs.status }} process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1595,15 +1804,18 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (Angular)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-angular.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" + - name: Mask OTLP telemetry headers + run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" - name: Download agent output artifact id: download-agent-output continue-on-error: true uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: agent + pattern: "{agent,agent-output-fallback}" + merge-multiple: true path: /tmp/gh-aw/ - name: Setup agent output environment variable id: setup-agent-output-env @@ -1611,7 +1823,9 @@ jobs: run: | mkdir -p /tmp/gh-aw/ find "/tmp/gh-aw/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + if [ -f "/tmp/gh-aw/agent_output.json" ]; then + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + fi - name: Download patch artifact continue-on-error: true uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1620,7 +1834,7 @@ jobs: path: /tmp/gh-aw/ - name: Checkout repository if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: true token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} @@ -1646,17 +1860,19 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} - GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_ALLOWED_DOMAINS: "api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_pull_request\":{\"base_branch\":\"vnext\",\"draft\":false,\"if_no_changes\":\"ignore\",\"labels\":[\"translation\",\"japanese\",\"automation\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[jp-sync] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_pull_request\":{\"base_branch\":\"vnext\",\"draft\":false,\"if_no_changes\":\"ignore\",\"labels\":[\"translation\",\"japanese\",\"automation\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[jp-sync] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs'); + const { main } = require(path.join(actionsDir, 'process_safe_outputs.cjs')); await main(); - name: Upload Safe Outputs Items if: always() @@ -1666,5 +1882,5 @@ jobs: path: | /tmp/gh-aw/safe-output-items.jsonl /tmp/gh-aw/temporary-id-map.json + /tmp/gh-aw/safe-output-errors.json if-no-files-found: ignore - diff --git a/.github/workflows/sync-jp-docs-xplat.lock.yml b/.github/workflows/sync-jp-docs-xplat.lock.yml index 11732e9e50..4efe245130 100644 --- a/.github/workflows/sync-jp-docs-xplat.lock.yml +++ b/.github/workflows/sync-jp-docs-xplat.lock.yml @@ -1,15 +1,15 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"3be0e260ff016c2a55ebcd858d000bcdff8fe7d1589000325e7b32c8116ba554","body_hash":"d88254a3e362e4146de4edda9875ee6ef2fab63e0cae554972e00fb2154c7404","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.63"}} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/cache/save","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} -# This file was automatically generated by gh-aw (v0.80.9). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"3be0e260ff016c2a55ebcd858d000bcdff8fe7d1589000325e7b32c8116ba554","body_hash":"63a107f55951ca48863523fe0fef93df4c548f8b63fd0ec6f72e8a8ce1ec591c","compiler_version":"v0.88.7","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.80"}} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_DEFAULT_OTLP_HEADERS","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"5e508589e03a7757a7e05b26e834292f5445bfb6","version":"v0.88.7"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.28.14","digest":"sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.28.14@sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14","digest":"sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14@sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.28.14","digest":"sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.28.14@sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.18","digest":"sha256:85b940556a8faa4e1fdbef124bfd75f2c4ebd855a10b88a1c3b6f3e97f6f1a53","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.18@sha256:85b940556a8faa4e1fdbef124bfd75f2c4ebd855a10b88a1c3b6f3e97f6f1a53"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0daa8971fa4732b647150cb6524a6b0804b68d5d24f6f58b5dd1af23bd63fb23","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0daa8971fa4732b647150cb6524a6b0804b68d5d24f6f58b5dd1af23bd63fb23"},{"image":"ghcr.io/github/github-mcp-server:v1.11.0","digest":"sha256:fbec75de11c255213fa08d80fb166abe73d851fff631c51c0079872967720699","pinned_image":"ghcr.io/github/github-mcp-server:v1.11.0@sha256:fbec75de11c255213fa08d80fb166abe73d851fff631c51c0079872967720699"}],"mcp_servers":[{"name":"github","tools":["get_commit","get_file_contents","get_latest_release","get_me","get_pull_request","get_pull_request_comments","get_pull_request_diff","get_pull_request_files","get_pull_request_review_comments","get_pull_request_reviews","get_pull_request_status","get_release_by_tag","get_tag","issue_read","list_branches","list_commits","list_issue_types","list_issues","list_pull_requests","list_releases","list_starred_repositories","list_tags","pull_request_read","search_code","search_issues","search_pull_requests","search_repositories"]},{"name":"safeoutputs","tools":["create_pull_request","missing_data","missing_tool","noop"]}]} +# This file was automatically generated by gh-aw (v0.88.7). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # -# ___ _ _ -# / _ \ | | (_) -# | |_| | __ _ ___ _ __ | |_ _ ___ +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ # | _ |/ _` |/ _ \ '_ \| __| |/ __| -# | | | | (_| | __/ | | | |_| | (__ +# | | | | (_| | __/ | | | |_| | (__ # \_| |_/\__, |\___|_| |_|\__|_|\___| # __/ | -# _ _ |___/ +# _ _ |___/ # | | | | / _| | # | | | | ___ _ __ _ __| |_| | _____ ____ # | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| @@ -28,36 +28,37 @@ # Secrets used: # - COPILOT_GITHUB_TOKEN # - GH_AW_CI_TRIGGER_TOKEN +# - GH_AW_DEFAULT_OTLP_HEADERS # - GH_AW_GITHUB_MCP_SERVER_TOKEN # - GH_AW_GITHUB_TOKEN # - GITHUB_TOKEN # # Custom actions used: -# - actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 -# - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 +# - actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 +# - actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 -# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 +# - actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 +# - github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6 -# - ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96 -# - ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7 -# - ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b -# - ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036 +# - ghcr.io/github/gh-aw-firewall/agent:0.28.14@sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14@sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5 +# - ghcr.io/github/gh-aw-firewall/squid:0.28.14@sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5 +# - ghcr.io/github/gh-aw-mcpg:v0.4.18@sha256:85b940556a8faa4e1fdbef124bfd75f2c4ebd855a10b88a1c3b6f3e97f6f1a53 +# - ghcr.io/github/gh-aw-node@sha256:0daa8971fa4732b647150cb6524a6b0804b68d5d24f6f58b5dd1af23bd63fb23 +# - ghcr.io/github/github-mcp-server:v1.11.0@sha256:fbec75de11c255213fa08d80fb166abe73d851fff631c51c0079872967720699 name: "Sync Japanese Documentation (xplat)" on: push: branches: - - vnext + - vnext paths: - - docs/xplat/src/content/en/** + - docs/xplat/src/content/en/** workflow_dispatch: inputs: aw_context: @@ -70,9 +71,18 @@ permissions: {} concurrency: group: "gh-aw-${{ github.workflow }}-${{ github.ref || github.run_id }}" + queue: max run-name: "Sync Japanese Documentation (xplat)" +env: + OTEL_EXPORTER_OTLP_ENDPOINT: ${{ vars.GH_AW_DEFAULT_OTLP_ENDPOINT }} + OTEL_SERVICE_NAME: gh-aw.sync-jp-docs-xplat + OTEL_RESOURCE_ATTRIBUTES: 'gh-aw.workflow.name=Sync%20Japanese%20Documentation%20%28xplat%29,gh-aw.repository=${{ github.repository }},gh-aw.run.id=${{ github.run_id }},github.run_id=${{ github.run_id }},gh-aw.engine.id=copilot' + OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }} + GH_AW_OTLP_ENDPOINTS: '[{"url":"${{ vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}","headers":"${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}"}]' + GH_AW_OTLP_IF_MISSING: ignore + jobs: activation: needs: pre_activation @@ -83,15 +93,18 @@ jobs: contents: read env: GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }} + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} outputs: comment_id: "" comment_repo: "" daily_ai_credits_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} + daily_ai_credits_guardrail_status: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_guardrail_status || '' }} daily_ai_credits_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} daily_ai_credits_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_ai_credits_total_effective_tokens || '' }} engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} + oauth_token_check_failed: ${{ steps.check-oauth-tokens.outputs.oauth_token_check_failed == 'true' }} secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} setup-span-id: ${{ steps.setup.outputs.span-id }} @@ -100,7 +113,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -110,40 +123,45 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-xplat.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" + - name: Mask OTLP telemetry headers + run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" - name: Generate agentic run info id: generate_aw_info env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" - GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AGENT_VERSION: "1.0.63" - GH_AW_INFO_CLI_VERSION: "v0.80.9" + GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }} + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AGENT_VERSION: "1.0.80" + GH_AW_INFO_CLI_VERSION: "v0.88.7" GH_AW_INFO_WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" + GH_AW_INFO_AGENT_RUNTIME: "" GH_AW_COMPILED_STRICT: "true" uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); + const { main } = require(path.join(actionsDir, 'generate_aw_info.cjs')); await main(core, context); - name: Restore daily AIC usage cache id: restore-daily-aic-cache if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} continue-on-error: true - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: agentic-workflow-usage-syncjpdocsxplat-${{ github.run_id }} restore-keys: agentic-workflow-usage-syncjpdocsxplat- @@ -159,9 +177,11 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/restore_aic_usage_cache_fallback.cjs'); + const { main } = require(path.join(actionsDir, 'restore_aic_usage_cache_fallback.cjs')); await main(); - name: Check daily workflow token guardrail id: daily-effective-workflow-guardrail @@ -179,37 +199,43 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_daily_aic_workflow_guardrail.cjs'); + const { main } = require(path.join(actionsDir, 'check_daily_aic_workflow_guardrail.cjs')); await main(); - name: Validate COPILOT_GITHUB_TOKEN secret id: validate-secret run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default env: COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + - name: Check for OAuth tokens + id: check-oauth-tokens + run: bash "${RUNNER_TEMP}/gh-aw/actions/check_oauth_tokens.sh" + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - name: Checkout .github and .agents folders - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false sparse-checkout: | .github .agents - .antigravity .claude .codex - .crush .gemini - .opencode .pi sparse-checkout-cone-mode: true fetch-depth: 1 - name: Save agent config folders for base branch restoration env: - GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" - # poutine:ignore untrusted_checkout_exec - run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh" + GH_AW_AGENT_FOLDERS: ".agents .github" + GH_AW_AGENT_FILES: "AGENTS.md" + run: | + bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh" - name: Check workflow lock file id: check-lock-file uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -218,24 +244,34 @@ jobs: GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs'); + const { main } = require(path.join(actionsDir, 'check_workflow_timestamp_api.cjs')); await main(); - name: Check compile-agentic version uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_COMPILED_VERSION: "v0.80.9" + GH_AW_COMPILED_VERSION: "v0.88.7" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_version_updates.cjs'); + const { main } = require(path.join(actionsDir, 'check_version_updates.cjs')); await main(); + - name: Log runtime features + if: ${{ contains(toJSON(vars), '"GH_AW_RUNTIME_FEATURES":') }} + run: bash "${RUNNER_TEMP}/gh-aw/actions/log_runtime_features_summary.sh" - name: Create prompt with built-in context + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_ACTIONS_DIR: ${{ runner.temp }}/gh-aw/actions + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_PROMPT_CONFIG: "{\"items\":[{\"content_env\":\"GH_AW_PROMPT_CONTENT_0000\"},{\"file\":\"xpia.md\"},{\"file\":\"temp_folder_prompt.md\"},{\"file\":\"markdown.md\"},{\"file\":\"safe_outputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0001\"},{\"file\":\"safe_outputs_create_pull_request.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0002\"},{\"file\":\"mcp_cli_tools_with_safeoutputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0003\"},{\"file\":\"github_mcp_tools_with_safeoutputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0004\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0005\"}]}" GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} @@ -244,77 +280,35 @@ jobs: GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - # poutine:ignore untrusted_checkout_exec - run: | - bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" - { - cat << 'GH_AW_PROMPT_43128737c4e73d61_EOF' - - GH_AW_PROMPT_43128737c4e73d61_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" - cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" - cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" - cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_43128737c4e73d61_EOF' - - Tools: create_pull_request, missing_tool, missing_data, noop - GH_AW_PROMPT_43128737c4e73d61_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_43128737c4e73d61_EOF' - - GH_AW_PROMPT_43128737c4e73d61_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_43128737c4e73d61_EOF' - - The following GitHub context information is available for this workflow: - {{#if github.actor}} - - **actor**: __GH_AW_GITHUB_ACTOR__ - {{/if}} - {{#if github.repository}} - - **repository**: __GH_AW_GITHUB_REPOSITORY__ - {{/if}} - {{#if github.workspace}} - - **workspace**: __GH_AW_GITHUB_WORKSPACE__ - {{/if}} - {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}} - - **issue-number**: #__GH_AW_EXPR_802A9F6A__ - {{/if}} - {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}} - - **discussion-number**: #__GH_AW_EXPR_1A3A194A__ - {{/if}} - {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}} - - **pull-request-number**: #__GH_AW_EXPR_463A214A__ - {{/if}} - {{#if github.event.comment.id || github.aw.context.comment_id}} - - **comment-id**: __GH_AW_EXPR_FF1D34CE__ - {{/if}} - {{#if github.run_id}} - - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ - {{/if}} - - - GH_AW_PROMPT_43128737c4e73d61_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_43128737c4e73d61_EOF' - - {{#runtime-import .github/workflows/sync-jp-docs-xplat.md}} - GH_AW_PROMPT_43128737c4e73d61_EOF - } > "$GH_AW_PROMPT" + GH_AW_PROMPT_CONTENT_0000: "\n" + GH_AW_PROMPT_CONTENT_0001: "\nTools: create_pull_request, missing_tool, missing_data, noop\n" + GH_AW_PROMPT_CONTENT_0002: "\n" + GH_AW_PROMPT_CONTENT_0003: "\nThe following GitHub context information is available for this workflow:\n{{#if github.actor}}\n- **actor**: __GH_AW_GITHUB_ACTOR__\n{{/if}}\n{{#if github.repository}}\n- **repository**: __GH_AW_GITHUB_REPOSITORY__\n{{/if}}\n{{#if github.workspace}}\n- **workspace**: __GH_AW_GITHUB_WORKSPACE__\n{{/if}}\n{{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}}\n- **issue-number**: #__GH_AW_EXPR_802A9F6A__\n{{/if}}\n{{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}}\n- **discussion-number**: #__GH_AW_EXPR_1A3A194A__\n{{/if}}\n{{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}}\n- **pull-request-number**: #__GH_AW_EXPR_463A214A__\n{{/if}}\n{{#if github.event.comment.id || github.aw.context.comment_id}}\n- **comment-id**: __GH_AW_EXPR_FF1D34CE__\n{{/if}}\n{{#if github.run_id}}\n- **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__\n{{/if}}\n\n\n" + GH_AW_PROMPT_CONTENT_0004: "\n" + GH_AW_PROMPT_CONTENT_0005: "{{#runtime-import .github/workflows/sync-jp-docs-xplat.md}}\n" + with: + script: | + const { setupGlobals } = require(process.env.GH_AW_ACTIONS_DIR + '/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(process.env.GH_AW_ACTIONS_DIR + '/create_prompt.cjs'); + await main(core); - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt GH_AW_ENGINE_ID: "copilot" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs'); + const { main } = require(path.join(actionsDir, 'interpolate_prompt.cjs')); await main(); - name: Substitute placeholders uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} @@ -323,15 +317,17 @@ jobs: GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools' + GH_AW_MCP_CLI_SERVERS_LIST: "- `github` — run `github --help` to see available tools\n- `safeoutputs` — run `safeoutputs --help` to see available tools" GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }} with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - - const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs'); - + + const substitutePlaceholders = require(path.join(actionsDir, 'substitute_placeholders.cjs')); + // Call the substitution function return await substitutePlaceholders({ file: process.env.GH_AW_PROMPT, @@ -350,16 +346,20 @@ jobs: }); - name: Validate prompt placeholders env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - # poutine:ignore untrusted_checkout_exec - run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh" + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt + run: | + bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh" - name: Print prompt env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - # poutine:ignore untrusted_checkout_exec - run: bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh" + GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt + run: | + bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh" + - name: Stage prompt files for artifact upload + run: | + mkdir -p /tmp/gh-aw/aw-prompts + cp -a "${RUNNER_TEMP}/gh-aw/aw-prompts/." /tmp/gh-aw/aw-prompts/ - name: Upload activation artifact - if: success() + if: success() || failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: activation @@ -384,12 +384,20 @@ jobs: permissions: actions: read contents: read + timeout-minutes: 60 env: DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} GH_AW_ASSETS_ALLOWED_EXTS: "" GH_AW_ASSETS_BRANCH: "" GH_AW_ASSETS_MAX_SIZE_KB: 0 GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + GH_AW_PR_HEAD_BASE_BRANCH: "" + GH_AW_PR_HEAD_BASE_PR_NUMBER: "" + GH_AW_PR_HEAD_BASE_REF: "" + GH_AW_PR_HEAD_BASE_REPO: "" + GH_AW_PR_HEAD_BASE_SHA: "" + GH_AW_PR_HEAD_REPO: "" + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} GH_AW_WORKFLOW_ID_SANITIZED: syncjpdocsxplat outputs: agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }} @@ -399,8 +407,13 @@ jobs: checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} has_patch: ${{ steps.collect_output.outputs.has_patch }} + http_400_response_error: ${{ steps.detect-agent-errors.outputs.http_400_response_error || 'false' }} inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }} + invocation_cap_exceeded: ${{ steps.detect-agent-errors.outputs.invocation_cap_exceeded || 'false' }} + max_cache_misses_exceeded: ${{ steps.detect-agent-errors.outputs.max_cache_misses_exceeded || 'false' }} mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }} + missing_model_pricing_error: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_error || 'false' }} + missing_model_pricing_model_name: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_model_name || '' }} model: ${{ needs.activation.outputs.model }} model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} @@ -408,11 +421,12 @@ jobs: setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} + shell_expansion_guard_rejected: ${{ steps.detect-agent-errors.outputs.shell_expansion_guard_rejected || 'false' }} unknown_model_ai_credits: ${{ steps.parse-mcp-gateway.outputs.unknown_model_ai_credits || 'false' }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -421,19 +435,28 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-xplat.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths + env: + GH_AW_RUNNER_TOOL_CACHE: ${{ runner.tool_cache }} run: | + if [ -z "${RUNNER_TOOL_CACHE:-}" ]; then + echo "RUNNER_TOOL_CACHE=${GH_AW_RUNNER_TOOL_CACHE}" >> "$GITHUB_ENV" + fi { echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl" echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json" } >> "$GITHUB_OUTPUT" + - name: Mask OTLP telemetry headers + run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" + - name: Check OTLP telemetry configuration + run: bash "${RUNNER_TEMP}/gh-aw/actions/check_otlp_default_credentials.sh" - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Create gh-aw temp directory @@ -442,6 +465,11 @@ jobs: run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} + - name: Download activation artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: activation + path: /tmp/gh-aw - name: Configure Git credentials env: GITHUB_REPOSITORY: ${{ github.repository }} @@ -458,16 +486,19 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); + const { main } = require(path.join(actionsDir, 'checkout_pr_branch.cjs')); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.63 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" env: GH_HOST: github.com + GH_AW_COMPILED_VERSION: v0.88.7 - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.7 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.14 --rootless - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -476,18 +507,15 @@ jobs: GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} with: script: | - const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const determineAutomaticLockdown = require(path.join(actionsDir, 'determine_automatic_lockdown.cjs')); await determineAutomaticLockdown(github, context, core); - - name: Download activation artifact - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: activation - path: /tmp/gh-aw - name: Restore agent config folders from base branch if: steps.checkout-pr.outcome == 'success' env: - GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi" - GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" + GH_AW_AGENT_FOLDERS: ".agents .github" + GH_AW_AGENT_FILES: "AGENTS.md" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh" - name: Restore inline sub-agents from activation artifact env: @@ -499,15 +527,26 @@ jobs: GH_AW_SKILL_DIR: ".github/skills" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6 ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96 ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036 - - name: Generate Safe Outputs Config + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.14@sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14@sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5 ghcr.io/github/gh-aw-firewall/squid:0.28.14@sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5 ghcr.io/github/gh-aw-mcpg:v0.4.18@sha256:85b940556a8faa4e1fdbef124bfd75f2c4ebd855a10b88a1c3b6f3e97f6f1a53 ghcr.io/github/gh-aw-node@sha256:0daa8971fa4732b647150cb6524a6b0804b68d5d24f6f58b5dd1af23bd63fb23 ghcr.io/github/github-mcp-server:v1.11.0@sha256:fbec75de11c255213fa08d80fb166abe73d851fff631c51c0079872967720699 + - name: Prepare Safe Outputs Directories run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_7e98029480883c79_EOF' - {"create_pull_request":{"base_branch":"vnext","draft":false,"if_no_changes":"ignore","labels":["translation","japanese","automation"],"max":1,"max_patch_files":100,"max_patch_size":4096,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[jp-sync] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_7e98029480883c79_EOF + - name: Generate Safe Outputs Config + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + GH_AW_FILE_ROOT: "${{ runner.temp }}/gh-aw" + GH_AW_FILE_CONFIG: "{\"files\":[{\"path\":\"safeoutputs/config.json\",\"content_env\":\"GH_AW_SAFE_OUTPUTS_CONFIG\"}]}" + GH_AW_SAFE_OUTPUTS_CONFIG: "{\"create_pull_request\":{\"base_branch\":\"vnext\",\"draft\":false,\"if_no_changes\":\"ignore\",\"labels\":[\"translation\",\"japanese\",\"automation\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[jp-sync] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"report_incomplete\":{}}" + with: + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'create_files.cjs')); + await main(); - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -540,6 +579,12 @@ jobs: "sanitize": true, "maxLength": 256 }, + "dependencies": { + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 256 + }, "draft": { "type": "boolean" }, @@ -553,6 +598,18 @@ jobs: "type": "string", "maxLength": 256 }, + "stack_position": { + "optionalPositiveInteger": true + }, + "stack_root": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "temporary_id": { + "type": "string", + "pattern": "^#?aw_[A-Za-z0-9_]{3,12}$" + }, "title": { "required": true, "type": "string", @@ -638,16 +695,20 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_safe_outputs_tools.cjs'); + const { main } = require(path.join(actionsDir, 'generate_safe_outputs_tools.cjs')); await main(); - name: Start MCP Gateway id: start-mcp-gateway env: + GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST: ${{ vars.GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST || 'true' }} GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }} GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }} + GH_AW_SINK_VISIBILITY: ${{ steps.determine-automatic-lockdown.outputs.visibility }} GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} @@ -655,41 +716,49 @@ jobs: run: | set -eo pipefail mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config" - + if [ -n "${GITHUB_EVENT_PATH:-}" ] && [ -r "${GITHUB_EVENT_PATH}" ]; then + GH_AW_SAFEOUTPUTS_EVENT_PATH="${RUNNER_TEMP}/gh-aw/safeoutputs/github_event.json" + cp "${GITHUB_EVENT_PATH}" "${GH_AW_SAFEOUTPUTS_EVENT_PATH}" + export GITHUB_EVENT_PATH="${GH_AW_SAFEOUTPUTS_EVENT_PATH}" + fi + # Export gateway environment variables for MCP config and gateway script export MCP_GATEWAY_PORT="8080" - export MCP_GATEWAY_DOMAIN="host.docker.internal" + export MCP_GATEWAY_DOMAIN="awmg-mcpg" export MCP_GATEWAY_HOST_DOMAIN="localhost" - MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${MCP_GATEWAY_API_KEY}" - export MCP_GATEWAY_API_KEY + MCP_GATEWAY_AGENT_ID=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${MCP_GATEWAY_AGENT_ID}" + export MCP_GATEWAY_AGENT_ID export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" + export MCP_GATEWAY_ALLOWED_MOUNT_ROOTS="${GITHUB_WORKSPACE}:rw,${RUNNER_TEMP}/gh-aw:ro,${RUNNER_TEMP}/gh-aw/safeoutputs:rw,/opt:ro,/tmp:rw,/usr/bin/gh:ro" + export GH_AW_PR_HEAD_BASE_BRANCH="${GH_AW_PR_HEAD_BASE_BRANCH:-}" + export GH_AW_PR_HEAD_BASE_SHA="${GH_AW_PR_HEAD_BASE_SHA:-}" + export GH_AW_PR_HEAD_BASE_REPO="${GH_AW_PR_HEAD_BASE_REPO:-}" + export GH_AW_PR_HEAD_BASE_PR_NUMBER="${GH_AW_PR_HEAD_BASE_PR_NUMBER:-}" + export GH_AW_PR_HEAD_BASE_REF="${GH_AW_PR_HEAD_BASE_REF:-}" + export GH_AW_PR_HEAD_REPO="${GH_AW_PR_HEAD_REPO:-}" export DEBUG="*" - + export GH_AW_ENGINE="copilot" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') - case "${DOCKER_HOST:-}" in - unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;; - /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;; - * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; - esac - DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --name awmg-mcpg --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.3.27' - + source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh" + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 127.0.0.1:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_AGENT_ID -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_PR_HEAD_BASE_BRANCH -e GH_AW_PR_HEAD_BASE_SHA -e GH_AW_PR_HEAD_BASE_REPO -e GH_AW_PR_HEAD_BASE_PR_NUMBER -e GH_AW_PR_HEAD_BASE_REF -e GH_AW_PR_HEAD_REPO -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GH_AW_SINK_VISIBILITY -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -e RUNNER_TOOL_CACHE -e MCP_GATEWAY_ALLOWED_MOUNT_ROOTS -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.4.18' + mkdir -p "$HOME/.copilot" GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_c70c556baaebe8bb_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_46604863f3d8e286_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.4.0", + "container": "ghcr.io/github/github-mcp-server:v1.11.0", "env": { - "GITHUB_HOST": "\${GITHUB_SERVER_URL}", - "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", + "GITHUB_FEATURES": "fields_param", + "GITHUB_HOST": "${GITHUB_SERVER_URL}", + "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_MCP_SERVER_TOKEN}", "GITHUB_READ_ONLY": "1", "GITHUB_TOOLSETS": "context,repos,issues,pull_requests" }, @@ -717,7 +786,17 @@ jobs: "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}", "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}", "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}", + "GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST": "\${GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST}", + "GH_AW_PR_HEAD_BASE_BRANCH": "\${GH_AW_PR_HEAD_BASE_BRANCH}", + "GH_AW_PR_HEAD_BASE_SHA": "\${GH_AW_PR_HEAD_BASE_SHA}", + "GH_AW_PR_HEAD_BASE_REPO": "\${GH_AW_PR_HEAD_BASE_REPO}", + "GH_AW_PR_HEAD_BASE_PR_NUMBER": "\${GH_AW_PR_HEAD_BASE_PR_NUMBER}", + "GH_AW_PR_HEAD_BASE_REF": "\${GH_AW_PR_HEAD_BASE_REF}", + "GH_AW_PR_HEAD_REPO": "\${GH_AW_PR_HEAD_REPO}", + "GITHUB_EVENT_NAME": "\${GITHUB_EVENT_NAME}", + "GITHUB_EVENT_PATH": "\${GITHUB_EVENT_PATH}", "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}", + "GITHUB_SHA": "\${GITHUB_SHA}", "GITHUB_TOKEN": "\${GITHUB_TOKEN}", "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}", "RUNNER_TEMP": "\${RUNNER_TEMP}" @@ -726,7 +805,8 @@ jobs: "write-sink": { "accept": [ "*" - ] + ], + "sink-visibility": "${GH_AW_SINK_VISIBILITY}" } } } @@ -734,24 +814,32 @@ jobs: "gateway": { "port": $MCP_GATEWAY_PORT, "domain": "${MCP_GATEWAY_DOMAIN}", - "apiKey": "${MCP_GATEWAY_API_KEY}", - "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" + "agentId": "${MCP_GATEWAY_AGENT_ID}", + "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}", + "startupTimeout": 120, + "opentelemetry": { + "endpoint": "${OTEL_EXPORTER_OTLP_ENDPOINT}", + "traceId": "${GITHUB_AW_OTEL_TRACE_ID}", + "spanId": "${GITHUB_AW_OTEL_PARENT_SPAN_ID}" + } } } - GH_AW_MCP_CONFIG_c70c556baaebe8bb_EOF + GH_AW_MCP_CONFIG_46604863f3d8e286_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true env: - MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }} MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }} MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io); - const { main } = require('${{ runner.temp }}/gh-aw/actions/mount_mcp_as_cli.cjs'); + const { main } = require(path.join(actionsDir, 'mount_mcp_as_cli.cjs')); await main(); - name: Clean credentials continue-on-error: true @@ -780,6 +868,7 @@ jobs: # --allow-tool shell(git rm:*) # --allow-tool shell(git status) # --allow-tool shell(git switch:*) + # --allow-tool shell(github:*) # --allow-tool shell(grep) # --allow-tool shell(head) # --allow-tool shell(ls) @@ -796,40 +885,41 @@ jobs: run: | set -o pipefail printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt - trap 'rm -f "$HOME/.copilot/settings.json"' EXIT + trap 'gh_aw_exit_code=$?; mkdir -p /tmp/gh-aw >/dev/null 2>&1 || true; printf "%s" "$gh_aw_exit_code" > /tmp/gh-aw/agent_execution_exit_code.txt || true; rm -f "$HOME/.copilot/settings.json"; if [ "$gh_aw_exit_code" -ne 0 ]; then echo "::error::Agent execution exited with code $gh_aw_exit_code"; fi' EXIT mkdir -p "$HOME/.copilot" printf '%s' '{"builtInAgents":{"rubberDuck":false}}' > "$HOME/.copilot/settings.json" export XDG_CONFIG_HOME="$HOME" export GH_AW_MCP_CONFIG="$HOME/.copilot/mcp-config.json" + GH_AW_COPILOT_SRC="$(command -v copilot 2>/dev/null || true)" + if [ -z "$GH_AW_COPILOT_SRC" ] || [ ! -x "$GH_AW_COPILOT_SRC" ]; then + echo "GitHub Copilot CLI executable not found on PATH after installation" >&2 + exit 127 + fi + GH_AW_COPILOT_BIN="${RUNNER_TEMP}/gh-aw/bin/copilot" + mkdir -p "${RUNNER_TEMP}/gh-aw/bin" + if [ "$GH_AW_COPILOT_SRC" != "$GH_AW_COPILOT_BIN" ]; then + cp "$GH_AW_COPILOT_SRC" "$GH_AW_COPILOT_BIN" + fi + chmod 755 "$GH_AW_COPILOT_BIN" + touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}" - printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.7/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"github.com\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"keyserver.ubuntu.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"raw.githubusercontent.com\",\"registry.npmjs.org\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"telemetry.enterprise.githubcopilot.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.5\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.7,squid=sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96,agent=sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c,api-proxy=sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6,cli-proxy=sha256:4757f198a3fa20f88bdbe70be7ae1a05f127d9c0a9e96a5d6460ef40c08fc83d\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then + GH_AW_MAX_AI_CREDITS="1000" + fi + printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.14/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"json-schema.org\",\"json.schemastore.org\",\"keyserver.ubuntu.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\"],\"isolation\":true,\"topologyAttach\":[\"awmg-mcpg\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.14,squid=sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5,agent=sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98,api-proxy=sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5,cli-proxy=sha256:3a379c5e96e29499c815e9dd2a71334d01c326a9b73991c76544fda9cae35c34\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" GH_AW_DOCKER_HOST="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then GH_AW_DOCKER_HOST="${DOCKER_HOST}" fi - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" - python3 - <<'PY' - import json,os,subprocess as sp - from pathlib import Path - try: - p=Path(os.environ["RUNNER_TEMP"])/"gh-aw"/"awf-config.json" - c=json.loads(p.read_text()) - c["chroot"]={"binariesSourcePath":"/tmp/gh-aw","identity":{"user":sp.check_output(["id","-un"],text=True).strip(),"uid":int(sp.check_output(["id","-u"],text=True)),"gid":int(sp.check_output(["id","-g"],text=True)),"home":"/tmp/gh-aw/home"}} - out=json.dumps(c,separators=(",",":"),ensure_ascii=False)+"\n" - p.write_text(out) - Path("/tmp/gh-aw/awf-config.json").write_text(out) - except Exception as e: - raise SystemExit(f"chroot config patch failed: {e}") from e - PY + GH_AW_CHROOT_BINARIES_SOURCE_PATH="${RUNNER_TEMP}/gh-aw" GH_AW_CHROOT_IDENTITY_HOME="${RUNNER_TEMP}/gh-aw/home" node "${RUNNER_TEMP}/gh-aw/actions/patch_awf_chroot_config.cjs" fi GH_AW_TOOL_CACHE_MOUNT="" GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}" @@ -838,22 +928,28 @@ jobs: GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" fi fi - # shellcheck disable=SC1003,SC2086 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; export PATH="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(find)'\'' --allow-tool '\''shell(git add:*)'\'' --allow-tool '\''shell(git branch:*)'\'' --allow-tool '\''shell(git checkout:*)'\'' --allow-tool '\''shell(git commit:*)'\'' --allow-tool '\''shell(git diff --name-only)'\'' --allow-tool '\''shell(git diff)'\'' --allow-tool '\''shell(git log)'\'' --allow-tool '\''shell(git merge:*)'\'' --allow-tool '\''shell(git rm:*)'\'' --allow-tool '\''shell(git status)'\'' --allow-tool '\''shell(git switch:*)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(printf)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + # shellcheck disable=SC1003,SC2016,SC2086 + GH_AW_AWF_ENGINE_NAME=copilot \ + GH_AW_AWF_HARNESS_MARKER='[copilot-harness]' \ + GH_AW_AWF_LOG_FILE=/tmp/gh-aw/agent-stdio.log \ + GH_AW_AWF_ATTEMPT_LOG_NAME=copilot \ + bash "${RUNNER_TEMP}/gh-aw/actions/run_awf_with_startup_retries.sh" -- \ + awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_AGENT_ID --mount /tmp/gh-aw:/tmp/gh-aw:rw --log-level info --skip-pull \ + -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" "${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs" "${RUNNER_TEMP}/gh-aw/bin/copilot" --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(find)'\'' --allow-tool '\''shell(git add:*)'\'' --allow-tool '\''shell(git branch:*)'\'' --allow-tool '\''shell(git checkout:*)'\'' --allow-tool '\''shell(git commit:*)'\'' --allow-tool '\''shell(git diff --name-only)'\'' --allow-tool '\''shell(git diff)'\'' --allow-tool '\''shell(git log)'\'' --allow-tool '\''shell(git merge:*)'\'' --allow-tool '\''shell(git rm:*)'\'' --allow-tool '\''shell(git status)'\'' --allow-tool '\''shell(git switch:*)'\'' --allow-tool '\''shell(github:*)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(printf)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }} + GH_AW_LLM_PROVIDER: github GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }} GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_TIMEOUT_MINUTES: 30 - GH_AW_VERSION: v0.80.9 + GH_AW_VERSION: v0.88.7 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -873,7 +969,18 @@ jobs: if: always() id: detect-agent-errors continue-on-error: true - run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs" + env: + GH_AW_AGENTIC_EXECUTION_OUTCOME: ${{ steps.agentic_execution.outcome }} + GH_AW_ENGINE_STEP_TIMEOUT_MINUTES: 30 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'detect_agent_errors.cjs')); + await main(); - name: Configure Git credentials env: GITHUB_REPOSITORY: ${{ github.repository }} @@ -889,7 +996,7 @@ jobs: continue-on-error: true env: MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} - MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }} GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} run: | bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID" @@ -898,9 +1005,11 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); + const { main } = require(path.join(actionsDir, 'redact_secrets.cjs')); await main(); env: GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' @@ -924,25 +1033,30 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_ALLOWED_DOMAINS: "api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs'); + const { main } = require(path.join(actionsDir, 'collect_ndjson_output.cjs')); await main(); - name: Parse agent logs for step summary if: always() uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs'); + const { main } = require(path.join(actionsDir, 'parse_copilot_log.cjs')); await main(); - name: Parse MCP Gateway logs for step summary if: always() @@ -950,34 +1064,29 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs'); + const { main } = require(path.join(actionsDir, 'parse_mcp_gateway_log.cjs')); await main(); - name: Print firewall logs if: always() continue-on-error: true env: AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs - run: | - # Fix permissions on firewall logs/audit dirs so they can be uploaded as artifacts - # AWF runs with sudo, creating files owned by root - sudo chmod -R a+rX /tmp/gh-aw/sandbox/firewall 2>/dev/null || true - # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) - if command -v awf &> /dev/null; then - awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" - else - echo 'AWF binary not installed, skipping firewall log summary' - fi + run: bash "${RUNNER_TEMP}/gh-aw/actions/print_firewall_logs.sh" --rootless - name: Parse token usage for step summary if: always() continue-on-error: true uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs'); + const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs')); await main(); - name: Print AWF reflect summary if: always() @@ -985,16 +1094,41 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/awf_reflect_summary.cjs'); + const { main } = require(path.join(actionsDir, 'awf_reflect_summary.cjs')); await main(); + - name: Generate observability summary + if: always() + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'generate_observability_summary.cjs')); + await main(core); - name: Write agent output placeholder if missing if: always() run: | if [ ! -f /tmp/gh-aw/agent_output.json ]; then echo '{"items":[]}' > /tmp/gh-aw/agent_output.json fi + # Small dedicated copy of the agent output so safe-output processing + # survives a failed or timed-out upload of the larger agent artifact + - name: Upload agent output fallback artifact + if: always() + continue-on-error: true + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: agent-output-fallback + path: | + /tmp/gh-aw/agent_output.json + /tmp/gh-aw/safeoutputs.jsonl + if-no-files-found: ignore - name: Upload agent artifacts if: always() continue-on-error: true @@ -1009,8 +1143,9 @@ jobs: /tmp/gh-aw/agent_usage.json /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/pre-agent-audit.txt - /tmp/gh-aw/agent/ /tmp/gh-aw/github_rate_limits.jsonl + /tmp/gh-aw/otel.jsonl + /tmp/gh-aw/otlp-export-errors.jsonl /tmp/gh-aw/safeoutputs.jsonl /tmp/gh-aw/agent_output.json /tmp/gh-aw/aw-*.patch @@ -1029,9 +1164,11 @@ jobs: - safe_outputs if: > always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' || - needs.activation.outputs.stale_lock_file_failed == 'true' || needs.activation.outputs.daily_ai_credits_exceeded == 'true') + needs.activation.outputs.oauth_token_check_failed == 'true' || needs.activation.outputs.stale_lock_file_failed == 'true' || + needs.activation.outputs.secret_verification_result == 'failed' || needs.activation.outputs.daily_ai_credits_exceeded == 'true') runs-on: ubuntu-slim permissions: + actions: read contents: write issues: write pull-requests: write @@ -1039,6 +1176,8 @@ jobs: group: "gh-aw-conclusion-sync-jp-docs-xplat" cancel-in-progress: false queue: max + env: + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} outputs: incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} noop_message: ${{ steps.noop.outputs.noop_message }} @@ -1047,7 +1186,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1056,15 +1195,16 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-xplat.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output continue-on-error: true uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: agent + pattern: "{agent,agent-output-fallback}" + merge-multiple: true path: /tmp/gh-aw/ - name: Setup agent output environment variable id: setup-agent-output-env @@ -1072,32 +1212,29 @@ jobs: run: | mkdir -p /tmp/gh-aw/ find "/tmp/gh-aw/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + if [ -f "/tmp/gh-aw/agent_output.json" ]; then + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + fi + - name: Download detection artifact + id: download-detection-artifact + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: detection + path: /tmp/gh-aw/threat-detection/ + - name: Download Safe Outputs Items Manifest + id: download-safe-outputs-manifest + if: always() + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: safe-outputs-items + merge-multiple: true + path: /tmp/gh-aw/ - name: Collect usage artifact files if: always() continue-on-error: true - run: | - mkdir -p /tmp/gh-aw/usage/agent /tmp/gh-aw/usage/detection - echo "Usage artifact source file status:" - for file in /tmp/gh-aw/aw_info.json /tmp/gh-aw/aw-info.jsonl /tmp/gh-aw/agent_usage.jsonl /tmp/gh-aw/detection_usage.jsonl /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/threat-detection/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/threat-detection/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/threat-detection/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl; do - [ -f "$file" ] && echo "FOUND: $file" || echo "MISSING: $file" - done - [ -f /tmp/gh-aw/aw_info.json ] && cp /tmp/gh-aw/aw_info.json /tmp/gh-aw/usage/aw_info.json || true - [ -f /tmp/gh-aw/aw-info.jsonl ] && cp /tmp/gh-aw/aw-info.jsonl /tmp/gh-aw/usage/aw-info.jsonl || true - [ -f /tmp/gh-aw/agent_usage.jsonl ] && cp /tmp/gh-aw/agent_usage.jsonl /tmp/gh-aw/usage/agent_usage.jsonl || true - [ -f /tmp/gh-aw/detection_usage.jsonl ] && cp /tmp/gh-aw/detection_usage.jsonl /tmp/gh-aw/usage/detection_usage.jsonl || true - [ -f /tmp/gh-aw/github_rate_limits.jsonl ] && cp /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/usage/github_rate_limits.jsonl || true - [ -f /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl || true - [ -f /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl || true - [ -f /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl || true - [ -f /tmp/gh-aw/threat-detection/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/threat-detection/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl || true - [ -f /tmp/gh-aw/threat-detection/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/threat-detection/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl || true - [ -f /tmp/gh-aw/threat-detection/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/threat-detection/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl || true - [ -f /tmp/gh-aw/usage/agent/token_usage.jsonl ] || : > /tmp/gh-aw/usage/agent/token_usage.jsonl - [ -f /tmp/gh-aw/usage/detection/token_usage.jsonl ] || : > /tmp/gh-aw/usage/detection/token_usage.jsonl - mkdir -p /tmp/gh-aw/usage/activity - node ${{ runner.temp }}/gh-aw/actions/generate_usage_activity_summary.cjs - find /tmp/gh-aw/usage -type f -print | sort + run: bash "${RUNNER_TEMP}/gh-aw/actions/collect_usage_artifact_files.sh" - name: Upload usage artifact if: always() continue-on-error: true @@ -1107,8 +1244,12 @@ jobs: path: | /tmp/gh-aw/usage/aw_info.json /tmp/gh-aw/usage/aw-info.jsonl + /tmp/gh-aw/usage/agent_usage.json /tmp/gh-aw/usage/agent_usage.jsonl /tmp/gh-aw/usage/detection_usage.jsonl + /tmp/gh-aw/usage/evals.jsonl + /tmp/gh-aw/usage/graders/grader_manifest.json + /tmp/gh-aw/usage/graders/grader_results.json /tmp/gh-aw/usage/github_rate_limits.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl @@ -1118,7 +1259,7 @@ jobs: id: restore-daily-aic-cache-conclusion if: always() continue-on-error: true - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: agentic-workflow-usage-syncjpdocsxplat-${{ github.run_id }} restore-keys: agentic-workflow-usage-syncjpdocsxplat- @@ -1131,15 +1272,17 @@ jobs: with: github-token: ${{ github.token }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context); - const { main } = require('${{ runner.temp }}/gh-aw/actions/write_daily_aic_usage_cache.cjs'); + const { main } = require(path.join(actionsDir, 'write_daily_aic_usage_cache.cjs')); await main(); - name: Save daily AIC usage cache id: save-daily-aic-cache if: always() continue-on-error: true - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: agentic-workflow-usage-syncjpdocsxplat-${{ github.run_id }} path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl @@ -1163,7 +1306,7 @@ jobs: GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sync-jp-docs-xplat.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_NOOP_REPORT_AS_ISSUE: "true" + GH_AW_NOOP_REPORT_AS_ISSUE: "false" GH_AW_AIC: ${{ needs.agent.outputs.aic }} GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }} GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }} @@ -1171,9 +1314,11 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs'); + const { main } = require(path.join(actionsDir, 'handle_noop_message.cjs')); await main(); - name: Log detection run id: detection_runs @@ -1188,9 +1333,11 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_detection_runs.cjs'); + const { main } = require(path.join(actionsDir, 'handle_detection_runs.cjs')); await main(); - name: Record missing tool id: missing_tool @@ -1203,9 +1350,11 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs'); + const { main } = require(path.join(actionsDir, 'missing_tool.cjs')); await main(); - name: Record incomplete id: report_incomplete @@ -1218,9 +1367,11 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/report_incomplete_handler.cjs'); + const { main } = require(path.join(actionsDir, 'report_incomplete_handler.cjs')); await main(); - name: Handle agent failure id: handle_agent_failure @@ -1233,9 +1384,10 @@ jobs: GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "sync-jp-docs-xplat" - GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "168" + GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "0" GH_AW_ENGINE_ID: "copilot" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} + GH_AW_ENGINE_SECRET_FAILURE_MESSAGE: "**Alternative**: If your organization has a Copilot subscription, you can avoid the need for a personal access token by adding a top-level `permissions` block to your workflow file. This enables Copilot inference through the org using the built-in GitHub Actions token.\n\n```yaml\npermissions:\n copilot-requests: write\n```\n\nSee: https://github.github.com/gh-aw/reference/engines/#github-copilot-default" GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }} GH_AW_AI_CREDITS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.ai_credits_rate_limit_error || 'false' }} @@ -1247,10 +1399,16 @@ jobs: GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }} + GH_AW_HTTP_400_RESPONSE_ERROR: ${{ needs.agent.outputs.http_400_response_error }} + GH_AW_MAX_CACHE_MISSES_EXCEEDED: ${{ needs.agent.outputs.max_cache_misses_exceeded }} + GH_AW_MISSING_MODEL_PRICING_ERROR: ${{ needs.agent.outputs.missing_model_pricing_error }} + GH_AW_MISSING_MODEL_PRICING_MODEL_NAME: ${{ needs.agent.outputs.missing_model_pricing_model_name }} + GH_AW_SHELL_EXPANSION_GUARD_REJECTED: ${{ needs.agent.outputs.shell_expansion_guard_rejected }} GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com" GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }} GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }} GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} + GH_AW_OAUTH_TOKEN_CHECK_FAILED: ${{ needs.activation.outputs.oauth_token_check_failed }} GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }} GH_AW_DAILY_AI_CREDITS_TOTAL_EFFECTIVE_TOKENS: ${{ needs.activation.outputs.daily_ai_credits_total_effective_tokens }} @@ -1263,20 +1421,43 @@ jobs: with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'handle_agent_failure.cjs')); + await main(); + - name: Report failed jobs + id: report_failed_jobs + if: always() + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sync-jp-docs-xplat.md" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_REPORT_FAILED_JOBS: "true" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs'); + const { main } = require(path.join(actionsDir, 'report_failed_jobs.cjs')); await main(); detection: needs: - activation - agent - if: > - always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true') + if: always() && needs.agent.result != 'skipped' runs-on: ubuntu-latest permissions: contents: read + timeout-minutes: 10 + env: + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} outputs: aic: ${{ steps.parse_detection_token_usage.outputs.aic }} detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} @@ -1285,7 +1466,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1294,15 +1475,22 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-xplat.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" + - name: Download activation artifact + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: activation + path: /tmp/gh-aw - name: Download agent output artifact id: download-agent-output continue-on-error: true uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: agent + pattern: "{agent,agent-output-fallback}" + merge-multiple: true path: /tmp/gh-aw/ - name: Setup agent output environment variable id: setup-agent-output-env @@ -1310,10 +1498,12 @@ jobs: run: | mkdir -p /tmp/gh-aw/ find "/tmp/gh-aw/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + if [ -f "/tmp/gh-aw/agent_output.json" ]; then + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + fi - name: Checkout repository for patch context if: needs.agent.outputs.has_patch == 'true' - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false # --- Threat Detection --- @@ -1322,7 +1512,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6 ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.14@sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.14@sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5 ghcr.io/github/gh-aw-firewall/squid:0.28.14@sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5 - name: Check if detection needed id: detection_guard if: always() @@ -1346,21 +1536,7 @@ jobs: - name: Prepare threat detection files if: always() && steps.detection_guard.outputs.run_detection == 'true' run: | - mkdir -p /tmp/gh-aw/threat-detection/aw-prompts - rm -f /tmp/gh-aw/agent_usage.json - cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true - if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then - echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context." - fi - cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true - for f in /tmp/gh-aw/aw-*.patch; do - [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true - done - for f in /tmp/gh-aw/aw-*.bundle; do - [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true - done - echo "Prepared threat detection files:" - ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + bash "${RUNNER_TEMP}/gh-aw/actions/prepare_threat_detection_files.sh" - name: Setup threat detection if: always() && steps.detection_guard.outputs.run_detection == 'true' uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1368,83 +1544,57 @@ jobs: WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" WORKFLOW_DESCRIPTION: "Monitors pushes to the vnext branch and keeps the Japanese documentation (docs/xplat/src/content/jp) in sync with changes made to the English documentation (docs/xplat/src/content/en). For each modified English file, the agent translates the updated content into Japanese and creates a pull request with the changes." HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" + GH_AW_DETECTION_SKIP_PROMPT_SUMMARY: "true" with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs'); + const { main } = require(path.join(actionsDir, 'setup_threat_detection.cjs')); await main(); - name: Ensure threat-detection directory and log if: always() && steps.detection_guard.outputs.run_detection == 'true' run: | mkdir -p /tmp/gh-aw/threat-detection touch /tmp/gh-aw/threat-detection/detection.log + - name: Install AWF binary + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.14 --rootless - name: Setup Node.js - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '24' package-manager-cache: false - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.63 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" env: GH_HOST: github.com - - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.7 - - name: Execute GitHub Copilot CLI + GH_AW_COMPILED_VERSION: v0.88.7 + - name: Install threat-detect binary if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true - id: detection_agentic_execution - # Copilot CLI tool arguments (sorted): - timeout-minutes: 20 run: | - set -o pipefail - printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt - trap 'rm -f "$HOME/.copilot/settings.json"' EXIT - mkdir -p "$HOME/.copilot" - printf '%s' '{"builtInAgents":{"rubberDuck":false}}' > "$HOME/.copilot/settings.json" - export XDG_CONFIG_HOME="$HOME" - touch /tmp/gh-aw/agent-step-summary.md - GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) - export GH_AW_NODE_BIN - export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" - (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) - GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-400}" - printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.7/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"github.com\",\"host.docker.internal\",\"registry.npmjs.org\",\"telemetry.enterprise.githubcopilot.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5},\"container\":{\"imageTag\":\"0.27.7,squid=sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96,agent=sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c,api-proxy=sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6,cli-proxy=sha256:4757f198a3fa20f88bdbe70be7ae1a05f127d9c0a9e96a5d6460ef40c08fc83d\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" - cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json - export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" - GH_AW_DOCKER_HOST="" - if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then - GH_AW_DOCKER_HOST="${DOCKER_HOST}" - fi - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" - if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" - _GH_AW_CHROOT_JSON=$(jq -c --arg src /tmp/gh-aw --arg user "$(id -un)" --argjson uid "$(id -u)" --argjson gid "$(id -g)" --arg home /tmp/gh-aw/home '.chroot={"binariesSourcePath":$src,"identity":{"user":$user,"uid":$uid,"gid":$gid,"home":$home}}' "${RUNNER_TEMP}/gh-aw/awf-config.json") || { echo "chroot config patch failed" >&2; exit 1; } - printf '%s\n' "$_GH_AW_CHROOT_JSON" > "${RUNNER_TEMP}/gh-aw/awf-config.json" - printf '%s\n' "$_GH_AW_CHROOT_JSON" > "/tmp/gh-aw/awf-config.json" - fi - GH_AW_TOOL_CACHE_MOUNT="" - GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}" - if [ -d "$GH_AW_TOOL_CACHE" ]; then - if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then - GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" - fi - fi - # shellcheck disable=SC1003,SC2086 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'set +o histexpand; : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; export PATH="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + bash "${RUNNER_TEMP}/gh-aw/actions/install_threat_detect_binary.sh" v0.5.1 + - name: Execute threat detection with AWF + id: detection_agentic_execution + if: always() && steps.detection_guard.outputs.run_detection == 'true' + continue-on-error: true + timeout-minutes: 10 env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} + COPILOT_MODEL: detection + GH_AW_HARNESS_MAX_RETRIES: 0 + GH_AW_LLM_PROVIDER: github GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }} GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_TIMEOUT_MINUTES: 20 - GH_AW_VERSION: v0.80.9 + GH_AW_TIMEOUT_MINUTES: 10 + GH_AW_VERSION: v0.88.7 GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows @@ -1459,61 +1609,110 @@ jobs: GIT_COMMITTER_NAME: github-actions[bot] RUNNER_TEMP: ${{ runner.temp }} TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }} - - name: Parse threat detection token usage for step summary - id: parse_detection_token_usage - if: always() + WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" + WORKFLOW_DESCRIPTION: "Monitors pushes to the vnext branch and keeps the Japanese documentation (docs/xplat/src/content/jp) in sync with changes made to the English documentation (docs/xplat/src/content/en). For each modified English file, the agent translates the updated content into Japanese and creates a pull request with the changes." + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" + run: | + set -o pipefail + printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt + GH_AW_COPILOT_SRC="$(command -v copilot 2>/dev/null || true)" + if [ -z "$GH_AW_COPILOT_SRC" ] || [ ! -x "$GH_AW_COPILOT_SRC" ]; then + echo "GitHub Copilot CLI executable not found on PATH after installation" >&2 + exit 127 + fi + GH_AW_COPILOT_BIN="${RUNNER_TEMP}/gh-aw/bin/copilot" + mkdir -p "${RUNNER_TEMP}/gh-aw/bin" + if [ "$GH_AW_COPILOT_SRC" != "$GH_AW_COPILOT_BIN" ]; then + cp "$GH_AW_COPILOT_SRC" "$GH_AW_COPILOT_BIN" + fi + chmod 755 "$GH_AW_COPILOT_BIN" + + (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) + GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-400}" + if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then + GH_AW_MAX_AI_CREDITS="400" + fi + printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.14/awf-config.schema.json\",\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.14,squid=sha256:2ce8df3abf3e9b76e9c0cf5863da41f1ab3f89b20ad14b988806ab89e7bf2cd5,agent=sha256:f7df036c86575527b61f3f7df91c4412349a12b2a74988d929eafa2999230c98,api-proxy=sha256:6f95e2234dd9bd6333a8ff28ccea7ecf0204acd4a09108723844dbd2bf6268c5,cli-proxy=sha256:3a379c5e96e29499c815e9dd2a71334d01c326a9b73991c76544fda9cae35c34\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" + GH_AW_DOCKER_HOST="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST="${DOCKER_HOST}" + fi + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + _GH_AW_CHROOT_JSON=$(jq -c --arg src "${RUNNER_TEMP}/gh-aw" --arg user "$(id -un)" --argjson uid "$(id -u)" --argjson gid "$(id -g)" --arg home "${RUNNER_TEMP}/gh-aw/home" '.chroot={"binariesSourcePath":$src,"identity":{"user":$user,"uid":$uid,"gid":$gid,"home":$home}}' "${RUNNER_TEMP}/gh-aw/awf-config.json") || { echo "chroot config patch failed" >&2; exit 1; } + printf '%s\n' "$_GH_AW_CHROOT_JSON" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + fi + GH_AW_TOOL_CACHE_MOUNT="" + GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}" + if [ -d "$GH_AW_TOOL_CACHE" ]; then + if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then + GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" + fi + fi + # shellcheck disable=SC1003,SC2016,SC2086 + awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env COPILOT_GITHUB_TOKEN --mount /tmp/gh-aw:/tmp/gh-aw:rw --mount /tmp/gh-aw/threat-detection:/tmp/gh-aw/threat-detection:rw --log-level info --skip-pull \ + -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && threat-detect --engine copilot --output /tmp/gh-aw/threat-detection/detection_result.json /tmp/gh-aw/threat-detection' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + - name: Render detection log + if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - GH_AW_TOKEN_USAGE_SUMMARY_TITLE: Threat Detection Token Usage with: script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs'); + const { main } = require(path.join(actionsDir, 'render_detection_log.cjs')); await main(); - - name: Upload threat detection log + - name: Copy detection firewall logs + if: always() && steps.detection_guard.outputs.run_detection == 'true' + continue-on-error: true + run: | + mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall + if [ -d /tmp/gh-aw/sandbox/firewall/logs ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/logs && cp -r /tmp/gh-aw/sandbox/firewall/logs/. /tmp/gh-aw/threat-detection/sandbox/firewall/logs/; fi + if [ -d /tmp/gh-aw/sandbox/firewall/audit ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/audit && cp -r /tmp/gh-aw/sandbox/firewall/audit/. /tmp/gh-aw/threat-detection/sandbox/firewall/audit/; fi + - name: Upload threat detection artifact if: always() && steps.detection_guard.outputs.run_detection == 'true' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: detection - path: /tmp/gh-aw/threat-detection/detection.log + path: | + /tmp/gh-aw/threat-detection/detection_result.json + /tmp/gh-aw/threat-detection/sandbox/firewall/logs/ + /tmp/gh-aw/threat-detection/sandbox/firewall/audit/ if-no-files-found: ignore - - name: Parse and conclude threat detection - id: detection_conclusion + - name: Parse threat detection token usage for step summary + id: parse_detection_token_usage if: always() continue-on-error: true uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + GH_AW_TOKEN_USAGE_SUMMARY_TITLE: Threat Detection Token Usage + with: + script: | + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs')); + await main(); + - name: Conclude threat detection + id: detection_conclusion + if: always() + continue-on-error: true env: RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }} GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" - with: - script: | - try { - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); - await main(); - } catch (loadErr) { - const continueOnError = process.env.GH_AW_DETECTION_CONTINUE_ON_ERROR !== 'false'; - const detectionExecutionFailed = process.env.DETECTION_AGENTIC_EXECUTION_OUTCOME === 'failure'; - const msg = 'ERR_SYSTEM: \u274C Unexpected error loading threat detection module: ' + (loadErr && loadErr.message ? loadErr.message : String(loadErr)); - core.error(msg); - core.setOutput('reason', 'parse_error'); - if (continueOnError && !detectionExecutionFailed) { - core.warning('\u26A0\uFE0F ' + msg); - core.setOutput('conclusion', 'warning'); - core.setOutput('success', 'false'); - } else { - core.setOutput('conclusion', 'failure'); - core.setOutput('success', 'false'); - core.setFailed(msg); - } - } + run: | + bash "${RUNNER_TEMP}/gh-aw/actions/conclude_threat_detection.sh" /tmp/gh-aw/threat-detection/detection_result.json pre_activation: runs-on: ubuntu-slim + env: + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} outputs: activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} matched_command: '' @@ -1523,15 +1722,15 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-xplat.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" - name: Check team membership for workflow id: check_membership @@ -1541,9 +1740,11 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/check_membership.cjs'); + const { main } = require(path.join(actionsDir, 'check_membership.cjs')); await main(); safe_outputs: @@ -1568,7 +1769,7 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} - GH_AW_ENGINE_VERSION: "1.0.63" + GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }} GH_AW_WORKFLOW_ID: "sync-jp-docs-xplat" GH_AW_WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" @@ -1580,12 +1781,20 @@ jobs: create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} created_pr_number: ${{ steps.process_safe_outputs.outputs.created_pr_number }} created_pr_url: ${{ steps.process_safe_outputs.outputs.created_pr_url }} + process_safe_outputs_items_applied: ${{ steps.process_safe_outputs.outputs.items_applied }} + process_safe_outputs_items_cancelled: ${{ steps.process_safe_outputs.outputs.items_cancelled }} + process_safe_outputs_items_deferred: ${{ steps.process_safe_outputs.outputs.items_deferred }} + process_safe_outputs_items_failed: ${{ steps.process_safe_outputs.outputs.items_failed }} + process_safe_outputs_items_skipped: ${{ steps.process_safe_outputs.outputs.items_skipped }} + process_safe_outputs_items_succeeded: ${{ steps.process_safe_outputs.outputs.items_succeeded }} + process_safe_outputs_items_warnings: ${{ steps.process_safe_outputs.outputs.items_warnings }} process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} + process_safe_outputs_status: ${{ steps.process_safe_outputs.outputs.status }} process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} steps: - name: Setup Scripts id: setup - uses: github/gh-aw-actions/setup@8c7d04ebf1ece56cd381446125da3e0f6896294a # v0.80.9 + uses: github/gh-aw-actions/setup@5e508589e03a7757a7e05b26e834292f5445bfb6 # v0.88.7 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1594,15 +1803,18 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Sync Japanese Documentation (xplat)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sync-jp-docs-xplat.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.7" + GH_AW_INFO_VERSION: "1.0.80" + GH_AW_INFO_AWF_VERSION: "v0.28.14" GH_AW_INFO_ENGINE_ID: "copilot" + - name: Mask OTLP telemetry headers + run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" - name: Download agent output artifact id: download-agent-output continue-on-error: true uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: agent + pattern: "{agent,agent-output-fallback}" + merge-multiple: true path: /tmp/gh-aw/ - name: Setup agent output environment variable id: setup-agent-output-env @@ -1610,7 +1822,9 @@ jobs: run: | mkdir -p /tmp/gh-aw/ find "/tmp/gh-aw/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + if [ -f "/tmp/gh-aw/agent_output.json" ]; then + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + fi - name: Download patch artifact continue-on-error: true uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1619,7 +1833,7 @@ jobs: path: /tmp/gh-aw/ - name: Checkout repository if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: true token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} @@ -1645,17 +1859,19 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} - GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_ALLOWED_DOMAINS: "api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_pull_request\":{\"base_branch\":\"vnext\",\"draft\":false,\"if_no_changes\":\"ignore\",\"labels\":[\"translation\",\"japanese\",\"automation\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[jp-sync] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_pull_request\":{\"base_branch\":\"vnext\",\"draft\":false,\"if_no_changes\":\"ignore\",\"labels\":[\"translation\",\"japanese\",\"automation\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[jp-sync] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + const path = require('path'); + const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); + const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs'); + const { main } = require(path.join(actionsDir, 'process_safe_outputs.cjs')); await main(); - name: Upload Safe Outputs Items if: always() @@ -1665,5 +1881,5 @@ jobs: path: | /tmp/gh-aw/safe-output-items.jsonl /tmp/gh-aw/temporary-id-map.json + /tmp/gh-aw/safe-output-errors.json if-no-files-found: ignore - diff --git a/cspell.json b/cspell.json index d4117e45dd..42f68b5116 100644 --- a/cspell.json +++ b/cspell.json @@ -397,6 +397,7 @@ "agentic", "wireframes", "opensource", - "unlayered" + "unlayered", + "VPAT" ] } diff --git a/docs/angular/package.json b/docs/angular/package.json index c9b3014c82..98f3d6fdcf 100644 --- a/docs/angular/package.json +++ b/docs/angular/package.json @@ -35,10 +35,9 @@ "node": ">=22.12.0" }, "dependencies": { - "astro": "^7.2.2", + "astro": "^7.3.4", "docs-template": "file:../../", - "igniteui-astro-components": "1.0.2", - "sharp": "^0.35.3" + "igniteui-astro-components": "1.3.0" }, "devDependencies": { "cross-env": "^7.0.3", diff --git a/docs/angular/src/content/en/.gitignore b/docs/angular/src/content/en/.gitignore index bc6cd82100..7b9ece5436 100644 --- a/docs/angular/src/content/en/.gitignore +++ b/docs/angular/src/content/en/.gitignore @@ -62,6 +62,8 @@ components/pivotGrid/*.mdx # All xplat-generated topics that should be ignored: /components/charts/ +/components/inputs/ +/components/layouts/ /components/geo-map*.mdx /components/spreadsheet-*.mdx /components/excel-library*.mdx @@ -72,7 +74,6 @@ components/pivotGrid/*.mdx /components/radial-gauge.mdx /components/zoomslider-overview.mdx /components/general-changelog-dv.mdx -/components/inputs/color-editor.mdx /components/interactivity/accessibility-compliance.mdx /components/maps/map-api.mdx /components/menus/toolbar.mdx diff --git a/docs/angular/src/content/en/components/accordion.mdx b/docs/angular/src/content/en/components/accordion.mdx deleted file mode 100644 index e47cdfb254..0000000000 --- a/docs/angular/src/content/en/components/accordion.mdx +++ /dev/null @@ -1,318 +0,0 @@ ---- -title: Angular Accordion Component – Fully-featured collapsible panels - Infragistics - MIT license -description: Angular Accordion is used to build vertical expandable panels in accordion menu. Check how to do it with Ignite UI for Angular accordion component. -keywords: angular accordion, angular accordion component, angular accordion example, ignite ui for angular, angular UI components, infragistics -license: MIT -llms: - description: "The Angular Accordion is a GUI component for building vertical expandable panels with clickable headers and associated content sections, displayed in a single container." ---- - -import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; -import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; -import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; - -# Angular Accordion Component Overview - -## What is Angular Accordion? - -The Angular Accordion is a GUI component for building vertical expandable panels with clickable headers and associated content sections, displayed in a single container. The accordion is commonly used to reduce the need of scrolling across multiple sections of content on a single page. It offers keyboard navigation and API to control the underlying panels' expansion state. - -Users are enabled to interact and navigate among a list of items, such as thumbnails or labels. Each one of those items can be toggled (expanded or collapsed) in order to reveal the containing information. Depending on the configuration, there can be a single or multiple expanded items at a time. - -## Angular Accordion Example - -The following is a basic Angular Accordion example of a FAQ section. It operates as an accordion, with individually working sections. You can toggle each text block with a single click, while expanding multiple panels at the same time. This way you can read information more easily, without having to go back and forth between an automatically expanding and collapsing panel, which conceals the previously opened section every time. - -In it, you can see how to define an `igx-accordion` and its . The sample also demonstrates the two types of expansion behavior. The switch button sets the property to toggle between single and multiple branches to be expanded at a time. - - - -
- -## Getting Started with Ignite UI for Angular Accordion - -To get started with the Ignite UI for Angular Accordion component, first you need to install Ignite UI for Angular. In an existing Angular application, type the following command: - -```cmd -ng add igniteui-angular -``` - -For a complete introduction to the Ignite UI for Angular, read the [_getting started_](/general/getting-started) topic. - -The next step is to import the `IgxAccordionModule` in your **app.module.ts** file. - -```typescript -// app.module.ts - -... -import { IgxAccordionModule } from 'igniteui-angular/accordion'; -// import { IgxAccordionModule } from '@infragistics/igniteui-angular'; for licensed package - -@NgModule({ - ... - imports: [..., IgxAccordionModule], - ... -}) -export class AppModule {} -``` - -Alternatively, as of `16.0.0` you can import the `IgxAccordionComponent` as a standalone dependency, or use the [`IGX_ACCORDION_DIRECTIVES`](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/accordion/src/accordion/public_api.ts) token to import the component and all of its supporting components and directives. - -```typescript -// home.component.ts - -... -import { IGX_ACCORDION_DIRECTIVES } from 'igniteui-angular/accordion'; -// import { IGX_ACCORDION_DIRECTIVES } from '@infragistics/igniteui-angular'; for licensed package - -@Component({ - selector: 'app-home', - template: ` - - - - Title Panel 1 - - - Content Panel 1 - - - - `, - styleUrls: ['home.component.scss'], - standalone: true, - imports: [IGX_ACCORDION_DIRECTIVES] - /* or imports: [IgxAccordionComponent] */ -}) -export class HomeComponent {} -``` - -Now that you have the Ignite UI for Angular Accordion module or directives imported, you can start with a basic configuration of the `igx-accordion` and its panels. - -## Using the Angular Accordion Component - -Each section in the is defined using an . -Panels provide , and properties, which give you the ability to configure the states of the panel as per your requirement. - -### Declaring an accordion - -The accordion wraps all declared inside it. - -```html - - - - Title Panel 1 - - - Content Panel 1 - - - - - Title Panel 2 - - - Content Panel 2 - - - -``` - -Using the accessor you can get a reference to the collection containing all children of the `igx-accordion`. - -```typescript -@ViewChild('accordion', { static: true }) -public accordion!: IgxAccordionComponent; - -this.accordion.panels; -``` - -As demonstrated above, the property gives you the ability to set whether single or multiple panels can be expanded at a time. - -### Angular Accordion Animations - -Angular Accordion supports animations for both expanding and collapsing actions of the panels. Animation behavior can be customized. Normally, animations can be set for each expansion panel individually. However, it could also be applied to all panels at once on level. This gives users the ability to disable animations for all sections at once via the animations property of the . - -With regards to animation, you have two options. First, you could set the property on the accordion component: - -```typescript -import { useAnimation, slideInLeft, slideOutRight } from '@angular/animations'; -// import { useAnimation, slideInLeft, slideOutRight } from '@infragistics/igniteui-angular/animations'; for licensed package - -@Component({ - ... -}) -export class AccordionComponent { - public animationSettingsCustom = { - closeAnimation: useAnimation(slideOutRight, { - params: { - duration: '100ms', - toPosition: 'translateX(25px)' - } - }), - openAnimation: useAnimation(slideInLeft, { - params: { - duration: '500ms', - fromPosition: 'translateX(-15px)', - startOpacity: 0.1 - } - }) - }; -} -``` - -As you can see, we are using and animations from our to make the component content appear from the left side and disappear to the right when collapsing the content. We further customize the animations by overriding some of the animations' parameters. - -The following snippet demonstrates passing the animation settings to the component: - -```html - - ... - -``` - - -If you would like to turn off the animation for the the could be set to `null`. - - -Alternatively, you have the ability to set every single `s input. - -```html - - - - Title Panel 1 - - - Content Panel 1 - - - - - Title Panel 2 - - - Content Panel 2 - - - -``` - -Using the and methods you can respectively collapse and expand all of the programmatically. - - -If property is set to _true_ calling method would expand only the last . - - -### Angular Accordion Templating Example - -With the Angular , you can customize the header and content panel`s appearance. -The sample below demonstrates how elaborate filtering options can be implemented using the built-in templating functionality of the . - - - -
- -### Nested Angular Accordions Scenario - -In the following Angular accordion example, we are going to create a complex FAQ section in order to illustrate how you can go about this common application scenario. In the sample nested is achieved by adding an inside the body of an . - -```html - - - - Title Panel 1 - - - - - - Title Nested Panel 1 - - - Content Nested Panel 1 - - - ... - - - - ... - -``` - -You can see the result below. - - - -
- -## Keyboard Navigation - -Keyboard navigation in the Ignite UI for Angular Accordion provides a rich variety of keyboard interactions to the end-user. This functionality is enabled by default and allows end-users to easily navigate through the panels. -The navigation is compliant with W3C accessibility standards and convenient to use. - -**Key Combinations** - -- Tab - moves the focus to the first(if the focus is before accordion)/next panel -- Shift + Tab - moves the focus to the last(if the focus is after accordion)/previous panel -- Arrow Down - moves the focus to the panel below -- Arrow Up - moves the focus to the panel above -- Alt + Arrow Down - expands the focused panel in the accordion -- Alt + Arrow Up - collapses the focused panel in the accordion -- Shift + Alt + Arrow Down - expands all enabled panels(if singleBranchExpand is set to true expands the last enabled panel) -- Shift + Alt + Arrow Up - collapses all enabled panels -- Home - navigates to the FIRST enabled panel in the accordion -- End - navigates to the LAST enabled panel in the accordion - -## Styling - -The serves only as a container for the underlying . Styles can be applied directly through the panel's theme, as described in the [`styling section of the IgxExpansionPanel topic`](/expansion-panel#styling). - -By design, there is a margin set to the expanded panels, in case that they are positioned within an `igx-accordion`. In order to modify it there is a property exposed inside the igx-expansion-panel theme. -In order to take advantage of the functions exposed by the theming engine, we have to import the `index` file in our style file: - -```scss -@use "igniteui-angular/theming" as *; - -// IMPORTANT: Prior to Ignite UI for Angular version 13 use: -// @import '~igniteui-angular/lib/core/styles/themes/index'; -``` - -Following the simplest approach, we create a new theme that extends the and accepts a `$header-background`, `$body-color` and `$expanded-margin` parameters. The theme automatically assigns foreground colors, either black or white, based on which provides better contrast with the specified backgrounds. - -```scss -$custom-panel-theme: expansion-panel-theme( - $header-background: #011627, - $body-background: #f0ece7, - $expanded-margin: 10px -); -``` - -The last step is to include the component's theme. - -```scss -:host { - @include tokens($custom-panel-theme); -} -``` - -### Demo - - - -## API Reference - -- -- -- -- -- - -## Additional Resources - -Our community is active and always welcoming new ideas. - -- [Ignite UI for Angular **Forums**](https://www.infragistics.com/community/forums/f/ignite-ui-for-angular) -- [Ignite UI for Angular **GitHub**](https://github.com/IgniteUI/igniteui-angular) diff --git a/docs/angular/src/content/en/components/ai/theming-mcp.mdx b/docs/angular/src/content/en/components/ai/theming-mcp.mdx index 60cfe03a47..ce7c9970eb 100644 --- a/docs/angular/src/content/en/components/ai/theming-mcp.mdx +++ b/docs/angular/src/content/en/components/ai/theming-mcp.mdx @@ -247,6 +247,10 @@ To see the current full list of tools and their parameters at any time, ask your Here is a brief overview of each tool: + +When it generates a palette, the server checks the contrast ratio between your surface and gray colors against WCAG thresholds and warns you when the pairing falls short. See [Accessibility](../themes/accessibility.mdx) for the contrast behavior built into the theming engine itself. + + | Tool | Description | |------|-------------| | `detect_platform` | Identifies the project framework and selects the correct import paths and selectors. For Angular, React, and Web Components projects, reads `package.json`. For Blazor projects, which do not have a `package.json`, returns `generic` - tell the AI explicitly: _"Use the Blazor platform."_ | diff --git a/docs/angular/src/content/en/components/button.mdx b/docs/angular/src/content/en/components/button.mdx deleted file mode 100644 index f9dfe1874c..0000000000 --- a/docs/angular/src/content/en/components/button.mdx +++ /dev/null @@ -1,788 +0,0 @@ ---- -title: Angular Button Component - Ignite UI for Angular - MIT license -description: Enhance standard buttons with built-in text, images and more features using Ignite UI for Angular Button component. Try it now. -keywords: Angular Button component, Angular Button control, Ignite UI for Angular, UI controls, Angular widgets, web widgets, UI widgets, Angular, Native Angular Components Suite, Native Angular Controls, Angular UI Components, -license: MIT -llms: - description: "Angular Button directive is used for creating and adding actionable buttons to a web page/application." ---- - -import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; -import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; -import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; - -# Angular Button Overview - -Angular Button directive is used for creating and adding actionable buttons to a web page/application. There are different Angular Button types that are easy to customize and include several built-in features. By default, Angular Material uses native `', - styleUrls: ['home.component.scss'], - standalone: true, - imports: [IgxButtonDirective] -}) -export class HomeComponent {} -``` - -Now that you have the Ignite UI for Angular Button module or directive imported, you can start using the `igxButton` directive on elements. - -## Angular Button Types - -### Flat Button - -Use the directive to add a simple flat button in your component template. Note that if you do not choose a type, by default it will be set to `flat`. - -```html - -``` - - - -### Contained Button - -All you have to do to create a contained button is to change the value of the `igxButton` property: - -```html - -``` - - - -### Outlined Button - -Analogically, we can switch to outlined type: - -```html - -``` - - - -### Icon Button - -As of version `17.1.0` the IgniteUI for Angular exposes a new `igxIconButton` directive intended to turn icons into fully functional buttons. You can read more about the [_Icon Button here_](/icon-button). - -```html - -``` - - -This component uses Material Icons. Add the following link to your `index.html`: `` - - - - -### Floating Action Button - -We can create a floating action button and use an icon to display: - -```html - -``` - -To create an extended FAB, you can add any element prior to the `igx-icon`: - -```html - -``` - - -To get the extended FAB text styled properly, use `` or `
` tags. - - - - -## Examples - -### Angular Disable Button - -The `disabled` property can be used to make a button unclickable: - -```html - -``` - - - -### Ripple - -The directive adds a ripple effect to your buttons or other specified elements. You can easily change the default ripple color, position and duration, using its properties: - -```html - -``` - - - -### Span - -We can also use the `igxButton` directive to turn elements like `span` and `div` into Ignite UI for Angular styled buttons. The default colors can be customized via the `igxButtonColor` and the `igxButtonBackground` properties: - -```html - - Span - -``` - - - -## Size - -We can allow the user to choose the size of the `igxButton` by using the `--ig-size` custom CSS property. To do this, first we have to import the `IgxButtonGroupModule`, and then use the component to display size values. This way whenever one gets selected, we will update the **--ig-size** CSS property. - -```typescript -// app.module.ts -... -import { IgxButtonGroupModule } from 'igniteui-angular/button-group'; -// import { IgxButtonGroupModule } from '@infragistics/igniteui-angular'; for licensed package -@NgModule({ - imports: [ - ... - IgxButtonGroupModule - ... - ] -}) -``` - -```html -{/*buttons-density.component.html*/} - -... - -``` - -```typescript -// buttons-density.component.ts -public size = "large"; -public sizes; -public ngOnInit() { - this.sizes = [ - { label: 'large', selected: this.size === 'large', togglable: true }, - { label: 'medium', selected: this.size === 'medium', togglable: true }, - { label: 'small', selected: this.size === 'small', togglable: true } - ]; -} - -public selectSize(event: any) { - this.size = this.sizes[event.index].label; -} - -@HostBinding('style.--ig-size') -protected get sizeStyle() { - return `var(--ig-size-${this.size})`; -} -``` - -If all went well, you should see something like the following in the browser: - - - -
- -## Styling - -### Button Theme Property Map - -When you modify a primary property, all related dependent properties are updated automatically: - -
- - - - - - - - - -
- -
- -### Material Theme - -#### Flat Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | - -#### Contained Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-background | Focus background color | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $active-background | Active background color | -| | $active-foreground | Active foreground color | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | - -#### Outlined Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $border-color | The border color for outlined buttons. | -| | $hover-border-color | The border color for hovered outlined buttons. | -| | $focus-border-color | The border color for focused outlined buttons. | -| | $focus-visible-border-color | The border color for outlined buttons when focus is visible. | -| | $active-border-color | The border color for active outlined buttons. | - -#### FAB Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-background | Focus background color | -| | $focus-foreground | Foreground on focus | -| | $active-background | Active background color | -| | $active-foreground | Active foreground color | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | - -
- -
- -### Fluent Theme - -#### Flat Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | - -#### Contained Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $active-foreground | Active foreground color | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | - -#### Outlined Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered outlined button. | -| | $focus-background | Background color for focused outlined button. | -| | $focus-hover-background | Background color for outlined button on focus + hover. | -| | $active-background | Background color for active outlined button. | -| | $hover-foreground | Foreground color for hovered outlined button. | -| | $icon-color-hover | Icon color for hovered outlined button. | -| | $focus-foreground | Foreground color for focused outlined button. | -| | $focus-hover-foreground | Foreground color for outlined button on focus + hover. | -| | $active-foreground | Foreground color for active outlined button. | -| | $focus-visible-foreground | Foreground color for outlined button when focus is visible. | -| | $focus-visible-border-color | Border color for outlined button when focus is visible. | -| | $border-color | Border color for outlined button. | -| | $hover-border-color | Border color for hovered outlined button. | -| | $focus-border-color | Border color for focused outlined button. | -| | $active-border-color | Border color for active outlined button. | - -#### FAB Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $active-background | Active background color | -| | $active-foreground | Active foreground color | -| | $focus-background | Focus background color | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | - -
- -
- -### Bootstrap Theme - -#### Flat Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | -| | $disabled-foreground | Foreground color for disabled button | -| | $disabled-icon-color | Icon color for disabled button | -| | $shadow-color | Shadow color | - -#### Contained Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $active-foreground | Active foreground color | -| | $shadow-color | Shadow color | -| | $disabled-background | Disabled background color | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | - -#### Outlined Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | -| | $disabled-foreground | Foreground color for disabled button | -| | $disabled-icon-color | Icon color for disabled button | -| | $disabled-border-color | Border color for disabled button | -| | $hover-border-color | Hover border color | -| | $focus-border-color | Focus border color | -| | $active-border-color | Active border color | -| | $shadow-color | Shadow color | - -#### FAB Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $disabled-background | Disabled background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $active-foreground | Active foreground color | -| | $shadow-color | Shadow color | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | - -
- -
- -### Indigo Theme - -#### Flat Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | -| | $shadow-color | Shadow color | - -#### Contained Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $active-foreground | Active foreground color | -| | $shadow-color | Shadow color | -| | $disabled-background | Disabled background color | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | - -#### Outlined Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | -| | $border-color | Border color | -| | $hover-border-color | Hover border color | -| | $focus-border-color | Focus border color | -| | $active-border-color | Active border color | -| | $shadow-color | Shadow color | - -#### FAB Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $disabled-background | Disabled background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $active-foreground | Active foreground color | -| | $shadow-color | Shadow color | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | - -
- -
- -
- - -> **Note:** The resulting dependent properties may vary slightly depending on the selected theme (Material, Fluent, Bootstrap, Indigo). - -To style the button you can use our type-specific theme functions: , , , and . - -Each of them will target only the buttons of that specific type. - -To get started, first import the themes module, which exports all theme functions and the `tokens()` mixin: - -```scss -@use "igniteui-angular/theming" as *; - -// IMPORTANT: Prior to Ignite UI for Angular version 13 use: -// @import '~igniteui-angular/lib/core/styles/themes/index'; -``` - -Next, create a new theme that extends the type-specific theme function for the type of button you are styling. In this example, we will use the function and pass values to the `$foreground` and the `$background` parameters, along with their respective hover and active parameters. - -Given the following markup: - -```html -
- - -
-``` - -You can create the following theme: - -```scss -$custom-contained-theme: contained-button-theme( - $background: #f9f0ff, - $foreground: #722ed1, - $hover-background: #efdbff, - $hover-foreground: #9254de, - $active-foreground: #531dab, - $active-background: #dfc2fa, -); -``` - -Take a look at the section for a complete list of available parameters for styling the contained-type buttons. - -Finally, **include** the custom theme in your application: - -```scss -.my-contained-btn { - @include tokens($custom-contained-theme); -} -``` - -With the type-specific theme functions, styling buttons is much easier. - -For and functions, you only need to provide a color value to the `$background` parameter. All other button state and text colors (if they are not provided) will then be automatically generated and applied based on that value. - -The text color is determined by the newly added function, which calculates whether black or white provides better contrast against the supplied background color. - -For and functions, the button state colors are also automatically generated and applied, but they are derived from the supplied `$foreground` parameter instead of `$background`. - -In the sample below, you can see how using the button component with customized CSS variables allows you to create a design that visually resembles the button used in the [`Ant`](https://ant.design/components/button?theme=light#button-demo-color-variant) design system. - - - - -The sample uses the [Bootstrap Light](/themes/sass/schemas#predefined-schemas) schema. - - -### Styling with Tailwind - -You can style the `button` using our custom Tailwind utility classes. Make sure to [set up Tailwind](/themes/misc/tailwind-classes) first. - -Along with the tailwind import in your global stylesheet, you can apply the desired theme utilities as follows: - -```scss -@import "tailwindcss"; -... -@use 'igniteui-theming/tailwind/utilities/material.css'; -``` - -The utility file includes both `light` and `dark` theme variants. - -- Use `light-*` classes for the light theme. -- Use `dark-*` classes for the dark theme. -- Append the component name after the prefix. Because the button has types, the classes are used like so, e.g., `light-contained-button`, `light-flat-button` `dark-outlined-button`, `dark-fab-button`, etc. - -Once applied, these classes enable dynamic theme calculations. From there, you can override the generated CSS variables using `arbitrary properties`. After the colon, provide any valid CSS color format (HEX, CSS variable, RGB, etc.). - -You can find the full list of properties in the which reflect differently in the different variants, the primary property for the `flat` and `outlined` buttons is `$foreground` and for the `contained` and `fab` buttons is `$background`. The syntax is as follows: - -```html -
- -
- - - -
-
- - - -
-
- - - -
-
- - - -
-
-``` - - -The exclamation mark(`!`) is required to ensure the utility class takes precedence. Tailwind applies styles in layers, and without marking these styles as important, they will get overridden by the component’s default theme. - - -At the end your buttons should look like this: - - - -### Custom sizing - -You can change the button height either by using the `--size` variable, targeting the `button` directly: - -```scss -button { - --size: 50px; -} -``` - -Or you can use the universal `--ig-button-size` variable to target all instances: - -```html -
- - -
-``` - -```scss -.my-app { - --ig-button-size: 50px; -} -``` - -You can also use one of the predefined sizes, assigning it to the `--ig-size` variable. The available values for `--ig-size` are `--ig-size-small`, `--ig-size-medium`, and `--ig-size-large`: - -```scss -button { - --ig-size: var(--ig-size-large); -} -``` - -Learn more about it in the [Size](/display-density) article. - -
- -## API References -
-- -- -- -- -- -## Additional Resources - -
- -Our community is active and always welcoming to new ideas. - -- [Ignite UI for Angular **Forums**](https://www.infragistics.com/community/forums/f/ignite-ui-for-angular) -- [Ignite UI for Angular **GitHub**](https://github.com/IgniteUI/igniteui-angular) diff --git a/docs/angular/src/content/en/components/chat.mdx b/docs/angular/src/content/en/components/chat.mdx index d19dab5073..979286aef8 100644 --- a/docs/angular/src/content/en/components/chat.mdx +++ b/docs/angular/src/content/en/components/chat.mdx @@ -85,13 +85,27 @@ The Chat component exposes several key properties that let you control its state | Name | Description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `messages` | Array of messages (`IgcChatMessage[]`) displayed in the chat. You can bind to this to control which messages are shown. | +| `messages` | Bidirectional array of messages (`IgcChatMessage[]`) displayed in the chat. The Chat updates the supplied collection when the user sends a message. | | `draftMessage` | The current unsent message, represented as an object containing `text` and optional `attachments`. This is useful for saving or restoring message drafts. | | `options` | Chat configuration () such as current user ID, input placeholders, accepted file types, quick reply suggestions and typing behavior. | | `templates` | Custom Angular templates () for message content, input, attachments, and other parts of the chat UI. | These properties make it straightforward to synchronize the Chat’s UI with your application’s state and backend. +#### Bidirectional Messages Collection + +The `messages` collection is bidirectional: the application provides the messages to display, and the Chat updates the original collection as the conversation continues. After the user sends a message, code holding a reference to the collection can access the newly created message. This is an in-place update to the collection rather than Angular two-way binding with `[(messages)]`. + +The `messageCreated` event is a notification for persistence or other side effects. Do not append the created message to the collection again. + +If the original collection must remain unchanged, pass the Chat a shallow copy: + +```ts +public messages = [...this.originalMessages]; +``` + +Existing message objects are still shared. Create a new instance of each message when building the copied collection if those objects must also remain independent. + ### Attachments Modern conversations are rarely limited to text alone. The Chat component includes built-in support for file attachments, allowing users to share images, documents, and other files. By default, the input area includes an attachment button. You can control which file types are allowed by setting the `acceptedFiles` property: diff --git a/docs/angular/src/content/en/components/combo.mdx b/docs/angular/src/content/en/components/combo.mdx index 86f9a31c4d..7f127f9b65 100644 --- a/docs/angular/src/content/en/components/combo.mdx +++ b/docs/angular/src/content/en/components/combo.mdx @@ -429,7 +429,7 @@ At the end your combo should look like this: - When the combobox is bound to a remote service and there is a predefined selection, its input will remain blank until the requested data is loaded. -The combobox uses `igxForOf` directive internally hence all `igxForOf` limitations are valid for the combobox. For more details see [`igxForOf Known Issues`](/for-of#known-limitations) section. +The combobox uses the [Virtual Scroll](./layouts/virtual-scroll.mdx) component internally to virtualize its list, hence all Virtual Scroll limitations are valid for the combobox. For more details see the [Virtual Scroll Known Limitations](./layouts/virtual-scroll.mdx#known-limitations) section. ## API References diff --git a/docs/angular/src/content/en/components/dialog.mdx b/docs/angular/src/content/en/components/dialog.mdx index 65dbe41167..b564ded9e8 100644 --- a/docs/angular/src/content/en/components/dialog.mdx +++ b/docs/angular/src/content/en/components/dialog.mdx @@ -294,7 +294,7 @@ $my-dialog-theme: dialog-theme( ``` -In order to style any additional components that are used as part of the dialog window's content (such as the [`IgxButton`](/button)), an additional theme should be created that is specific to the respective component and is placed under the dialog window's scope only (so it does not affect the rest of the application). +In order to style any additional components that are used as part of the dialog window's content (such as the [`IgxButton`](./inputs/button.mdx)), an additional theme should be created that is specific to the respective component and is placed under the dialog window's scope only (so it does not affect the rest of the application). ```scss diff --git a/docs/angular/src/content/en/components/drop-down-virtual.mdx b/docs/angular/src/content/en/components/drop-down-virtual.mdx index 093eba6242..081464e004 100644 --- a/docs/angular/src/content/en/components/drop-down-virtual.mdx +++ b/docs/angular/src/content/en/components/drop-down-virtual.mdx @@ -4,7 +4,7 @@ description: Use Ignite UI for Angular Virtualized Drop Down to display a very l keywords: Ignite UI for Angular, UI controls, Angular widgets, web widgets, UI widgets, Angular, Native Angular Components Suite, Native Angular Controls, Native Angular Components Library, Angular Drop Down components, Angular Drop Down controls, Angular Control Large Item List, Angular Control Singe Selection license: MIT llms: - description: "The Ignite UI for Angular Drop Down component can fully integrate with the IgxForOf directive in order to display a very large list of items for its selection." + description: "The Ignite UI for Angular Drop Down component can host the Virtual Scroll component in order to display a very large list of items for its selection." --- import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; @@ -13,69 +13,64 @@ import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; # Virtual Drop Down -The Ignite UI for Angular Drop Down component can fully integrate with the [`IgxForOf`](/for-of) directive in order to display a very large list of items for its selection. +The Ignite UI for Angular Drop Down component can host the [Virtual Scroll](./layouts/virtual-scroll.mdx) component in order to display a very large list of items for its selection. Only the items in the drop-down's viewport are rendered, while selection and keyboard navigation work over the whole list. ## Angular Virtual Drop Down Example -
- ## Usage ### First Steps -In order to configure the drop-down to display a list of virtual items, you need to fulfill some prerequisites. -First, we need to import the `IgxForOfModule` in the module of the component that will declare our drop-down. +Import the drop-down together with the and the `IgxVirtualItemDirective`, which marks the template of a list item: ```typescript -// app.module.ts -import { IgxForOfModule } from 'igniteui-angular/directives'; -// import { IgxForOfModule } from '@infragistics/igniteui-angular'; for licensed package +// drop-down-virtual.component.ts +import { Component } from '@angular/core'; +import { IgxButtonDirective, IgxToggleActionDirective } from 'igniteui-angular/directives'; +import { IgxDropDownComponent, IgxDropDownItemComponent, IgxDropDownItemNavigationDirective } from 'igniteui-angular/drop-down'; +import { IgxVirtualItemDirective, IgxVirtualScrollComponent } from 'igniteui-angular/virtual-scroll'; +// import { IgxVirtualItemDirective, IgxVirtualScrollComponent } from '@infragistics/igniteui-angular'; for licensed package -@NgModule({ +@Component({ + selector: 'app-drop-down-virtual', + templateUrl: './drop-down-virtual.component.html', + styleUrls: ['./drop-down-virtual.component.scss'], imports: [ - ... - IgxForOfModule + IgxButtonDirective, IgxToggleActionDirective, IgxDropDownItemNavigationDirective, + IgxDropDownComponent, IgxDropDownItemComponent, + IgxVirtualScrollComponent, IgxVirtualItemDirective ] }) -export class AppModule {} +export class DropDownVirtualComponent { } ``` ### Template Configuration -Next, we need to create the drop-down component's template, looping through the data using instead of `*ngFor`. The `*igxFor` directive needs some additional configuration in order to properly display all of the items: +Next, place an `igx-virtual-scroll` inside the drop-down and render each item with an `ng-template` marked with `igxVirtualItem`. The drop-down detects the projected virtual scroll and uses it for scrolling, keyboard navigation, and selection: ```html -{/* drop-down-virtual.component.html */} - - + + + + {{ item.name }} + + +
Selected Model: {{ dropdown.selectedItem?.value.name }}
``` -The additional parameters passed to the `*igxFor` directive are: +The inputs of `igx-virtual-scroll` used here are: -- `index` - captures the index of the current item in the data set -- `scrollOrientation` - should always be `'vertical'` -- `containerSize` - the size of the virtualized container (in `px`). This needs to be enforced on the wrapping `
` as well -- `itemSize` - the size of the items that will be displayed (in `px`) +- `data` - the whole list of items. It is compared by reference, so assign a new array to change it. +- `estimatedItemSize` - the height of an item (in `px`) before it is rendered and measured. Set it to the real height of the drop-down items, so that the scrollbar and keyboard navigation are accurate from the start. In order to assure uniqueness of the items, pass `item` inside of the input and `index` inside of the input of the `igx-drop-down-item`. To preserve selection while scrolling, the drop-down item needs to have a reference to the data items it is bound to. @@ -92,14 +87,13 @@ When the drop-down uses virtualized items, the type of input to the loaded page, and load the next page from the range that the output reports. The list is as long as the whole remote collection, so the scrollbar spans every item, while only the loaded page is in memory. ### Template -The drop-down template does not need to change much compared to the previous example - we still need to specify a wrapping div, style it accordingly and write out the complete configuration for the `*igxFor`. Since we'll be getting our data from a remote source, we need to specify that our data will be an observable and pass it through Angular's `async` pipe: +The template differs from the previous example only in the data binding: `dataWindow` takes the place of `data`, and `stateChange` requests the pages. The `index` template variable is the index of the item in the whole remote collection: ```html - + + + + {{ item.ProductName }} + + + ``` -### Handling chunk load - -As you can see, the template is almost identical to the one in the previous example. In this remote data scenario, the code behind will do most of the heavy lifting. +### Loading pages -First, we need to define a remote service for fetching data: +First, define a remote service that returns a page of the collection together with the total number of records: ```typescript // remote.service.ts import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { IForOfState } from 'igniteui-angular/directives'; -// import { IForOfState } from '@infragistics/igniteui-angular'; for licensed package -import { BehaviorSubject, Observable } from 'rxjs'; +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; @Injectable() export class RemoteService { - public remoteData: Observable; - private _remoteData: BehaviorSubject; - - constructor(private http: HttpClient) { - this._remoteData = new BehaviorSubject([]); - this.remoteData = this._remoteData.asObservable(); + private http = inject(HttpClient); + + // Assuming that the API service is RESTful and can take the following: + // skip: start index of the data that we fetch + // count: number of records we fetch + public getPage(skip: number, count: number): Observable<{ value: any[]; '@odata.count': number }> { + return this.http.get<{ value: any[]; '@odata.count': number }>( + `https://dummy.db/dummyEndpoint?$skip=${skip}&$top=${count}&$count=true` + ); } - - public getData(data?: IForOfState, cb?: (any) => void): any { - // Assuming that the API service is RESTful and can take the following: - // skip: start index of the data that we fecth - // count: number of records we fetch - this.http.get(`https://dummy.db/dummyEndpoint?skip=${data.startIndex}&count=${data.chunkSize}`).subscribe((data) => { - // emit the values through the _remoteData subject - this._remoteData.next(data); - }) } ``` -The service exposes an `Observable` under `remoteData`. We will inject our service and bind to that property in our remote drop-down component: +In the component, keep the loaded page in a signal of type `VirtualDataWindow`. Load the first page on initialization, and a new one whenever `stateChange` reports a range that the loaded page does not cover. Cancel the previous request, so a slow response cannot replace a newer page: ```typescript -// remote-drop-down.component.ts +// drop-down-remote.component.ts +import { Component, OnDestroy, OnInit, inject, signal } from '@angular/core'; +import { VirtualDataWindow, VirtualScrollState } from 'igniteui-angular/virtual-scroll'; +import { Subscription } from 'rxjs'; + +/** Extra records requested on each side of the range the viewport wants. */ +const BUFFER = 10; + @Component({ providers: [RemoteService], selector: 'app-drop-down-remote', templateUrl: './drop-down-remote.component.html', - styleUrls: ['./drop-down-remote.component.scss'] + styleUrls: ['./drop-down-remote.component.scss'], + imports: [/* the same imports as in the local example */] }) export class DropDownRemoteComponent implements OnInit, OnDestroy { - @ViewChild(IgxForOfDirective, { read: IgxForOfDirective }) - public remoteForDir: IgxForOfDirective; - @ViewChild('remoteDropDown', { read: IgxDropDownComponent }) - public remoteDropDown: IgxDropDownComponent; - public itemHeight = 48; - public itemsMaxHeight = 480; - public prevRequest: Subscription; - public rData: any; - - private destroy$ = new Subject(); - constructor(private remoteService: RemoteService) { } - - public ngAfterViewInit() { - const initialState = { startIndex: 0, chunkSize: Math.ceil(this.itemsMaxHeight / this.itemHeight) } - this.remoteService.getData(initialState, (data) => { - this.remoteForDir.totalItemCount = data['@odata.count']; - }); - // Subscribe to igxForOf.chunkPreload and load new data from service - this.remoteForDir.chunkPreload.pipe(takeUntil(this.destroy$)).subscribe((data) => { - this.dataLoading(data); - }); + private remoteService = inject(RemoteService); + public itemHeight = 40; + public readonly page = signal>({ items: [], startIndex: 0, totalCount: 0 }); + private pending?: Subscription; + + public ngOnInit() { + this.loadPage(0, 2 * BUFFER); } - public dataLoading(evt) { - if (this.prevRequest) { - this.prevRequest.unsubscribe(); + public onStateChange(state: VirtualScrollState) { + const page = this.page(); + if (state.startIndex >= page.startIndex && state.endIndex < page.startIndex + page.items.length) { + return; // The loaded page already covers the range. } - this.prevRequest = this.remoteService.getData( - evt, - (data) => { - this.remoteForDir.totalItemCount = data['@odata.count']; - }); + const startIndex = Math.max(0, state.startIndex - BUFFER); + this.loadPage(startIndex, state.endIndex - startIndex + 1 + BUFFER); } - public ngOnInit() { - this.rData = this.remoteService.remoteData; + public ngOnDestroy() { + this.pending?.unsubscribe(); } - public ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); + private loadPage(startIndex: number, count: number) { + this.pending?.unsubscribe(); + this.pending = this.remoteService.getPage(startIndex, count).subscribe(data => { + this.page.set({ items: data.value, startIndex, totalCount: data['@odata.count'] }); + }); } } ``` -Inside of the `ngAfterViewInit` hook, we call to get data for the initial state and subscribe to the `igxForOf` directive's emitter. This subscription will be responsible for fetching data every time the loaded chunk changes. We use `pipe(takeUntil(this.destroy$))` so we can easily unsubscribe from the emitter on component destroy. +When the drop-down navigates to an item that is not loaded yet, for example with the `End` key, the virtual scroll scrolls to it, `stateChange` reports the new range, and the page that contains the item is loaded. ### Remote Virtualization - Demo The result of the above configuration is a drop-down that dynamically loads the data it should display, depending on the scrollbar's state: - - -
+ ## Notes and Limitations -Using the drop-down with a virtualized list of items enforces some limitations. Please, be aware of the following when trying to set up a drop-down list using `*igxFor`: +Using the drop-down with a virtualized list of items enforces some limitations. Please, be aware of the following when trying to set up a drop-down list with `igx-virtual-scroll`: -- The drop-down items that are being looped need to be passed in a wrapping element (e.g. `
`) which has the following css: `overflow: hidden` and `height` equal to `containerSize` in `px` +- The `igx-virtual-scroll` element must have a fixed `height`, because it is the scroll container of the list. - `` cannot be used for grouping items when the list is virtualized. Use the `isHeader` property instead - The `items` accessor will return only the list of non-header drop-down items that are currently in the virtualized view. - is of type `{ value: any, index: number }` -- The object emitted by changes to `const emittedEvent: { newSelection: { value: any, index: number }, oldSelection: { value: any, index: number }, cancel: boolean, }` +- The object emitted by changes to `const emittedEvent: { newSelection: { value: any, index: number }, oldSelection: { value: any, index: number }, cancel: boolean, }` - `dropdown.setSelectedItem` should be called with the **item's index in the data set** - setting the drop-down item's `[selected]` input will **not** mark the item in the drop-down selection +The drop-down also works with a projected [`*igxFor`](./for-of.mdx) directive, as in earlier versions. The directive is deprecated in favor of the Virtual Scroll, so use `igx-virtual-scroll` for new drop-downs. + ## API References -- +- - diff --git a/docs/angular/src/content/en/components/expansion-panel.mdx b/docs/angular/src/content/en/components/expansion-panel.mdx index 87c61acac8..4d49687e13 100644 --- a/docs/angular/src/content/en/components/expansion-panel.mdx +++ b/docs/angular/src/content/en/components/expansion-panel.mdx @@ -417,7 +417,7 @@ You can see the results below: ## Multiple panel scenario -See the [igxAccordion topic](/accordion) +See the [igxAccordion topic](/layouts/accordion) ## API Reference diff --git a/docs/angular/src/content/en/components/for-of.mdx b/docs/angular/src/content/en/components/for-of.mdx index 7c193487df..5fc1f79ea1 100644 --- a/docs/angular/src/content/en/components/for-of.mdx +++ b/docs/angular/src/content/en/components/for-of.mdx @@ -4,14 +4,19 @@ description: Ignite UI for Angular now exposes a virtual igxFor directive simila keywords: Angular Virtual ForOf Directive, Native Angular Components Suite, Angular UI Components, Native Angular Components Library, Virtualization, Performance, Virtual directive, Angular Virtual For license: MIT llms: - description: "The Ignite UI for Angular igxForOf directive is an alternative to ngForOf for templating large amounts of data." + description: "The Ignite UI for Angular igxForOf directive is a deprecated alternative to ngForOf for templating large amounts of data; the Virtual Scroll component replaces it." --- +import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; # Angular Virtual ForOf Directive Overview + +The `igxForOf` directive is deprecated in favor of the [Virtual Scroll](./layouts/virtual-scroll.mdx) component. Existing lists keep working, but use the Virtual Scroll for new lists that virtualize a single axis: it measures items at runtime, so items can have different sizes, and it creates its own scroll container. To migrate an existing list, see [How do I replace an igxForOf list with the Virtual Scroll?](./layouts/virtual-scroll.mdx#how-do-i-replace-an-igxforof-list-with-the-virtual-scroll). + +
The Ignite UI for Angular igxForOf directive is an alternative to ngForOf for templating large amounts of data. It uses virtualization behind the scenes to optimize DOM rendering and memory consumption.
diff --git a/docs/angular/src/content/en/components/general/cli/component-templates.mdx b/docs/angular/src/content/en/components/general/cli/component-templates.mdx index 1b4d9466c2..6377475146 100644 --- a/docs/angular/src/content/en/components/general/cli/component-templates.mdx +++ b/docs/angular/src/content/en/components/general/cli/component-templates.mdx @@ -44,7 +44,7 @@ These templates generate components into an existing Angular workspace only. The | carousel | Ignite UI Schematics collection:
ng g @igniteui/angular-schematics:c carousel newCarousel
Ignite UI CLI:
ig add carousel newCarousel
Basic IgxCarousel.
| [IgxCarousel](../../carousel.mdx) cycling through a series of images. | | tabs | Ignite UI Schematics collection:
ng g @igniteui/angular-schematics:c tabs newTabs
Ignite UI CLI:
ig add tabs newTabs
Basic IgxTabs.
| [IgxTabs](../../tabs.mdx) component that includes three customized tab-groups. | | bottom-nav | Ignite UI Schematics collection:
ng g @igniteui/angular-schematics:c bottom-nav newBottomNav
Ignite UI CLI:
ig add bottom-nav newBottomNav
Three item bottom-nav template.
| Three item bottom [navbar](../../navbar.mdx) template. | -| accordion | Ignite UI Schematics collection:
ng g @igniteui/angular-schematics:c accordion newAccordion
Ignite UI CLI:
ig add accordion newAccordion
Basic IgxAccordion sample.
| [IgxAccordion](../../accordion.mdx) with multiple collapsible panels in a single container. | +| accordion | Ignite UI Schematics collection:
ng g @igniteui/angular-schematics:c accordion newAccordion
Ignite UI CLI:
ig add accordion newAccordion
Basic IgxAccordion sample.
| [IgxAccordion](../../layouts/accordion.mdx) with multiple collapsible panels in a single container. | | stepper | Ignite UI Schematics collection:
ng g @igniteui/angular-schematics:c stepper newStepper
Ignite UI CLI:
ig add stepper newStepper
Basic IgxStepper sample.
| [IgxStepper](../../stepper.mdx) visualizing content as a process with successive steps. | | Data Entry & Display | | | | chip | Ignite UI Schematics collection:
ng g @igniteui/angular-schematics:c chip newChip
Ignite UI CLI:
ig add chip newChip
Basic IgxChip.
| [IgxChip](../../chip.mdx) components inside igx-chips-area. | diff --git a/docs/angular/src/content/en/components/general/cli/step-by-step-guide-using-angular-schematics.mdx b/docs/angular/src/content/en/components/general/cli/step-by-step-guide-using-angular-schematics.mdx index b45d6134fd..dbac01d08c 100644 --- a/docs/angular/src/content/en/components/general/cli/step-by-step-guide-using-angular-schematics.mdx +++ b/docs/angular/src/content/en/components/general/cli/step-by-step-guide-using-angular-schematics.mdx @@ -79,7 +79,7 @@ If you select **side-nav** or **side-nav-mini**, the wizard will prompt you with Two theme options are available: - **default** - includes a pre-compiled CSS file (`igniteui-angular.css`) with the default Ignite UI for Angular Material-based theme in `angular.json` -- **custom** - generates a color palette and theme configuration using the [Theming API](../../themes.mdx) in `app/styles.scss`, ready for customization +- **custom** - generates a color palette and theme configuration using the [Theming API](../../themes/sass/index.mdx) in `app/styles.scss`, ready for customization Step by step prompt: choose default or custom theme diff --git a/docs/angular/src/content/en/components/general/cli/step-by-step-guide-using-cli.mdx b/docs/angular/src/content/en/components/general/cli/step-by-step-guide-using-cli.mdx index 66c4165524..9db761e032 100644 --- a/docs/angular/src/content/en/components/general/cli/step-by-step-guide-using-cli.mdx +++ b/docs/angular/src/content/en/components/general/cli/step-by-step-guide-using-cli.mdx @@ -67,7 +67,7 @@ If you select **Side Navigation** or **Side Navigation Mini**, the wizard will p Step by step auth question prompt -The next step is to choose a theme for your application. Selecting the default option includes a pre-compiled CSS file (`igniteui-angular.css`) with the default Ignite UI for Angular theme in your project's `angular.json`. The custom option generates a color palette and theme configuration using the [Theming API](../../themes.mdx) in `app/styles.scss`. +The next step is to choose a theme for your application. Selecting the default option includes a pre-compiled CSS file (`igniteui-angular.css`) with the default Ignite UI for Angular theme in your project's `angular.json`. The custom option generates a color palette and theme configuration using the [Theming API](../../themes/sass/index.mdx) in `app/styles.scss`. Step by step new project theme selection diff --git a/docs/angular/src/content/en/components/general/getting-started.mdx b/docs/angular/src/content/en/components/general/getting-started.mdx index cc324d0c46..40a8286a1c 100644 --- a/docs/angular/src/content/en/components/general/getting-started.mdx +++ b/docs/angular/src/content/en/components/general/getting-started.mdx @@ -88,7 +88,7 @@ If you already have an Angular project or prefer to work entirely within the Ang ng new --style=scss ``` -SCSS is recommended because the [Ignite UI for Angular Theming Library](../themes.mdx) is built on it and `ng add` configures the default theme automatically. Then add Ignite UI for Angular: +SCSS is recommended because the [Ignite UI for Angular Theming Library](../themes/sass/index.mdx) is built on it and `ng add` configures the default theme automatically. Then add Ignite UI for Angular: ```cmd ng add igniteui-angular diff --git a/docs/angular/src/content/en/components/hierarchicalgrid/hierarchical-grid.mdx b/docs/angular/src/content/en/components/hierarchicalgrid/hierarchical-grid.mdx index 96585e739b..fb5e67926a 100644 --- a/docs/angular/src/content/en/components/hierarchicalgrid/hierarchical-grid.mdx +++ b/docs/angular/src/content/en/components/hierarchicalgrid/hierarchical-grid.mdx @@ -368,7 +368,7 @@ This way, due to Angular's [`ViewEncapsulation`](https://angular.io/api/core/Com ### Demo - + There are also additional parameters in the that you can use if you want more specific customizations. diff --git a/docs/angular/src/content/en/components/layouts/avatar.mdx b/docs/angular/src/content/en/components/layouts/avatar.mdx deleted file mode 100644 index d0e1cd89bb..0000000000 --- a/docs/angular/src/content/en/components/layouts/avatar.mdx +++ /dev/null @@ -1,296 +0,0 @@ ---- -title: "Angular Avatar Component | Layouts | Infragistics" -description: "Use the Angular Avatar component to represent users, entities, or objects with images, initials, icons, or custom content." -keywords: "Angular Avatar, avatar component, profile image, initials, Ignite UI for Angular, Infragistics" -last_updated: "2026-07-29" -license: MIT -mentionedTypes: ["Avatar", "Badge", "Icon"] -relatedComponents: ["Badge"] -llms: - description: "The Ignite UI for Angular Avatar topic shows how to render user, entity, or object identity with images, initials, icons, custom content, shape, size, styling, and accessibility guidance." ---- -import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; -import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; -import Anatomy from 'igniteui-astro-components/components/mdx/Anatomy.astro'; -import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; -import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; -import { Image } from 'astro:assets'; -import avatarAnatomy from '@xplat-images/anatomy-content-light/avatar-lt-a.png'; -import avatarDo from '@xplat-images/avatar/avatar_do1.png'; -import avatarDo2x from '@xplat-images/avatar/avatar_do1@2x.png'; -import avatarDoNot from '@xplat-images/avatar/avatar_do_not1.png'; -import avatarDoNot2x from '@xplat-images/avatar/avatar_dont1@2x.png'; - -# Avatar Component - -The Ignite UI for Angular Avatar represents a user, entity, or object with an image, initials, or custom content. - -Use the avatar to provide a compact visual identity in lists, cards, profile menus, and activity feeds. - -## Live Demo - - - -## Anatomy - -The avatar is a single host element that applies image semantics and renders one of the supported content patterns. - - - - - -1. Image container: Displays image content type.
-2. Icon container: Displays icon content type.
-3. Initials container: Displays text content type.
- -```text -igx-avatar[role="img"] // host - exposes the avatar -└─ one of, by priority: - ├─ div.igx-avatar__image // `src` set - image painted as a background - ├─ igx-icon // `icon` set - ├─ span // `initials` set - first two characters - └─ ng-content // custom projected content -``` - -## Getting Started - -Import the Angular avatar component before you render ``. If you have not set up Ignite UI for Angular yet, complete the shared [Getting Started](../general/getting-started.mdx) topic first. - -```ts -import { IgxAvatarComponent } from 'igniteui-angular/avatar'; -``` - -## Usage - -Render an avatar with an image source, initials, or custom content in the default slot. - -### Variants - -Set only the content source you intend to show. The Angular avatar renders `src` first, then `icon`, then `initials`, and falls back to projected custom content when none of those inputs are set. - -```html - - - - - -``` - - - -### Shape - -Set to `square`, `rounded`, or `circle`. - -```html - -``` - - - -### Size - -Set `--ig-size` to one of the shared size tokens when you need a preset avatar size. - -```html - -``` - - - -### Do/Don't - -**When to use:** Use the avatar when a UI needs a small representation of a person, organization, object, or account, such as a profile image, initials, or an icon. Keep a consistent avatar strategy within the same UI region so repeated identities are easy to scan. - -**When not to use:** Use the [Badge](../inputs/badge.mdx) component when you need to show a count, status, or notification indicator instead of representing an entity. Badges can also decorate avatars when both identity and status need to appear together. - -
- - - - - - - - - - - - - -
DoDon't
Angular Avatar do guidanceAngular Avatar don't guidance
-
- -## Properties - -The avatar exposes a small set of inputs for its content and shape. - -| Name | Type | Default | Description | -| -- | -- | -- | -- | -| | `string` | n/a | Sets the icon rendered by the avatar. | -| | `string` | n/a | Sets text initials rendered by the avatar. | -| | `"square" \| "rounded" \| "circle"` | `"square"` | Sets the avatar shape. | -| | `"small" \| "medium" \| "large"` | `"small"` | Sets the avatar size. | -| | `string` | n/a | Sets the image source URL. | - -## Styling - - - -The avatar appearance is controlled through theme variables and platform-specific styling hooks. - -Use the avatar CSS variables for token-level changes and Angular host classes when you need to target a specific rendered type or shape. - -| Variable | What it changes | -| -- | -- | -| `--ig-avatar-background` | Avatar background color. | -| `--ig-avatar-color` | Text and initials color. | -| `--ig-avatar-icon-color` | Icon color. | -| `--ig-avatar-border-radius` | Border radius used by rounded avatars. | -| `--ig-avatar-size` | Avatar width and height. | -| `--ig-size` | Shared component size token used to derive preset avatar sizes. | - -| Selector | Description | -| -- | -- | -| `igx-avatar` | The avatar host element. | -| `.igx-avatar--rounded` | Applied when `shape` is `rounded`. | -| `.igx-avatar--circle` | Applied when `shape` is `circle`. | -| `.igx-avatar--image` | Applied when the avatar renders an image. | -| `.igx-avatar--icon` | Applied when the avatar renders an icon. | -| `.igx-avatar--initials` | Applied when the avatar renders initials. | -| `.igx-avatar__image` | The image avatar element. | - -### Sass Theming - -Use the function when your application customizes Ignite UI themes through Sass. - -```scss -@use "igniteui-angular/theming" as *; - -$custom-avatar-theme: avatar-theme( - $background: #72da67, - $border-radius: 16px, - $size: 3rem -); - -:root { - @include tokens($custom-avatar-theme); -} -``` - -### CSS Variables - -Set component CSS variables directly when you need local styling without a Sass build step. - -```css -igx-avatar { - --ig-avatar-background: var(--ig-success-500); - --ig-avatar-color: var(--ig-success-500-contrast); - --ig-avatar-border-radius: 20px; -} -``` - -### Styling with Tailwind - -Use the Angular Tailwind utility syntax when your application styles Ignite UI components through Tailwind classes. - - - -## Accessibility - -The avatar is a non-interactive identity visual with accessible image semantics. - -### Keyboard Interaction - -The avatar does not receive focus and has no keyboard interaction. - -| Key | Action | -| -- | -- | -| n/a | The avatar is not keyboard interactive. | - -### Screen Readers / ARIA - -The avatar initializes with image semantics and a default accessible label of `avatar`. - -- Use surrounding text to identify the represented person, entity, or object when an image avatar conveys identity. -- Treat decorative avatars as redundant when adjacent text already identifies the same entity. - -### Accessibility Compliance - -Infragistics documents Ignite UI for Angular accessibility support for Section 508 and WCAG 2.1 guideline areas in the [Accessibility Compliance](../interactivity/accessibility-compliance.mdx) topic. - -| Criterion | How the component complies | -| -- | -- | -| [1.1.1 Non-text Content](https://www.w3.org/WAI/WCAG22/Understanding/non-text-content) | The avatar has an accessible label and can be paired with surrounding text that identifies the represented entity. | -| [4.1.2 Name, Role, Value](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value) | The component initializes with `role="img"` and a default accessible label. | - -Your responsibilities: - -- Keep sufficient contrast between the avatar background and text or icon color when overriding styles. -- Avoid duplicating the same identity announcement when adjacent text already names the person or entity. - -- Make sure nearby text identifies the represented entity when the avatar image conveys identity. - -## Troubleshooting - -Use this section to check boundaries and common decisions before treating Avatar as an interactive or status component. - -### Known Limitations - -The avatar is a visual identity primitive and does not add interaction, status, or notification behavior by itself. - -- Use an interactive container, such as a button or list item, when the represented entity must be clickable. -- Use a badge with the avatar when you need to show status, counts, or notification indicators. - -## API References - -Use these API references for the complete avatar API surface. - - - -## Dependencies - -The Sass styling workflow uses the and APIs. - -## Additional Resources - -Use these resources for support and related Ignite UI documentation. - -- [Ignite UI for Angular **Forums**](https://www.infragistics.com/community/forums/f/ignite-ui-for-angular) -- [Ignite UI for Angular **GitHub**](https://github.com/IgniteUI/igniteui-angular) - -## Related Components - -Use these related components when identity needs to be combined with status, actions, or richer layout. - -- [Badge](../inputs/badge.mdx) - Use Badge to show counts, status, or notification indicators. Badge can decorate Avatar when the UI needs both identity and status. - -## FAQ - - - - Use Avatar when the UI needs to represent a person, account, organization, or object. Use Badge when the UI needs to show a count, status, or notification indicator. - - - - No. Avatar is non-interactive and does not receive focus by itself. Put it inside an interactive component when the represented entity needs an action. - - - - Provide meaningful alternative text when the avatar image identifies a specific entity. Avoid repeating the same identity when adjacent text already names that entity. - - diff --git a/docs/angular/src/content/en/components/list.mdx b/docs/angular/src/content/en/components/list.mdx index bbc09c7109..6c51853f19 100644 --- a/docs/angular/src/content/en/components/list.mdx +++ b/docs/angular/src/content/en/components/list.mdx @@ -300,7 +300,7 @@ toggleFavorite(item: IgxListItem) { } ``` -Let's also allow the user to choose the size of the list by using the `--ig-size` CSS custom property. We will do this by importing the `IgxButtonGroupModule` and using the [**IgxButtonGroup**](/components/inputs/button-group) to display all size values. This way whenever one gets selected, we will update the **size** of the list. +Let's also allow the user to choose the size of the list by using the `--ig-size` CSS custom property. We will do this by importing the `IgxButtonGroupModule` and using the [**IgxButtonGroup**](/inputs/button-group) to display all size values. This way whenever one gets selected, we will update the **size** of the list. ```typescript // app.module.ts diff --git a/docs/angular/src/content/en/components/pivotgrid/pivot-grid.mdx b/docs/angular/src/content/en/components/pivotgrid/pivot-grid.mdx index 5a74dd2461..1e1aa67422 100644 --- a/docs/angular/src/content/en/components/pivotgrid/pivot-grid.mdx +++ b/docs/angular/src/content/en/components/pivotgrid/pivot-grid.mdx @@ -377,7 +377,7 @@ igx-pivot-grid { ### Demo - + There are also additional parameters in the that you can use if you want more specific customizations. diff --git a/docs/angular/src/content/en/components/simple-combo.mdx b/docs/angular/src/content/en/components/simple-combo.mdx index 502659acde..049a4f7fcc 100644 --- a/docs/angular/src/content/en/components/simple-combo.mdx +++ b/docs/angular/src/content/en/components/simple-combo.mdx @@ -391,7 +391,7 @@ The default `type` of the `IgxSimpleCombo` is `box` unlike the [`IgxSelect`](/se - When the simple combobox is bound to a remote service and there is a predefined selection, its input will remain blank until the requested data is loaded. -The simple combobox uses `igxForOf` directive internally hence all `igxForOf` limitations are valid for the simple combobox. For more details see [igxForOf Known Issues](/for-of#known-limitations) section. +The simple combobox uses the [Virtual Scroll](./layouts/virtual-scroll.mdx) component internally to virtualize its list, hence all Virtual Scroll limitations are valid for the simple combobox. For more details see the [Virtual Scroll Known Limitations](./layouts/virtual-scroll.mdx#known-limitations) section. ## API References diff --git a/docs/angular/src/content/en/components/switch.mdx b/docs/angular/src/content/en/components/switch.mdx deleted file mode 100644 index 94b5957a5b..0000000000 --- a/docs/angular/src/content/en/components/switch.mdx +++ /dev/null @@ -1,325 +0,0 @@ ---- -title: Angular Switch Component – Ignite UI for Angular | Infragistics | MIT license -description: Ignite UI for Angular Switch component enables developers to use binary on/off or true/false data input functions within their applications. -keywords: Angular Switch component, Angular Switch control, Ignite UI for Angular, UI controls, Angular widgets, web widgets, UI widgets, Angular, Native Angular Components Suite, Angular UI Components, Native Angular Components Library -license: MIT -llms: - description: "The Ignite UI for Angular Switch component is a binary choice selection component that behaves similarly to the switch component in iOS." ---- - -import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; -import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; -import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; - -# Angular Switch Component Overview - -
-The Ignite UI for Angular Switch component is a binary choice selection component that behaves similarly to the switch component in iOS. -
- -## Angular Switch Example - - - -
- -## Getting Started with Ignite UI for Angular Switch - -To get started with the Ignite UI for Angular Switch component, first you need to install Ignite UI for Angular. In an existing Angular application, type the following command: - -```cmd -ng add igniteui-angular -``` - -For a complete introduction to the Ignite UI for Angular, read the [_getting started_](/general/getting-started) topic. - -The next step is to import the `IgxSwitchModule` in your **app.module.ts** file. - -```typescript -// app.module.ts - -... -import { IgxSwitchModule } from 'igniteui-angular/switch'; -// import { IgxSwitchModule } from '@infragistics/igniteui-angular'; for licensed package - -@NgModule({ - ... - imports: [..., IgxSwitchModule], - ... -}) -export class AppModule {} -``` - -Alternatively, as of `16.0.0` you can import the `IgxSwitchComponent` as a standalone dependency. - -```typescript -// home.component.ts - -import { IgxSwitchComponent } from 'igniteui-angular/switch'; -// import { IgxSwitchComponent } from '@infragistics/igniteui-angular'; for licensed package - -@Component({ - selector: 'app-home', - template: ` Simple switch `, - styleUrls: ['home.component.scss'], - standalone: true, - imports: [IgxSwitchComponent], -}) -export class HomeComponent {} -``` - -Now that you have the Ignite UI for Angular Switch module or component imported, you can start using the `igx-switch` component. - -## Using the Angular Switch - -At its core the switch component allows for toggling between on/off state. The default styling is done according to the selection controls specification in the Material Design guidelines. - -To get a simple switch as the one in the demo, add the following code inside the component template: - -```html - Simple switch -``` - -### Switch properties - -Let's enhance the code above by binding the switch properties to some data. Say, we have an array of settings objects, each having two properties - `name` and `state`. You can bind the switch component property to the underlying object state property. Analogically, you can bind the value property to name. - -```typescript -// toggle.component.ts -... -public settings = [ - { name: 'WiFi', state: false}, - { name: 'Bluetooth', state: true}, - { name: 'Device visibility', state: false} -]; -``` - -Enhance the component template by adding a switch for each setting and then binding the corresponding property: - -```html -{/*toggle.component.html*/} - - - {{ setting.name }} - -``` - -Add some styles: - -```scss -:host { - display: flex; - flex-flow: column nowrap; - padding: 16px; -} - -igx-switch { - margin-top: 24px; -} -``` - -And the final result should be something like that: - - - -### Label Positioning - -You can position the label using the switch's property: - -```html - -``` - -If the `labelPosition` is not set, the label will be positioned after the switch. - -## Styling - -### Switch Theme Property Map - -When you modify a primary property, all related dependent properties are automatically updated to reflect the change: - -
- - {/*Theme Switcher Radios and Labels*/} - - - - - - - - - -
- - {/* Material Theme Table */} -
- - | Primary Property | Dependent Property | Description | -| --- | --- | --- | -| **$track-off-color** | $thumb-off-color | Thumb color when switch is off | -| | $track-disabled-color | Track color when switch is disabled | -| **$thumb-off-color** | $track-off-color | Track color when switch is off | -| | $thumb-disabled-color | Thumb color when switch is disabled | -| **$track-on-color** | $thumb-on-color | Thumb color when switch is on | -| | $track-on-hover-color | Track color when switch is on and hovered | -| | $track-on-disabled-color | Track color when switch is on and disabled | -|**$thumb-on-color** | $track-on-color | Track color when switch is on | -| | $thumb-on-disabled-color | Thumb color when switch is on and disabled | - -
- {/* Fluent Theme Table */} -
- - | Primary Property | Dependent Property | Description | -| --- | --- | --- | -| **$thumb-off-color** | $border-color | Border color derived from thumb off color | -| | $thumb-off-hover-color | Thumb color on hover | -| **$border-color** | $thumb-off-color | Thumb off color derived from border color | -| | $border-hover-color | Border color on hover | -| | $border-disabled-color | Border color when disabled | -| **$track-off-color**| $thumb-off-color | Thumb off color derived from track off color | -| | $border-hover-color | Border color on hover | -| | $track-disabled-color | Track color when disabled | -| **$track-on-color** | $thumb-on-color | Thumb color when switch is on | -| | $thumb-on-disabled-color | The color of the thumb when the switch is on and disabled | -| | $border-on-color | The border color when the switch is on | -| | $border-on-hover-color | Border color when switch is on and hovered | -| | $track-on-hover-color | Track color when switch is on and hovered | -| | $track-on-disabled-color | Track color when on and disabled | - -
-
- - | Primary Property | Dependent Property | Description | -| --- | --- | --- | -| **$thumb-off-color** | $border-color | Border color derived from thumb off color | -| | $thumb-off-hover-color | Thumb color on hover | -| **$border-color** | $thumb-off-color | Thumb off color derived from border color | -| | $border-hover-color | Border color on hover | -| | $border-disabled-color | Border color when disabled | -| **$track-off-color**| $thumb-off-color | Thumb off color derived from track off color | -| | $border-hover-color | Border color on hover | -| | $track-disabled-color | Track color when disabled | -| **$track-on-color** | $thumb-on-color | Thumb color when switch is on | -| | $thumb-on-disabled-color | The color of the thumb when the switch is on and disabled | -| | $border-on-color | The border color when the switch is on | -| | $border-on-hover-color | Border color when switch is on and hovered | -| | $track-on-hover-color | Track color when switch is on and hovered | -| | $track-on-disabled-color | Track color when on and disabled | -| | $focus-fill-color | Fill color when switch is focused | -| **$focus-fill-color** | $focus-outline-color | Outline color derived from focus fill | -| | $focus-fill-hover-color | Focus fill color when hovered | - -
-
- - | Primary Property | Dependent Property | Description | -| --- | --- | --- | -| **$thumb-off-color** | $border-color | Border color derived from thumb off color | -| | $thumb-off-hover-color | Thumb color on hover | -| **$border-color** | $thumb-off-color | Thumb off color derived from border color | -| | $border-hover-color | Border color on hover | -| | $border-disabled-color | Border color when disabled | -| **$track-off-color**| $thumb-off-color | Thumb off color derived from track off color | -| | $border-hover-color | Border color on hover | -| | $track-disabled-color | Track color when disabled | -| **$track-on-color** | $thumb-on-color | Thumb color when switch is on | -| | $thumb-on-disabled-color | The color of the thumb when the switch is on and disabled | -| | $border-on-color | The border color when the switch is on | -| | $track-on-hover-color | Track color when switch is on and hovered | -| | $track-on-disabled-color | Track color when on and disabled | -| **$border-on-color** | $border-on-hover-color | Border color when switch is on and hovered | -| | $focus-outlined-color-focused | The focus outlined color for focused state | - -
- -
-
- -To get started with styling the switch, we need to import the `index` file, where all the theme functions and the `tokens()` mixin are exported: - -```scss -@use "igniteui-angular/theming" as *; - -// IMPORTANT: Prior to Ignite UI for Angular version 13 use: -// @import '~igniteui-angular/lib/core/styles/themes/index'; -``` - -Then, we create a new theme that extends the and by providing just two parameters - `$thumb-off-color` and `$thumb-on-color` you can get a fully styled switch, as the theme generates all the rest of the necessary colors based on these two, you can of course override any of the other parameters for a customized look: - -```scss -$custom-switch-theme: switch-theme( - $thumb-off-color: #7cadd5, - $thumb-on-color: #ecaa53, -); -``` - -Finally, **include** the custom theme in your application: - -```scss -:host { - @include tokens($custom-switch-theme); -} -``` - -In the sample below, you can see how using the switch component with customized CSS variables allows you to create a design that visually resembles the switch used in the [`SAP UI5`](https://ui5.sap.com/#/entity/sap.m.Switch/sample/sap.m.sample.Switch) design system. - - - -### Styling with Tailwind - -You can style the switch using our custom Tailwind utility classes. Make sure to [set up Tailwind](/themes/misc/tailwind-classes) first. - -Along with the tailwind import in your global stylesheet, you can apply the desired theme utilities as follows: - -```scss -@import "tailwindcss"; -... -@use 'igniteui-theming/tailwind/utilities/material.css'; -``` - -The utility file includes both `light` and `dark` theme variants. - -- Use `light-*` classes for the light theme. -- Use `dark-*` classes for the dark theme. -- Append the component name after the prefix, e.g., `light-switch`, `dark-switch`. - -Once applied, these classes enable dynamic theme calculations. From there, you can override the generated CSS variables using `arbitrary properties`. After the colon, provide any valid CSS color format (HEX, CSS variable, RGB, etc.). - -You can find the full list of properties in the . The syntax is as follows: - -```html - - ... - -``` - - -The exclamation mark(`!`) is required to ensure the utility class takes precedence. Tailwind applies styles in layers, and without marking these styles as important, they will get overridden by the component’s default theme. - - -At the end your switch should look like this: - - - -
- -## API References -
-- -- -## Theming Dependencies - -- - -## Additional Resources - -
- -Our community is active and always welcoming to new ideas. - -- [Ignite UI for Angular **Forums**](https://www.infragistics.com/community/forums/f/ignite-ui-for-angular) -- [Ignite UI for Angular **GitHub**](https://github.com/IgniteUI/igniteui-angular) diff --git a/docs/angular/src/content/en/components/themes.mdx b/docs/angular/src/content/en/components/themes.mdx deleted file mode 100644 index da4dccf952..0000000000 --- a/docs/angular/src/content/en/components/themes.mdx +++ /dev/null @@ -1,169 +0,0 @@ ---- -title: Theming Component - Native Angular | Ignite UI for Angular | MIT license -description: The Ignite UI for Angular Theming component was developed through SASS with a low-difficulty API that offers restyling of one component, multiple components, or the entire suite. -keywords: Ignite UI for Angular, UI controls, Angular widgets, web widgets, UI widgets, Angular, Native Angular Components Suite, Native Angular Controls, Native Angular Components Library, Native Angular Components, Angular Theming Component, Angular Theming -license: MIT -llms: - description: "With only a few lines of code, users can easily change the theming for their components." ---- - -import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; - -# Themes - -With only a few lines of code, users can easily change the theming for their components. Being developed through SASS, the API use is low-difficulty and offers restyling of one component, multiple components, or the entire suite. - -## The Essence of a Theme - -Since **IgniteUI for Angular** bases its component designs on the **
Material Design Guidelines**, we try to get as close as possible to colors, sizes, and overall look and feel of our components to those created by Google. - -Our approach to theming is based around several simple concepts. - -### Palettes - -The first concept is the one of palettes of colors. As in any visual tool, colors are the main difference between one application and another. The Material Design Guidelines prescribe predefined palettes of colors that range in hue and lightness for a base color. There's a good reason for that. They really want to ensure good color matching and contrast between the background colors and the foreground text colors. This is great, but limiting at the same time. If you wanted to have your own custom palette that matches your branding, you would be out of luck. We recognize this is a problem, so we invented an algorithm that would generate Material-like palettes from base colors you provide. Even more, we also generate contrast text colors for each hue in the palette. - -### Themes - -The second concept is the one of themes. Palettes, wouldn't do much good if they weren't used by a theme. So we have themes for each component, and a global one, that styles the entire application and every component in it. You simply pass your generated palette to the global theme, we take care of the rest. You can, of course, style each component individually to your liking. We will take a closer look at how to do that later in this article. - -### Typography - -The last concept revolves around typography. Although we have a default typeface choice, we really want to give you the power to style your application in every single way. Typography is such an important part of that. We provide a method for changing the font family, the sizes and weights for headings, subheadings and paragraph texts in your app. - - -Theming **requires** [**Sass**](https://github.com/sass/node-sass). - - -## Generating Color Palettes - -Our theming library is based on Sass. If you used the **Ignite UI CLI** to bootstrap your app, you can specify the style in the **angular.json** config to _scss_, the CLI will take care of compiling the Sass styles for you. If you haven't used Ignite UI CLI then you have to configure your builder to compile Sass styles for you. - -Our palettes accept arguments for `primary`, `secondary`, `surface`, `info`, `success`, `warn`, and `error` colors. The primary color is the one that will be the more prominent color throughout your application. The secondary color is the one used on elements that are actionable, such as buttons, switches, sliders, etc. The surface color is used for the background color of some of the components. The only required arguments are the ones for `primary`, `secondary` and `surface` colors. We default the ones for `info`, `success`, `warn`, and `error` to a predefined set of our choosing. - -To get started with our first color palette, create an _scss_ file that would be the base file for your global theme. I will call mine _"my-app-theme.scss"_. - -```scss -@use "igniteui-angular/theming" as *; - -// IMPORTANT: Prior to Ignite UI for Angular version 13 use: -// @import '~igniteui-angular/lib/core/styles/themes/index'; - -$company-color: #2ab759; // Some green shade I like -$secondary-color: #f96a88; // Watermelon pink -$surface-color: #e5e5e5; // Light gray - -$my-color-palette: palette( - $primary: $company-color, - $secondary: $secondary-color, - $surface: $surface-color -); -``` - -Now we have a palette, that contains exactly 216 colors! Whoa, wait, what? How did that happen? You provided 3 and got 216? Where did the other 213 colors come from? -Let's stop here to explain what just happened as it's quite important. When you provided `primary`, `secondary` and `surface` colors, we took those and generated shades and accent colors for each one. Basically now in your palette you have 3 sub-palettes for `primary`, `secondary` and `surface` colors. Each sub-palette contains 13 additional color variations based on the original color. 5 of the 13 colors are lighter shades of your original color, and 4 are darker. The remaining 4 colors are more exaggerated 'accent' versions of the original color. With the original color that makes for a total of 14 colors in each palette. - -With so many colors in each sub-palette you may be wondering, how on Earth will I know which one is which, right? It's quite simple, really. Each of the colors in the sub-palette has a number. We assign the number `500` to the original color. The lighter shades start from `50` and range to `400`. The darker shades start from `600` and range to `900`. The accent colors have string names `A100`, `A200`, `A400`, and `A700`, respectively. Okay, but now that's only 42 out of 216. Don't worry, there's another sub-palette we give you. One that consists of gray 'colors', called `grays`. It's just like the other two color sub-palettes, but doesn't include any accent variations. Good, now we're up to 42 + 10 for a total of 52 colors. That is still a long way from 216. Where do the other 164 colors come from? Let's solve the final puzzle. Remember you can also have 4 additional colors for `info`, `success`, `warn` and `error`. So that leaves another 56 colors unaccounted for. Remember the count for the `primary`, `secondary`, `surface`, `info`, `success`, `warn`, `error` and `grays` sub-palettes was exactly is exactly 108, which is the half of the 216 colors. The remaining half of the colors are the contrast text colors for each color variant, they all have `-contrast` as a suffix in their variable name, and they are either black or white. - -Got it? Good! But how does one access any of the colors in the palette? - - - -### Getting Sub-Palette Colors - -We provide a function that is easy to remember and use `color`. It takes three arguments - `palette`, `color`, and `variant`; - -```scss -$my-primary-600: color($my-color-palette, "primary", 600); -$my-primary-A700: color($my-color-palette, "secondary", "A700"); -$my-warning-color: color($my-color-palette, "warn"); -// sample usage - -.my-awesome-class { - background: $my-primary-600; - border-color: $my-primary-A700; -} - -.warning-bg { - background: $my-warning-color; -} -``` - - - -### Getting Contrast Text Colors - -Similar to how we get sub-palette colors, there's a way to get the contrast text color for each of the colors in the sub-palettes. - -```scss -$my-primary-800: color($my-palette, "primary", 600); -$my-primary-800-text: contrast-color($my-palette, "primary", 600); -// sample usage - -.my-awesome-article { - background: $my-primary-800; - color: $my-primary-800-text; -} -``` - -## Generating a Theme - -If you've included the _"igniteui-angular.css"_ file in your application project, now is a good time to remove it. We are going to use our own _"my-app-theme.scss"_ file to generate our own theme. - -Let's start from our very first example on this page. This time, though, we're going to be including two mixins `core` and `theme`; For now `core` doesn't accept any arguments. `theme`, however, does accept a few - `$palette`, `$schema`, `$exclude`, `$roundness`, `$elevation`, `$elevations`. For now, we'll only talk about the `$palette` argument. - - -Including `core` before `theme` is essential. The `core` mixin provides all base definitions needed for `theme` to work. - - -```scss -// Import the IgniteUI themes library first -@use "igniteui-angular/theming" as *; - -// IMPORTANT: Prior to Ignite UI for Angular version 13 use: -// @import '~igniteui-angular/lib/core/styles/themes/index'; - -$company-color: #2ab759; // Some green shade I like -$secondary-color: #f96a88; // Watermelon pink -$surface-color: #e5e5e5; // Light gray - -$my-color-palette: palette( - $primary: $company-color, - $secondary: $secondary-color, - $surface: $surface-color -); - -// IMPORTANT: Make sure you always include core first! -@include core(); -// Pass the color palette we generated to the theme mixin -@include theme($my-color-palette); -``` - -That's it. Your application will now use the colors from your newly generated palette. - - -In its current state, the defining custom typography is limited to changing the `font family` of the application. We'll be updating this functionality with subsequent releases. Our intent is to provide a robust way to customize the typography in your application. - -To customize the typography use the `typography` mixin. It takes exactly one argument - `config`. - - -Including `typography` after `core` is essential. This is subject to change in future releases. - - -```scss -// Import the IgniteUI themes library first -@use "igniteui-angular/theming" as *; - -// IMPORTANT: Prior to Ignite UI for Angular version 13 use: -// @import '~igniteui-angular/lib/core/styles/themes/index'; - -// IMPORTANT: Make sure you always include core first! -@include core(); -// Include typography before theme -@include typography( - $config: ( - font-family: "Comic Sans MS", - ) -); -@include theme($default-palette); -``` diff --git a/docs/angular/src/content/en/components/themes/index.mdx b/docs/angular/src/content/en/components/themes/index.mdx index 39a4a5dadb..2cf51d7828 100644 --- a/docs/angular/src/content/en/components/themes/index.mdx +++ b/docs/angular/src/content/en/components/themes/index.mdx @@ -1,9 +1,10 @@ --- -title: Theming Engine - Angular | Ignite UI for Angular -description: The Ignite UI for Angular Theming engine was developed through SASS with a low-difficulty API that offers restyling of one component, multiple components, or the entire application. -keywords: Ignite UI for Angular, UI controls, Angular widgets, web widgets, UI widgets, Angular, Native Angular Components Suite, Native Angular Controls, Native Angular Components Library, Native Angular Components, Angular Theming Engine, Angular Theming +title: Theming +description: Ignite UI for Angular theming lets you restyle components with CSS custom properties and an optional Sass engine, from a single component to your entire application. +keywords: Ignite UI for Angular, UI controls, Angular widgets, web widgets, UI widgets, Angular, Native Angular Components Suite, Native Angular Controls, Native Angular Components Library, Native Angular Components, Angular Theming Engine, Angular Theming, CSS variables, Sass theming, palettes, elevations, roundness llms: - description: "Ignite UI for Angular allows you to modify the styles of all component themes using CSS variables." + description: "Ignite UI for Angular allows you to modify the styles of all component themes using CSS variables, or go deeper with its Sass theming engine." +last_updated: "2026-09-10" --- import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; @@ -11,23 +12,25 @@ import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro' # Theming -Ignite UI for Angular allows you to modify the styles of all component themes using CSS variables. If you really wanted to dig deep, we provide a powerful Sass theming engine that allows you to create global component themes tailored to your specific design language that work in all modern browsers. +Ignite UI for Angular allows you to modify the styles of all component themes using CSS variables, or go deeper with a powerful Sass theming engine that lets you create global or component themes tailored to your specific design language, in all modern browsers. -This document describes the theming system in Ignite UI for Angular from version 12 forward. Starting with version 12 **CSS variables are the recommended way to modify the global and component themes**. -You can still use the Sass theming library as you would've prior to version 12. +This document describes the theming system in Ignite UI for Angular from version 12 forward. Starting with version 12, **CSS variables are the recommended way to modify the global and component themes**. The Sass theming library is still available and works alongside CSS variables. -## Basic Usage +## Key Features -Ignite UI for Angular includes the following themes as part of its package: +| Feature | Description | Benefit | +| :------ | :----------- | :------ | +| Bundled design-system themes | Material, Bootstrap, Fluent, and Indigo themes, each with light and dark variants and built-in LTR/RTL support. | Get a production-ready look with a single stylesheet reference — no build step required. | +| CSS custom properties | Every theme exposes color, elevation, typography, and configuration values as `--ig-*` CSS variables. | Restyle components at runtime, per-application or per-instance, without recompiling Sass. | +| Sass theming engine | The same Sass API used internally to build every bundled theme, exposed as public mixins and functions. | Generate palettes, exclude unused component tokens, and build fully custom themes at compile time. | +| Global and local component variables | Each component exposes a global (`--ig-[component]-*`) and a local (`--*`) variable for the same property. | Override a look application-wide, then selectively override individual instances without extra CSS specificity tricks. | +| Configurable roundness and elevation | Single `--ig-radius-factor` and `--ig-elevation-factor` variables scale every component's corners and shadows. | Change the overall shape and depth of the UI without touching individual component styles. | -- Material -- Bootstrap -- Fluent -- Indigo +## Bundled Themes -All themes have light and dark variants as well as support for left-to-right(LTR) and right-to-left(RTL) content by default. The easiest way to start using any of the bundled themes in your application is by specifying the path to a CSS theme file in your `angular.json` configuration. For example, if you wanted to use the dark Material theme, you would include the path to the theme file like so: +All themes ship with light and dark variants and support left-to-right (LTR) and right-to-left (RTL) content by default. The easiest way to use a bundled theme is to reference its CSS file in your `angular.json` configuration. For example, to use the dark Material theme: ```json "styles": [ @@ -37,7 +40,7 @@ All themes have light and dark variants as well as support for left-to-right(LTR ``` -If you've installed the Ignite UI for Angular package using `ng add igniteui-angular`, you will have noticed that we've already added `igniteui-angular.css` to the styles array. +If you installed Ignite UI for Angular using `ng add igniteui-angular`, `igniteui-angular.css` is already added to the styles array for you. Here's the full list of themes included in the styles folder: @@ -58,19 +61,15 @@ Here's the full list of themes included in the styles folder: | **Indigo Light** | `node_modules/igniteui-angular/styles/igniteui-indigo-light.css` | | **Indigo Dark** | `node_modules/igniteui-angular/styles/igniteui-indigo-dark.css` | -As you can see, we ship Ignite UI for Angular with a substantial amount of themes. +All bundled themes are compiled from the same Sass source, using the theming engine's public `mixins` and `functions`. If Sass isn't your thing, that's fine — every compiled theme also exposes its values as [CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties), so you can restyle it without a Sass build step. You can also combine both approaches in the same project. -This is not the end of our theming story, though. All themes are compiled from Sass source and are built using our powerful theming engine. This engine contains Sass `mixins` and `functions` many of which are publicly exposed, which allows you to completely redesign all components in your application. +## Customizing with CSS Variables -If Sass isn't your thing that's completely fine, we've made it easy to modify the compiled themes using [custom CSS properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties), or otherwise known as CSS variables. You can still use Sass in combination with CSS variables. +Every bundled CSS theme declares its variables in the `:root` scope, covering `colors`, `shadows`, `typography`, and `configuration`. Changing any of them updates the corresponding component styles across your application. -## Global Variables +### Palette Colors -If you inspect any of the CSS themes above, you will notice that there are quite a few CSS variables included in the `:root` scope; We include variables for `colors`, `shadows`, `typography`, and `configuration`. Modifying any of these variables will allow you to customize the overall look and feel of the theme and conversely the components. - -What most people look for when modifying a theme is changing the default colors used by the components. - -If you wanted to change the primary and secondary colors, all you have to do is type the following in your `styles.css` file: +To change the primary and secondary colors, set the corresponding variables in your `styles.css` file: ```css /* styles.css */ @@ -81,17 +80,15 @@ If you wanted to change the primary and secondary colors, all you have to do is } ``` -Let's break down the names of these color variables. The `ig` prefix is there as a unique identifier to indicate that this variable is part of an Ignite UI for Angular theme, `primary` is the color variable name, and `500` stands for the color variant. We will take a deeper look at palettes in the [Palettes](/themes/palettes) section of the documentation. For now all you need to know is that we have several base color variables (primary, secondary, surface, success, info, etc.) that include different shades or _variants_ that are all generated from the main color variants. The `500` color variants that we set in the above example are considered the main variable color and all of the other variants for the given color variable are generated from the `500` variant. - -Changing these variants, you can completely overhaul the entire palette. +The `ig` prefix identifies the variable as part of an Ignite UI for Angular theme, `primary` names the color variable, and `500` is the color variant. Ignite UI for Angular ships several base color variables (`primary`, `secondary`, `surface`, `success`, `info`, and more), each with a range of variants generated from its `500` (main) value. Changing the `500` variant regenerates the rest of that color's palette. See [Palettes](/themes/palettes) for the full list of variants. -Some components do not use colors from the palettes. In those instances, you will have to target the component CSS variables directly to modify their colors. -To find out which palette colors are used by what component, take a look at the . +Some components do not use colors from the palettes. In those instances, target the component's CSS variables directly to modify their colors. To find out which palette colors a component uses, see the . -Likewise, changing the `elevations`(shadows) is just as easy. We include 25 elevation levels (0-24). -Here's a simplified version of what those variables look like: +### Elevations + +Elevations (shadows) work the same way, across 25 levels (0–24): ```css /* styles.css */ @@ -107,43 +104,37 @@ Here's a simplified version of what those variables look like: } ``` -These are essentially stacked CSS [`box-shadow`](https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow) declarations. You can replace them with any other valid `box-shadow` value. The higher the elevation level number is, the bigger the shadow is. Again, different components use different elevation levels, to find out which elevation levels are used by which component, take look at the . We will take a deeper look at elevations in the [Elevations](/themes/elevations) of the documentation. +Each variable is a stacked CSS [`box-shadow`](https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow) declaration; you can replace any of them with another valid `box-shadow` value. The higher the elevation level, the larger the shadow. Different components use different elevation levels by default — see [Elevations](/themes/elevations) for the full breakdown, and the for which level each component uses. -## Configuration +### Roundness and Elevation Factor -There are several variables that allow you to configure the global behavior of the theme: +Two variables configure component shape and depth globally: -### Roundness +- `--ig-radius-factor` sets the radius factor of all components. The default is `1`. Set it to `0` to make every component's corners square: -To configure the radius factor of all components you can change the value of the `--ig-radius-factor` variable. The default value is 1, meaning the default radius factor is used across component themes. + ```css + /* Makes all components appear blocky in shape */ + :root { + --ig-radius-factor: 0; + } + ``` -Example: +- `--ig-elevation-factor` sets the elevation (shadow) factor of all components. The default is `1`. Set it to `0` to remove shadows entirely: -```css -/* Makes all components appear blocky in shape */ -:root { - --ig-radius-factor: 0; -} -``` + ```css + /* Makes all components appear flat (no shadows) */ + :root { + --ig-elevation-factor: 0; + } + ``` -### Elevation Factor +See [Roundness](/themes/roundness) to scope `--ig-radius-factor` to individual components instead of the whole application. -To configure the elevation factor of all components you can change the value of the `--ig-elevation-factor` variable. The default value is 1, meaning the default elevations are used across component themes. +### Component Variables -Example: +Every component exposes two variables for each themeable property: a **global** variable (prefixed `--ig-[component-name]-`) and a **local** variable (`--*`). Both modify the same property; the difference is scope. Global variables apply from any parent selector to all instances of a component. Local variables apply only to the instances matched by the selector that sets them, and always take priority over the global variable. -```css -/* Makes all components appear flat (no-shadows) */ -:root { - --ig-elevation-factor: 0; -} -``` - -## Component Variables - -All components provide the ability to modify their themes using component-specific CSS variables. Each component exposes two variables that modify the same property. The exposed variables can be thought of as `global` and `local`. They both modify the component theme in the same way, the only difference is that `global` variables have the `igx-[component-name]` prefix attached to the variable name and can be used from parent selectors to style child components, while `local` variables are specific to a component instance. - -Let's look at an example. Say you wanted to modify the background of the avatar. The avatar looks for the following CSS variables that modify its background: +For example, the avatar component looks for `--ig-avatar-background` (global) and `--background` (local): ```css /* styles.css */ @@ -156,12 +147,7 @@ igx-avatar { } ``` -The snippet above will set the background in all avatars to orange. - -The avatar component will look for the `--background` variable first. If explicitly set, it will take its value. In other words, `local` variables have higher priority and will work **only** if applied to the `igx-avatar` directly, either by using its tag selector or any other selector that targets `igx-avatar`. -The global `--ig-avatar-background` can be thought of as _fallback_ variable. It's going to be used only if the local `--background` is not explicitly overridden. - -For the curious, here's how this is implemented internally in the avatar: +This sets the background of every avatar to orange, because the local `--background` variable overrides the global one wherever it's set on `igx-avatar` directly. Here's how the avatar implements this internally: ```css igx-avatar { @@ -170,9 +156,7 @@ igx-avatar { } ``` -You would generally use _global_ variables when you want to apply changes to all instances of a component while _local_ variables target specific component instances and will always override the global variable. - -Here's another example: +Use the global variable to restyle all instances of a component at once; use the local variable to target specific instances. For example: ```html {/* app.component.html */} @@ -201,21 +185,57 @@ igx-avatar { } ``` -Avatars `AB` and `CD` will use the globally set _lavender_ color as background, while avatars `EF` and `GH` will have _purple_ backgrounds. +Avatars `AB` and `CD` use the globally set _lavender_ background, while avatars `EF` and `GH` — scoped under `contacts.component.css` — use _purple_. -**Each component has all of its theme properties documented in the styling section of the component documentation.** +**Each component documents its own theme properties in the styling section of its topic.** -This should be all you need to get you started with theming. You can modify global palette colors, elevations, and change component theme properties by creating global and local component themes. If you want to learn more, we have extensive documentation covering topics like **Palettes**, **Elevations**, **Typography**, and **Theming with Sass** in depth. +## Sass Theming Engine -## Additional Resources +If CSS variables don't give you enough control — for example, you need several reusable theme variants of the same component, or you want to tree-shake the generated CSS down to only the components you use — use the Sass theming engine directly. It exposes the same `palette`, `core`, and `theme` APIs used to build every bundled theme: + +```scss +// Import the theming module +@use "igniteui-angular/theming" as *; + +$my-color-palette: palette( + $primary: #2ab759, + $secondary: #f96a88, + $surface: #e5e5e5 +); + +// IMPORTANT: Always include core() first — it provides the base +// definitions theme() depends on. +@include core(); +@include theme($my-color-palette); +``` + +See [Theming with Sass](/themes/sass) for the full concept breakdown — palettes, schemas, typography, roundness, elevations, and animations — and how to build global or component-scoped themes with it. + +## Accessibility -Related topics: +Palette colors and their contrast text colors are generated together: every color variant in a palette has a matching `-contrast` variant (black or white) chosen for readable contrast against it, retrievable with the Sass `contrast-color` function — see [Contrast Text Colors](/themes/sass/palettes#contrast-text-colors). Compiled themes also expose each one as a `--ig-*-contrast` CSS variable; see [Palettes](/themes/palettes). + +The `core()` Sass mixin accepts an `$enhanced-accessibility` argument (default `false`). Enabling it switches chart color brushes to a color-blind–friendly palette instead of the regular one: + +```scss +@include core($enhanced-accessibility: true); +``` + +## API References + +- + +## Next Steps - [Palettes](/themes/palettes) - [Elevations](/themes/elevations) - [Typography](/themes/typography) +- [Roundness](/themes/roundness) +- [Spacing](/themes/spacing) - [Theming with Sass](/themes/sass) +## Additional Resources + Our community is active and always welcoming to new ideas. - [Ignite UI for Angular **Forums**](https://www.infragistics.com/community/forums/f/ignite-ui-for-angular) diff --git a/docs/angular/src/content/en/components/themes/misc/angular-material-theming.mdx b/docs/angular/src/content/en/components/themes/misc/angular-material-theming.mdx index 0ba0614b6a..105caff742 100644 --- a/docs/angular/src/content/en/components/themes/misc/angular-material-theming.mdx +++ b/docs/angular/src/content/en/components/themes/misc/angular-material-theming.mdx @@ -415,7 +415,7 @@ Related topics: - [Component Themes](../sass/component-themes.mdx) - [Typography](../sass/typography.mdx) - [Avatar Component](../../layouts/avatar.mdx) -- [Button Component](../../button.mdx) +- [Button Component](inputs/button) - [Dialog Component](../../dialog.mdx) - [Icon Component](../../icon.mdx) - [Expansion Panel Component](../../expansion-panel.mdx) diff --git a/docs/angular/src/content/en/components/themes/misc/bootstrap-theming.mdx b/docs/angular/src/content/en/components/themes/misc/bootstrap-theming.mdx index 8e684acf91..29ecf33030 100644 --- a/docs/angular/src/content/en/components/themes/misc/bootstrap-theming.mdx +++ b/docs/angular/src/content/en/components/themes/misc/bootstrap-theming.mdx @@ -368,7 +368,7 @@ Ignite UI for Angular exposes four default type scales for each of its themes, w - [Component Themes](/themes/sass/component-themes) - [Typography](/themes/sass/typography) - [Avatar Component](../../layouts/avatar.mdx) -- [Button Component](/button) +- [Button Component](inputs/button) - [Dialog Component](/dialog) - [Icon Component](/icon) - [List Component](/list) diff --git a/docs/angular/src/content/en/components/themes/palettes.mdx b/docs/angular/src/content/en/components/themes/palettes.mdx index 2349cbc1ac..cf00e2a1f0 100644 --- a/docs/angular/src/content/en/components/themes/palettes.mdx +++ b/docs/angular/src/content/en/components/themes/palettes.mdx @@ -60,17 +60,17 @@ Here's an excerpt of the `primary` variable color as declared in the Light Mater :root { //... --ig-primary-500: #09f; - --ig-primary-500-contrast: hsl(from color(from var(--ig-primary-500) var(--y-contrast)) h 0 l); + --ig-primary-500-contrast: hsla(from color(from var(--ig-primary-500) var(--y-contrast)) h 0 l / 1); --ig-primary-600: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-primary-600-contrast: hsl(from color(from var(--ig-primary-600) var(--y-contrast)) h 0 l); + --ig-primary-600-contrast: hsla(from color(from var(--ig-primary-600) var(--y-contrast)) h 0 l / 1); --ig-primary-700: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.81)); //... --ig-secondary-400: hsl(from var(--ig-secondary-500) h calc(s * 0.875) calc(l * 1.08)); - --ig-secondary-400-contrast: hsl(from color(from var(--ig-secondary-400) var(--y-contrast)) h 0 l); + --ig-secondary-400-contrast: hsla(from color(from var(--ig-secondary-400) var(--y-contrast)) h 0 l / 1); --ig-secondary-500: #df1b74; - --ig-secondary-500-contrast: hsl(from color(from var(--ig-secondary-500) var(--y-contrast)) h 0 l); + --ig-secondary-500-contrast: hsla(from color(from var(--ig-secondary-500) var(--y-contrast)) h 0 l / 1); --ig-secondary-600: hsl(from var(--ig-secondary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-secondary-600-contrast: hsl(from color(from var(--ig-secondary-600) var(--y-contrast)) h 0 l); + --ig-secondary-600-contrast: hsla(from color(from var(--ig-secondary-600) var(--y-contrast)) h 0 l / 1); //... --ig-wcag-a: 0.31; --ig-wcag-aa: 0.185; diff --git a/docs/angular/src/content/en/components/themes/roundness.mdx b/docs/angular/src/content/en/components/themes/roundness.mdx index 36eb3f72e4..929642b288 100644 --- a/docs/angular/src/content/en/components/themes/roundness.mdx +++ b/docs/angular/src/content/en/components/themes/roundness.mdx @@ -20,7 +20,7 @@ Many Ignite UI components have predefined minimum and maximum border-radius valu When you set `--ig-radius-factor` to 0, the component uses its minimum border-radius and will appear more block-like with sharp corners. When set to 1, the component uses its maximum predefined border-radius and will appear rounded. Here is a list of the components that have predefined minimum and maximum border-radius values and can be modified using the `--ig-radius-factor` variable:
-• [Action Strip](/action-strip) • [Button](/button) • [Button Group](/components/inputs/button-group) • [Calendar](/calendar) • [Card](/card) • [Carousel](/carousel) • [Checkbox](/checkbox) • [Chip](/chip) • [Combo](/combo) • [Date Picker](/date-picker) • [Date Range Picker](/date-range-picker) • [Grid](/grid/grid) • [Input Group](/input-group) • [Linear Progress](/linear-progress) • [List](/list) • [Month Picker](/month-picker) • [Navigation Drawer](/navdrawer) • [Radio](/radio-button) • [Ripple](/ripple) • [Snackbar](/snackbar) • [Switch](/switch) • [Toast](/toast) +• [Action Strip](/action-strip) • [Button](inputs/button) • [Button Group](/inputs/button-group) • [Calendar](/calendar) • [Card](/card) • [Carousel](/carousel) • [Checkbox](/checkbox) • [Chip](/chip) • [Combo](/combo) • [Date Picker](/date-picker) • [Date Range Picker](/date-range-picker) • [Grid](/grid/grid) • [Input Group](/input-group) • [Linear Progress](/linear-progress) • [List](/list) • [Month Picker](/month-picker) • [Navigation Drawer](/navdrawer) • [Radio](/radio-button) • [Ripple](/ripple) • [Snackbar](/snackbar) • [Switch](inputs/switch) • [Toast](/toast) ## Usage diff --git a/docs/angular/src/content/en/components/themes/sass/global-themes.mdx b/docs/angular/src/content/en/components/themes/sass/global-themes.mdx index 80c034cc4c..3e4f694b76 100644 --- a/docs/angular/src/content/en/components/themes/sass/global-themes.mdx +++ b/docs/angular/src/content/en/components/themes/sass/global-themes.mdx @@ -30,7 +30,7 @@ To generate a global theme we're going to be including two mixins `core` and `th | Name | Type | Default | Description | | :-----------------------: | :-----: | :-----: | :-----------------------------------------------------------------------: | | `$print-layout` | boolean | true | Include/exclude the styles for printing. | -| `$enhanced-accessibility` | boolean | false | Switches component colors and other properties to more accessible values. | +| `$enhanced-accessibility` | boolean | false | Switches chart color brushes to a color-blind–friendly palette. | ### Theme mixins diff --git a/docs/angular/src/content/en/components/time-picker.mdx b/docs/angular/src/content/en/components/time-picker.mdx index 115711897c..d177134b97 100644 --- a/docs/angular/src/content/en/components/time-picker.mdx +++ b/docs/angular/src/content/en/components/time-picker.mdx @@ -408,7 +408,7 @@ $my-time-picker-theme: time-picker-theme( ``` -In order to style any additional components that are used as part of the time picker window's content (such as the [`IgxButton`](/button)), an additional theme should be created that is specific to the respective component and is placed under the dialog window's scope only (so it does not affect the rest of the application). +In order to style any additional components that are used as part of the time picker window's content (such as the [`IgxButton`](./inputs/button.mdx)), an additional theme should be created that is specific to the respective component and is placed under the dialog window's scope only (so it does not affect the rest of the application). Since the time picker window uses the [`IgxOverlayService`](/overlay), in order for our custom theme to reach down the time picker window that we want to style, we will provide a specific outlet where the dialog window will be placed in the DOM when it is visible. diff --git a/docs/angular/src/content/en/components/toc.json b/docs/angular/src/content/en/components/toc.json index cee884ad7d..1284f8f3ac 100644 --- a/docs/angular/src/content/en/components/toc.json +++ b/docs/angular/src/content/en/components/toc.json @@ -482,6 +482,12 @@ "updated": false, "premium": true }, + { + "name": "Theming", + "href": "grid/theming.mdx", + "new": true, + "premium": true + }, { "name": "Keyboard navigation", "href": "grid/keyboard-navigation.mdx", @@ -758,6 +764,12 @@ "updated": false, "premium": true }, + { + "name": "Theming", + "href": "treegrid/theming.mdx", + "new": true, + "premium": true + }, { "name": "Group By", "href": "treegrid/groupby.mdx", @@ -1012,6 +1024,12 @@ "updated": false, "premium": true }, + { + "name": "Theming", + "href": "hierarchicalgrid/theming.mdx", + "new": true, + "premium": true + }, { "name": "Size", "href": "hierarchicalgrid/display-density.mdx", @@ -1078,6 +1096,12 @@ "new": false, "updated": true, "premium": true + }, + { + "name": "Theming", + "href": "pivotgrid/theming.mdx", + "new": true, + "premium": true } ] }, @@ -1806,6 +1830,11 @@ "href": "themes/spacing.mdx", "new": false }, + { + "name": "Accessibility", + "href": "themes/accessibility.mdx", + "new": true + }, { "name": "Sass", "new": false, @@ -1950,7 +1979,7 @@ }, { "name": "Button", - "href": "button.mdx" + "href": "inputs/button.mdx" }, { "name": "Button Group", @@ -1967,7 +1996,7 @@ }, { "name": "Switch", - "href": "switch.mdx" + "href": "inputs/switch.mdx" }, { "name": "Query Builder", @@ -2010,6 +2039,11 @@ "href": "inputs/badge.mdx", "updated": false }, + { + "name": "QR Code", + "href": "inputs/qr-code.mdx", + "new": true + }, { "name": "Icon", "href": "icon.mdx", @@ -2042,6 +2076,11 @@ "name": "Virtual For Directive", "href": "for-of.mdx" }, + { + "name": "Virtual Scroll", + "href": "layouts/virtual-scroll.mdx", + "new": true + }, { "name": "Chip", "href": "chip.mdx", @@ -2188,7 +2227,7 @@ }, { "name": "Accordion", - "href": "accordion.mdx", + "href": "layouts/accordion.mdx", "new": false }, { diff --git a/docs/angular/src/content/en/components/tooltip.mdx b/docs/angular/src/content/en/components/tooltip.mdx index 88c1e4a8a1..f073fd551f 100644 --- a/docs/angular/src/content/en/components/tooltip.mdx +++ b/docs/angular/src/content/en/components/tooltip.mdx @@ -486,7 +486,7 @@ $dark-tooltip: tooltip-theme( ``` -In order to style any additional components that are used as part of the tooltip's content (such as [`IgxButton`](/button), [`IgxSwitch`](/switch), etc.), an additional theme should be created that is specific to the respective component and placed under the tooltip's scope only (so it does not affect the rest of the application). +In order to style any additional components that are used as part of the tooltip's content (such as [`IgxButton`](./inputs/button.mdx), [`IgxSwitch`](./inputs/switch.mdx), etc.), an additional theme should be created that is specific to the respective component and placed under the tooltip's scope only (so it does not affect the rest of the application). Since the tooltip uses the [`IgxOverlayService`](/overlay), in order for our custom theme to reach down the tooltip that we want to style, we will provide a specific outlet where the tooltip will be placed in the DOM when it is visible. diff --git a/docs/angular/src/content/en/components/treegrid/tree-grid.mdx b/docs/angular/src/content/en/components/treegrid/tree-grid.mdx index c48d49809b..7144ed39f5 100644 --- a/docs/angular/src/content/en/components/treegrid/tree-grid.mdx +++ b/docs/angular/src/content/en/components/treegrid/tree-grid.mdx @@ -328,7 +328,7 @@ The last step is to **include** the component theme in our application. ### Angular Tree Grid Styling Demo - + There are also additional parameters in the that you can use if you want more specific customizations. diff --git a/docs/angular/src/content/en/grids_templates/row-editing.mdx b/docs/angular/src/content/en/grids_templates/row-editing.mdx index effadae05b..7844ca4a1c 100644 --- a/docs/angular/src/content/en/grids_templates/row-editing.mdx +++ b/docs/angular/src/content/en/grids_templates/row-editing.mdx @@ -320,9 +320,9 @@ If you want the buttons to be part of the keyboard navigation, then each on of t Using the [Ignite UI for Angular Theme Library](/themes), we can greatly alter the Row Editing overlay. The Row Editing overlay is a composite element - its UI is comprised of a couple of other components: - [`igx-banner`](/banner) in order to render its contents - - [`igx-button`](/button)s are rendered in the default template (for the `Done` and `Cancel` buttons). + - [`igx-button`](inputs/button)s are rendered in the default template (for the `Done` and `Cancel` buttons). -In the below example, we will make use of those two components' styling options, [`button styling`](/button#styling) & [`banner-styling`](/banner#styling), to customize the experience of our {ComponentName}'s Row Editing. +In the below example, we will make use of those two components' styling options, [`button styling`](inputs/button#styling) & [`banner-styling`](/banner#styling), to customize the experience of our {ComponentName}'s Row Editing. We will also style the current cell's editor and background to make it more distinct. diff --git a/docs/angular/src/content/en/grids_templates/search.mdx b/docs/angular/src/content/en/grids_templates/search.mdx index c75a46a425..d0330d3f09 100644 --- a/docs/angular/src/content/en/grids_templates/search.mdx +++ b/docs/angular/src/content/en/grids_templates/search.mdx @@ -260,7 +260,7 @@ What if we would like to filter and sort our {ComponentTitle} or even to add and ### Adding icons By using some of our other components, we can create an enriched user interface and improve the overall design of our entire search bar! We can have a nice search or delete icon on the left of the search input, a couple of chips for our search options and some material design icons combined with nice ripple styled buttons for our navigation on the right. We can wrap these components inside an input group for a more refined design. -To do this, let's go and grab the [**IgxInputGroup**](/input-group), [**IgxIcon**](/icon), [**IgxRipple**](/ripple), [**IgxButton**](/button) and the [**IgxChip**](/chip) modules. +To do this, let's go and grab the [**IgxInputGroup**](/input-group), [**IgxIcon**](/icon), [**IgxRipple**](/ripple), [**IgxButton**](inputs/button) and the [**IgxChip**](/chip) modules. ```typescript // app.module.ts diff --git a/docs/angular/src/content/en/grids_templates/theming.mdx b/docs/angular/src/content/en/grids_templates/theming.mdx new file mode 100644 index 0000000000..82e55027be --- /dev/null +++ b/docs/angular/src/content/en/grids_templates/theming.mdx @@ -0,0 +1,244 @@ + + +--- +title: Angular Grid Theming - Ignite UI for Angular +description: The Ignite UI for Angular Grid is themed with grid-theme(), a Sass function that derives every color in the component from three primary tokens. +keywords: angular grid theming, angular grid styling, grid theme, ignite ui for angular, infragistics +license: commercial +last_updated: "2026-08-27" +llms: + description: "The Ignite UI for Angular Grid is themed through grid-theme(), which derives every color from a background, foreground and accent token." +--- + + + + +--- +title: Angular Tree Grid Theming - Ignite UI for Angular +description: The Ignite UI for Angular Tree Grid is themed with grid-theme(), a Sass function that derives every color in the component from three primary tokens. +keywords: angular tree grid theming, angular tree grid styling, grid theme, ignite ui for angular, infragistics +license: commercial +_canonicalLink: grid/theming +last_updated: "2026-08-27" +llms: + description: "The Ignite UI for Angular Tree Grid is themed through grid-theme(), which derives every color from a background, foreground and accent token." +--- + + + + +--- +title: Angular Hierarchical Grid Theming - Ignite UI for Angular +description: The Ignite UI for Angular Hierarchical Grid is themed with grid-theme(), a Sass function that derives every color in the component from three primary tokens. +keywords: angular hierarchical grid theming, angular hierarchical grid styling, grid theme, ignite ui for angular, infragistics +license: commercial +_canonicalLink: grid/theming +last_updated: "2026-08-27" +llms: + description: "The Ignite UI for Angular Hierarchical Grid is themed through grid-theme(), which derives every color from a background, foreground and accent token." +--- + + + + +--- +title: Angular Pivot Grid Theming - Ignite UI for Angular +description: The Ignite UI for Angular Pivot Grid is themed with grid-theme(), a Sass function that derives every color in the component from three primary tokens. +keywords: angular pivot grid theming, angular pivot grid styling, grid theme, ignite ui for angular, infragistics +license: commercial +_canonicalLink: grid/theming +last_updated: "2026-08-27" +llms: + description: "The Ignite UI for Angular Pivot Grid is themed through grid-theme(), which derives every color from a background, foreground and accent token." +--- + + + +import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; +import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; +import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; + +# Angular {ComponentTitle} Theming + +The Ignite UI for Angular {ComponentTitle} is themed through , which derives every color from a background, foreground and accent token. Those three primary tokens reach everything the component renders: the header, the rows, the borders, the summaries, the toolbar, the paginator and the filtering popups. + + +There is no separate theme function per grid. The Data Grid, Tree Grid, Hierarchical Grid and Pivot Grid all read `grid-theme()`, so the same theme applies to any of them without modification. + + +## Angular {ComponentTitle} Theming Example + +The four themes below are custom — written for this sample, not shipped with the library. Each sets the three primary tokens and nothing else in the color space, so switching between them shows how far those three values reach. + + + + + + + + + + + + + + + + + + + + + + +## Getting started + +Import the theming entry point, where the theme functions and the `tokens()` mixin are exported: + +```scss +@use "igniteui-angular/theming" as *; +``` + +Then declare a theme and include it on the element you want to affect: + +```scss +:host { + @include tokens(grid-theme( + $background: #08002e, + $accent-color: #ff7d52 + )); +} +``` + +That is a complete theme. The {ComponentTitle} is now dark indigo with a coral accent, and the text, header, row borders, hover states, selection tints and popup chrome have all been computed for you. + +## Primary tokens + +The {ComponentTitle} theme is built from three tokens; every other color is derived from them. + +| Token | What it controls | +| -- | -- | +| `$background` | The surface the whole component is built on. Every other surface and the default foreground are derived from it. | +| `$foreground` | Text and icons. Derived from `$background` by contrast when not set. | +| `$accent-color` | Interactive color: sort indicators, selection, hover tints, focus. | + +`$foreground` is listed as primary but rarely needs setting. Left alone, it is chosen for contrast against the background, so a dark background produces light text and a light one produces dark text without a second declaration. + +## How derivation works + +When you declare a theme, the derived tokens are not resolved at build time into fixed colors. They are emitted as CSS expressions over the primary tokens you supplied: + +```css +.my-grid { + --ig-grid-foreground: hsla(from color(from var(--ig-grid-background) var(--y-contrast)) h 0 l/1); + --ig-grid-header-background: color-mix(in srgb, var(--ig-grid-foreground) 6%, var(--ig-grid-background)); + --ig-grid-row-hover-background: color-mix(in srgb, var(--ig-grid-accent-color) 8%, var(--ig-grid-row-odd-background)); + --ig-grid-sorted-header-icon-color: hsl(from var(--ig-grid-accent-color) h s l/0.7); +} +``` + +Two consequences follow. Changing a primary token re-computes everything downstream, including at runtime through CSS custom properties. And the relationships hold whatever value you supply, so a theme cannot fall out of step with itself. + +## Going deeper + +Some tokens are derivation roots in their own right. Declaring one detaches it from the background, and whatever sits on it derives from the new value instead. + +`$header-background` is the clearest example. Left alone it is mixed from `$background`, and the header text follows `$foreground`. Declare it, and the header text is re-derived to take contrast against the header itself: + +```scss +:host { + @include tokens(grid-theme( + $background: #08002e, + $accent-color: #ff7d52, + $header-background: #ff7d52 + )); +} +``` + + +Reach for these only when you want a surface to stop tracking the background. Most tokens the theme documents as auto-derived are best left alone — overriding one pins a value that would otherwise stay in step with the rest of the theme. + + +## Structure + +Color is only half of a theme. Density and roundness are controlled by global design-system tokens rather than `grid-theme()` parameters, so they are set as plain custom properties: + +```scss +:host { + --ig-size: var(--ig-size-small); // small | medium | large + --ig-radius-factor: 0; // 0 to 1 + + @include tokens(grid-theme( + $background: #08002e, + $accent-color: #ff7d52 + )); +} +``` + +Grid lines are theme parameters. To hide one, tint it to the surface behind it rather than removing it, so the row metrics do not change between themes: + +```scss +@include tokens(grid-theme( + // horizontal dividers, blended away + $row-border-color: var(--ig-grid-background), + // vertical dividers, drawn in the same color the theme derives for rows + $body-column-border-color-odd: hsl(from color-mix(in srgb, var(--ig-grid-foreground) 16%, var(--ig-grid-background)) h s l/0.38), + $body-column-border-color-even: hsl(from color-mix(in srgb, var(--ig-grid-foreground) 16%, var(--ig-grid-background)) h s l/0.38) +)); +``` + +## CSS variables + +The default appearance is deliberate, not derived: out of the box the {ComponentTitle} matches the Ignite UI design specification exactly, resolving against the base palette rather than computing colors from a background. Derivation is what you opt into when you declare a theme of your own. + +That has one practical consequence for CSS-only theming. Until a theme is declared there are no derived expressions to override — the component reads `var(--ig-grid-header-background, var(--ig-gray-100))` and its siblings — so setting a couple of custom properties by hand does **not** cascade: + +```css +/* Not enough on its own: the background changes, the header stays grey. */ +.my-grid { + --ig-grid-background: #08002e; + --ig-grid-accent-color: #ff7d52; +} +``` + +To theme without a Sass build, declare the **full token set** — the roots plus the derived expressions that reference them. That block is self-contained, because each derived token is an expression over the roots: + +```css +.my-grid { + --ig-grid-background: #08002e; + --ig-grid-accent-color: #ff7d52; + --ig-grid-foreground: hsla(from color(from var(--ig-grid-background) var(--y-contrast)) h 0 l/1); + --ig-grid-header-background: color-mix(in srgb, var(--ig-grid-foreground) 6%, var(--ig-grid-background)); + /* … and the rest of the theme's tokens */ +} +``` + +Generating that by hand is impractical, so use the playground below: it emits the complete block for the colors you pick. + + +Prefer the Sass route when you can. `grid-theme()` writes the derived tokens for you and keeps them in step with the library; a hand-maintained CSS block is a snapshot that will not pick up changes to the theme. + + +## Try it + +Change a color and watch it reach the header, the rows, the summaries, the paginator and the filtering popups. Switch grids to confirm the same tokens serve all of them, and copy the generated theme when you are happy with it. + + + +## API References + +- +- + +## Additional Resources + +- [{ComponentTitle} overview](/{igPath}/{ComponentMainTopic}) +- [Palettes](/themes/sass/palettes) +- [Typography](/themes/typography) + + + +- [Size](/{igPath}/display-density) +- [Conditional Styling](/{igPath}/conditional-cell-styling) + + diff --git a/docs/angular/src/content/en/images/accordion/accordion_do1.png b/docs/angular/src/content/en/images/accordion/accordion_do1.png new file mode 100644 index 0000000000..148543500f Binary files /dev/null and b/docs/angular/src/content/en/images/accordion/accordion_do1.png differ diff --git a/docs/angular/src/content/en/images/accordion/accordion_do1@2x.png b/docs/angular/src/content/en/images/accordion/accordion_do1@2x.png new file mode 100644 index 0000000000..a7cf23b8cc Binary files /dev/null and b/docs/angular/src/content/en/images/accordion/accordion_do1@2x.png differ diff --git a/docs/angular/src/content/en/images/accordion/accordion_do_not1.png b/docs/angular/src/content/en/images/accordion/accordion_do_not1.png new file mode 100644 index 0000000000..2cd85c19bc Binary files /dev/null and b/docs/angular/src/content/en/images/accordion/accordion_do_not1.png differ diff --git a/docs/angular/src/content/en/images/accordion/accordion_dont1@2x.png b/docs/angular/src/content/en/images/accordion/accordion_dont1@2x.png new file mode 100644 index 0000000000..61f5c80b74 Binary files /dev/null and b/docs/angular/src/content/en/images/accordion/accordion_dont1@2x.png differ diff --git a/docs/angular/src/content/en/images/anatomy-content-light/button-lt-a.png b/docs/angular/src/content/en/images/anatomy-content-light/button-lt-a.png new file mode 100644 index 0000000000..05656c6c3e Binary files /dev/null and b/docs/angular/src/content/en/images/anatomy-content-light/button-lt-a.png differ diff --git a/docs/angular/src/content/en/images/anatomy-content-light/qr-code-lt-a.png b/docs/angular/src/content/en/images/anatomy-content-light/qr-code-lt-a.png new file mode 100644 index 0000000000..3ffa3c018b Binary files /dev/null and b/docs/angular/src/content/en/images/anatomy-content-light/qr-code-lt-a.png differ diff --git a/docs/angular/src/content/en/images/anatomy-content-light/switch-lt-a.png b/docs/angular/src/content/en/images/anatomy-content-light/switch-lt-a.png new file mode 100644 index 0000000000..a52a0c650e Binary files /dev/null and b/docs/angular/src/content/en/images/anatomy-content-light/switch-lt-a.png differ diff --git a/docs/angular/src/content/en/images/anatomy-frame-light/Accordion-lt.png b/docs/angular/src/content/en/images/anatomy-frame-light/Accordion-lt.png new file mode 100644 index 0000000000..d13af44d2a Binary files /dev/null and b/docs/angular/src/content/en/images/anatomy-frame-light/Accordion-lt.png differ diff --git a/docs/angular/src/content/en/images/button/button-do-1.png b/docs/angular/src/content/en/images/button/button-do-1.png new file mode 100644 index 0000000000..9243c7edbd Binary files /dev/null and b/docs/angular/src/content/en/images/button/button-do-1.png differ diff --git a/docs/angular/src/content/en/images/button/button-do-2.png b/docs/angular/src/content/en/images/button/button-do-2.png new file mode 100644 index 0000000000..d833307a65 Binary files /dev/null and b/docs/angular/src/content/en/images/button/button-do-2.png differ diff --git a/docs/angular/src/content/en/images/button/button-do-3.png b/docs/angular/src/content/en/images/button/button-do-3.png new file mode 100644 index 0000000000..d833307a65 Binary files /dev/null and b/docs/angular/src/content/en/images/button/button-do-3.png differ diff --git a/docs/angular/src/content/en/images/button/button-do-not-1.png b/docs/angular/src/content/en/images/button/button-do-not-1.png new file mode 100644 index 0000000000..2f37198ea3 Binary files /dev/null and b/docs/angular/src/content/en/images/button/button-do-not-1.png differ diff --git a/docs/angular/src/content/en/images/button/button-do-not-2.png b/docs/angular/src/content/en/images/button/button-do-not-2.png new file mode 100644 index 0000000000..aa39725522 Binary files /dev/null and b/docs/angular/src/content/en/images/button/button-do-not-2.png differ diff --git a/docs/angular/src/content/en/images/button/button-do-not-3.png b/docs/angular/src/content/en/images/button/button-do-not-3.png new file mode 100644 index 0000000000..473d3e6ed6 Binary files /dev/null and b/docs/angular/src/content/en/images/button/button-do-not-3.png differ diff --git a/docs/angular/src/content/en/images/qr-code/qr-code-do-not1.png b/docs/angular/src/content/en/images/qr-code/qr-code-do-not1.png new file mode 100644 index 0000000000..70764cd765 Binary files /dev/null and b/docs/angular/src/content/en/images/qr-code/qr-code-do-not1.png differ diff --git a/docs/angular/src/content/en/images/qr-code/qr-code-do-not1@2x.png b/docs/angular/src/content/en/images/qr-code/qr-code-do-not1@2x.png new file mode 100644 index 0000000000..52a584d1de Binary files /dev/null and b/docs/angular/src/content/en/images/qr-code/qr-code-do-not1@2x.png differ diff --git a/docs/angular/src/content/en/images/qr-code/qr-code-do-not2.png b/docs/angular/src/content/en/images/qr-code/qr-code-do-not2.png new file mode 100644 index 0000000000..aca377f3a3 Binary files /dev/null and b/docs/angular/src/content/en/images/qr-code/qr-code-do-not2.png differ diff --git a/docs/angular/src/content/en/images/qr-code/qr-code-do-not2@2x.png b/docs/angular/src/content/en/images/qr-code/qr-code-do-not2@2x.png new file mode 100644 index 0000000000..ef33cbe601 Binary files /dev/null and b/docs/angular/src/content/en/images/qr-code/qr-code-do-not2@2x.png differ diff --git a/docs/angular/src/content/en/images/qr-code/qr-code-do1.png b/docs/angular/src/content/en/images/qr-code/qr-code-do1.png new file mode 100644 index 0000000000..86e7240d5b Binary files /dev/null and b/docs/angular/src/content/en/images/qr-code/qr-code-do1.png differ diff --git a/docs/angular/src/content/en/images/qr-code/qr-code-do1@2x.png b/docs/angular/src/content/en/images/qr-code/qr-code-do1@2x.png new file mode 100644 index 0000000000..d512af1fc2 Binary files /dev/null and b/docs/angular/src/content/en/images/qr-code/qr-code-do1@2x.png differ diff --git a/docs/angular/src/content/en/images/qr-code/qr-code-do2.png b/docs/angular/src/content/en/images/qr-code/qr-code-do2.png new file mode 100644 index 0000000000..67f8c0c220 Binary files /dev/null and b/docs/angular/src/content/en/images/qr-code/qr-code-do2.png differ diff --git a/docs/angular/src/content/en/images/qr-code/qr-code-do2@2x.png b/docs/angular/src/content/en/images/qr-code/qr-code-do2@2x.png new file mode 100644 index 0000000000..91b49814fe Binary files /dev/null and b/docs/angular/src/content/en/images/qr-code/qr-code-do2@2x.png differ diff --git a/docs/angular/src/content/en/images/switch/switch-do-not.png b/docs/angular/src/content/en/images/switch/switch-do-not.png new file mode 100644 index 0000000000..236f605389 Binary files /dev/null and b/docs/angular/src/content/en/images/switch/switch-do-not.png differ diff --git a/docs/angular/src/content/en/images/switch/switch-do.png b/docs/angular/src/content/en/images/switch/switch-do.png new file mode 100644 index 0000000000..111adf80b9 Binary files /dev/null and b/docs/angular/src/content/en/images/switch/switch-do.png differ diff --git a/docs/angular/src/content/jp/components/ai/theming-mcp.mdx b/docs/angular/src/content/jp/components/ai/theming-mcp.mdx index 674661c15f..4eebec06dd 100644 --- a/docs/angular/src/content/jp/components/ai/theming-mcp.mdx +++ b/docs/angular/src/content/jp/components/ai/theming-mcp.mdx @@ -255,6 +255,10 @@ MCP サーバーは、プロンプトに基づいて AI が自動的に使用す 各ツールの簡単な概要を以下に示します。 + +パレットを生成する際、サーバーはサーフェス カラーとグレー カラーのコントラスト比を WCAG のしきい値と照合し、組み合わせが基準を満たさない場合は警告します。テーマ設定エンジン自体に組み込まれているコントラストの動作については、[アクセシビリティ](../themes/accessibility.mdx) を参照してください。 + + | ツール | 説明 | |------|-------------| | `detect_platform` | `package.json` を読み取り、プロジェクトが Ignite UI for Angular、Web Components、React、Blazor のいずれを使用しているかを識別します。以降のすべてのツールに対して正しいインポート パスとコンポーネント セレクターを選択します。 | diff --git a/docs/angular/src/content/jp/components/button.mdx b/docs/angular/src/content/jp/components/button.mdx deleted file mode 100644 index a3a5cfe00d..0000000000 --- a/docs/angular/src/content/jp/components/button.mdx +++ /dev/null @@ -1,784 +0,0 @@ ---- -title: Angular Button コンポーネント – Ignite UI for Angular - MITライセンス -description: Ignite UI for Angular Button コンポーネントで規格のボタンに定義済みテキスト、画像、およびその他の機能を追加します。今すぐお試しください。 -keywords: Angular Button コンポーネント, Angular Button コントロール, Ignite UI for Angular, UI コントロール, Angular ウィジェット, web ウィジェット, UI ウィジェット, Angular, ネイティブ Angular コンポーネント スイート, ネイティブ Angular コントロール, Angular UI コンポーネント -license: MIT -_language: ja -llms: - description: "Angular Button ディレクティブは、アクション可能なボタンを作成して Web ページ/アプリケーションに追加するために使用されます。" ---- - -import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; -import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; -import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; - -# Angular Button (ボタン) の概要 - -Angular Button ディレクティブは、アクション可能なボタンを作成して Web ページ/アプリケーションに追加するために使用されます。簡単にカスタマイズでき、いくつかの組み込み機能を含むさまざまな Angular Button タイプがあります。デフォルトでは、AngularMaterial はネイティブの `', - styleUrls: ['home.component.scss'], - standalone: true, - imports: [IgxButtonDirective] -}) -export class HomeComponent {} -``` - -Ignite UI for Angular Button モジュールまたはディレクティブをインポートしたので、要素で `igxButton` ディレクティブの使用を開始できます。 - -## Angular ボタン タイプ - -### Flat ボタン - - ディレクティブを使用して、シンプルなフラット ボタンをコンポーネント テンプレートに追加します。タイプを選択しない場合、デフォルト値は `flat` です。 - -```html - -``` - - - -このコンポーネントはマテリアル アイコンを使用します。`index.html` に次のリンクを追加してください: `` - - - - -### Contained ボタン - -Contained ボタンを作成するには、`igxButton` プロパティの値を変更するだけです。 - -```html - -``` - - - -### Outlined ボタン - -同様に、アウトライン タイプに切り替えることができます。 - -```html - -``` - - - -### Icon ボタン - -バージョン `17.1.0` 以降、IgniteUI for Angular は、アイコンを完全に機能するボタンに変えることを目的とした新しい `igxIconButton` ディレクティブを公開します。_Icon Button_ の詳細については[こちら](/icon-button)を参照してください。 - -```html - -``` - - - -### FAB (フローティング アクション ボタン) - -アイコンを使用して、フローティング アクション ボタンを作成します。 - -```html - -``` - -拡張 FAB を作成するには、`igx-icon` の前に任意の要素を追加できます。 - -```html - -``` - - -拡張 FAB テキストを適切にスタイルするには、`` または `
` タグを使用します。 - - - - -## 例 - -### Angular ボタンの無効化 - -ボタンを無効にするには、`disabled` プロパティを使用します。 - -```html - -``` - - - -### Ripple - - ディレクティブは、ボタンまたはその他の指定した要素にリップル効果を追加します。`以下のプロパティを使用して、デフォルトのリップル色、位置、および期間を簡単に変更できます。 - -```html - -``` - - - -### Span - -`span` や `div` などの要素を Ignite UI for Angular スタイルのボタンに変更するために `igxButton` ディレクティブを使用できます。デフォルトの色は `igxButtonColor` と `igxButtonBackground` プロパティでカスタマイズできます。 - -```html - - Span - -``` - - - -## サイズ - -`--ig-size` カスタム CSS プロパティを使用して、ユーザーが `igxButton` のサイズを選択できるようにすることができます。これを行うには、まず `IgxButtonGroupModule` をインポートし、 コンポーネントによってサイズ値を表示する必要があります。このようにして、選択されるたびに **--ig-size** CSS プロパティを更新します。 - -```typescript -// app.module.ts -... -import { IgxButtonGroupModule } from 'igniteui-angular/button-group'; -// import { IgxButtonGroupModule } from '@infragistics/igniteui-angular'; for licensed package -@NgModule({ - imports: [ - ... - IgxButtonGroupModule - ... - ] -}) -``` - -```html - - -... - -``` - -```typescript -// buttons-density.component.ts -public size = "large"; -public sizes; -public ngOnInit() { - this.sizes = [ - { label: 'large', selected: this.size === 'large', togglable: true }, - { label: 'medium', selected: this.size === 'medium', togglable: true }, - { label: 'small', selected: this.size === 'small', togglable: true } - ]; -} - -public selectSize(event: any) { - this.size = this.sizes[event.index].label; -} - -@HostBinding('style.--ig-size') -protected get sizeStyle() { - return `var(--ig-size-${this.size})`; -} -``` - -以下は結果です。 - - - -
- -## スタイル設定 - -### Button テーマのプロパティ マップ - -プライマリ プロパティを変更すると、関連するすべての依存プロパティが自動的に更新されます。 - -
- - - - - - - - - -
- -
- -### Material Theme - -#### Flat Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | - -#### Contained Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-background | Focus background color | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $active-background | Active background color | -| | $active-foreground | Active foreground color | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | - -#### Outlined Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $border-color | The border color for outlined buttons. | -| | $hover-border-color | The border color for hovered outlined buttons. | -| | $focus-border-color | The border color for focused outlined buttons. | -| | $focus-visible-border-color | The border color for outlined buttons when focus is visible. | -| | $active-border-color | The border color for active outlined buttons. | - -#### FAB Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-background | Focus background color | -| | $focus-foreground | Foreground on focus | -| | $active-background | Active background color | -| | $active-foreground | Active foreground color | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | - -
- -
- -### Fluent Theme - -#### Flat Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | - -#### Contained Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $active-foreground | Active foreground color | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | - -#### Outlined Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered outlined button. | -| | $focus-background | Background color for focused outlined button. | -| | $focus-hover-background | Background color for outlined button on focus + hover. | -| | $active-background | Background color for active outlined button. | -| | $hover-foreground | Foreground color for hovered outlined button. | -| | $icon-color-hover | Icon color for hovered outlined button. | -| | $focus-foreground | Foreground color for focused outlined button. | -| | $focus-hover-foreground | Foreground color for outlined button on focus + hover. | -| | $active-foreground | Foreground color for active outlined button. | -| | $focus-visible-foreground | Foreground color for outlined button when focus is visible. | -| | $focus-visible-border-color | Border color for outlined button when focus is visible. | -| | $border-color | Border color for outlined button. | -| | $hover-border-color | Border color for hovered outlined button. | -| | $focus-border-color | Border color for focused outlined button. | -| | $active-border-color | Border color for active outlined button. | - -#### FAB Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $active-background | Active background color | -| | $active-foreground | Active foreground color | -| | $focus-background | Focus background color | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | - -
- -
- -### Bootstrap Theme - -#### Flat Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | -| | $disabled-foreground | Foreground color for disabled button | -| | $disabled-icon-color | Icon color for disabled button | -| | $shadow-color | Shadow color | - -#### Contained Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $active-foreground | Active foreground color | -| | $shadow-color | Shadow color | -| | $disabled-background | Disabled background color | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | - -#### Outlined Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | -| | $disabled-foreground | Foreground color for disabled button | -| | $disabled-icon-color | Icon color for disabled button | -| | $disabled-border-color | Border color for disabled button | -| | $hover-border-color | Hover border color | -| | $focus-border-color | Focus border color | -| | $active-border-color | Active border color | -| | $shadow-color | Shadow color | - -#### FAB Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $disabled-background | Disabled background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $active-foreground | Active foreground color | -| | $shadow-color | Shadow color | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | - -
-ボタンにスタイルを設定する別の方法は、**Sass** とタイプ別テーマ関数を使用することです。、、、および 。 - -それぞれは、特定のタイプのボタンのみをターゲットにします。 -
- -### Indigo Theme - -#### Flat Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | -| | $shadow-color | Shadow color | - -#### Contained Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $active-foreground | Active foreground color | -| | $shadow-color | Shadow color | -| | $disabled-background | Disabled background color | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | - -#### Outlined Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$foreground** | $hover-background | Background color for hovered button | -| | $focus-background | Background color for focused button | -| | $focus-hover-background | Background color for button on focus + hover | -| | $active-background | Background color for active button | -| | $hover-foreground | Foreground color for hovered button | -| | $icon-color-hover | Icon color for hovered button | -| | $focus-foreground | Foreground color for focused button | -| | $focus-hover-foreground | Foreground color for button on focus + hover | -| | $active-foreground | Foreground color for active button | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $focus-visible-border-color | Border color when focus is visible | -| | $border-color | Border color | -| | $hover-border-color | Hover border color | -| | $focus-border-color | Focus border color | -| | $active-border-color | Active border color | -| | $shadow-color | Shadow color | - -#### FAB Button - -| Primary Property | Dependent Property | Description | -|:--|:--|:--| -| **$background** | $foreground | Foreground based on background | -| | $icon-color | Icon color based on background | -| | $hover-background | Hover background color | -| | $focus-background | Focus background color | -| | $active-background | Active background color | -| | $disabled-background | Disabled background color | -| | $hover-foreground | Foreground on hover | -| | $icon-color-hover | Icon color on hover | -| | $focus-foreground | Foreground on focus | -| | $focus-hover-background | Focus + hover background | -| | $focus-hover-foreground | Foreground on focus + hover | -| | $focus-visible-background | Background when focus is visible | -| | $focus-visible-foreground | Foreground when focus is visible | -| | $active-foreground | Active foreground color | -| | $shadow-color | Shadow color | -| | $disabled-foreground | Disabled foreground color | -| | $disabled-icon-color | Disabled icon color | - -
- -
- -
- - -> **注:** 結果の依存プロパティは、選択したテーマ (Material、Fluent、Bootstrap、Indigo) によって若干異なる場合があります。 - -ボタンのスタイルを設定するには、タイプ固有のテーマ関数を使用できます: 、、、および 。 - -各関数は、特定のタイプのボタンのみをターゲットにします。 - -まず、すべてのテーマ関数とコンポーネント ミックスインを含む themes モジュールをインポートします。 - -```scss -@use "igniteui-angular/theming" as *; - -// IMPORTANT: Prior to Ignite UI for Angular version 13 use: -// @import '~igniteui-angular/lib/core/styles/themes/index'; -``` - -次に、スタイル設定するボタンのタイプ固有のテーマ機能を拡張する新しいテーマを作成します。この例では、 関数を使用し、`$foreground` および `$background` パラメーターに、それぞれの hover および active パラメーターとともに値を渡します。 - -次のマークアップを前提として: - -```html -
- -
-``` - -次のテーマを作成する必要があります: - -```scss -$custom-contained-theme: contained-button-theme( - $background: #f9f0ff, - $foreground: #722ed1, - $hover-background: #efdbff, - $hover-foreground: #9254de, - $active-foreground: #531dab, - $active-background: #dfc2fa, -); -``` - -contained タイプのボタンのスタイル設定に使用できるパラメーターの完全なリストについては、 セクションを参照してください。 - -最後に、カスタム テーマをアプリケーションに**含めます**。 - -```scss -.my-contained-btn { - @include tokens($custom-contained-theme); -} -``` - -タイプ別テーマ関数により、ボタンのスタイリングがより簡単になりました。 - - 関数と 関数の場合、`$background` パラメーターに色の値を指定するだけで済みます。他のすべてのボタンの状態とテキストの色 (指定されていない場合) は、その値に基づいて自動的に生成され、適用されます。 - -テキストの色は、新しく追加された 関数によって、指定された背景に対して黒か白のどちらがより良いコントラストを持つかを計算して決定されます。 - - および では、状態用の色も自動的に生成されますが、これらは `$background` ではなく `$foreground` パラメーターに基づいて計算されます。 - -以下のサンプルでは、カスタマイズした CSS 変数を使用したボタン コンポーネントが、[`Ant`](https://ant.design/components/button?theme=light#button-demo-color-variant) デザイン システムのボタンに視覚的に似たデザインを実現している様子を確認できます。 - - - - -サンプルでは、[Bootstrap Light](/themes/sass/schemas#predefined-schemas) スキーマを使用します。 - - -### Tailwind によるスタイル設定 - -カスタム Tailwind ユーティリティ クラスを使用して `button` をスタイル設定できます。まず [Tailwind を設定して](/themes/misc/tailwind-classes)ください。 - -グローバル スタイルシートに Tailwind をインポートした上で、以下のように必要なテーマ ユーティリティを適用します: - -```scss -@import "tailwindcss"; -... -@use 'igniteui-theming/tailwind/utilities/material.css'; -``` - -ユーティリティ ファイルには、`light` テーマと `dark` テーマの両方のバリエーションが含まれています。 - -- `light-*` クラスはライト テーマ用です。 -- `dark-*` クラスはダーク テーマ用です。 -- プレフィックスの後にコンポーネント名を追加します。 ボタンにはタイプがあるため、クラスは次のように使用されます: `light-contained-button`、`light-flat-button`、`dark-outlined-button`、`dark-fab-button`。 - -これらのクラスを適用すると、動的なテーマの計算が可能になります。そこから、`任意のプロパティ`を使用して、生成された CSS 変数をオーバーライドできます。コロンの後に、有効な CSS カラー形式 (HEX、CSS 変数、RGB など) を指定します。 - -プロパティの完全なリストは で確認できます。これはさまざまなバリエーションで異なって反映されます。`flat` ボタンと `outlined` ボタンの主なプロパティは `$foreground` で、`contained` ボタンと `fab` ボタンの主なプロパティは `$background` です。構文は次のとおりです: - -```html -
-
- -
-
- -
-
- -
-
- -
-
-``` - - -ユーティリティ クラスが優先されるようにするには、感嘆符 (`!`) が必要です。Tailwind はスタイルをレイヤーに適用しますが、これらのスタイルを重要としてマークしないと、コンポーネントのデフォルトのテーマによってオーバーライドしてしまいます。 - - -最終的に、button は次のようになります: - - - -### カスタム サイズ変更 - -ボタンの高さは、`--size` 変数を使用して、`button` を直接ターゲットにして変更できます。 - -```scss -button { - --size: 50px; -} -``` - -または、ユニバーサル変数 `--ig-button-size` を使用して、すべてのインスタンスをターゲットにすることもできます。 - -```html -
- -
-``` - -```scss -.my-app { - --ig-button-size: 50px; -} -``` - -事前定義されたサイズの 1 つを使用して、それを `--ig-size` 変数に割り当てることもできます。`--ig-size` に使用可能な値は、`--ig-size-small`、`--ig-size-medium`、`--ig-size-large` です。 - -```scss -button { - --ig-size: var(--ig-size-large); -} -``` - -詳細については、[サイズ](/display-density)の記事をご覧ください。 - -
- -## API リファレンス - -
- -- -- -- -- -- - -## その他のリソース - -
- -コミュニティに参加して新しいアイデアをご提案ください。 - -- [Ignite UI for Angular **フォーラム** (英語)](https://www.infragistics.com/community/forums/f/ignite-ui-for-angular) -- [Ignite UI for Angular **GitHub** (英語)](https://github.com/IgniteUI/igniteui-angular) diff --git a/docs/angular/src/content/jp/components/chat.mdx b/docs/angular/src/content/jp/components/chat.mdx index 49c10daabf..8c7e73e56e 100644 --- a/docs/angular/src/content/jp/components/chat.mdx +++ b/docs/angular/src/content/jp/components/chat.mdx @@ -86,13 +86,27 @@ Chat コンポーネントは、その状態と構成を制御できるいくつ | 名前 | 説明 | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `messages` | チャットに表示されるメッセージ (`IgcChatMessage[]`) の配列。表示するメッセージを制御するためにバインド可能。 | +| `messages` | チャットに表示される双方向のメッセージ (`IgcChatMessage[]`) の配列。ユーザーがメッセージを送信すると、Chat は渡されたコレクションを更新します。 | | `draftMessage` | 未送信メッセージ。`text` とオプションの `attachments` を含むオブジェクト。メッセージ下書きの保存や復元に便利。 | | `options` | 現在のユーザー ID、入力プレースホルダー、許可されるファイル タイプ、クイック リプライサジェスト、入力遅延、カスタム レンダラーなどのチャット設定 ()。 | | `templates` | メッセージ コンテンツ、入力、添付ファイル、その他のチャット UI 部分に対して、カスタム Angular テンプレート()。 | 上記のプロパティを使用することで、Chat の UI をアプリケーションの状態やバックエンドと簡単に同期させることができます。 +#### 双方向のメッセージ コレクション + +`messages` コレクションは双方向です。アプリケーションが表示するメッセージを提供し、会話が進むにつれて Chat が元のコレクションを更新します。ユーザーがメッセージを送信すると、そのコレクションへの参照を保持しているコードから、新しく作成されたメッセージにアクセスできます。これは、Angular の `[(messages)]` による双方向バインディングではなく、コレクションのインプレース更新です。 + +`messageCreated` イベントは、永続化やその他の副作用のための通知です。作成されたメッセージをコレクションに再度追加しないでください。 + +元のコレクションを変更せずに残す必要がある場合は、シャロー コピーを Chat に渡します。 + +```ts +public messages = [...this.originalMessages]; +``` + +既存のメッセージ オブジェクトは引き続き共有されます。これらのオブジェクトも独立させる必要がある場合は、コピーしたコレクションを構築する際に、各メッセージの新しいインスタンスを作成してください。 + ### 添付 モダンな会話ではテキストだけに限られません。Chat コンポーネントはファイル添付機能のサポートが組み込まれており、ユーザーは画像、ドキュメント、その他のファイルを共有できます。 デフォルトでは入力領域に添付ボタンが表示されます。`acceptedFiles` プロパティで許可されるファイル タイプを制御可能です。 diff --git a/docs/angular/src/content/jp/components/combo.mdx b/docs/angular/src/content/jp/components/combo.mdx index ff69547b1f..b8e947090d 100644 --- a/docs/angular/src/content/jp/components/combo.mdx +++ b/docs/angular/src/content/jp/components/combo.mdx @@ -5,7 +5,7 @@ keywords: angular combobox, angular combo コンポーネント, angular combobo license: MIT _language: ja llms: - description: "Angular ComboBox コンポーネントは、編集可能な機能を提供するドロップダウン リストを表し、ユーザーが事前定義されたリストからオプションを選択できるようにします。" + description: "Angular ComboBox コンポーネントは、編集可能な機能を提供するドロップダウン リストを表し、ユーザーが事前定義されたリストから複数のオプションを選択できるようにします。" --- import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; @@ -14,11 +14,11 @@ import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; # Angular ComboBox (コンボボックス) コンポーネントの概要 -Angular ComboBox コンポーネントは、編集可能な機能を提供するドロップダウン リストを表し、ユーザーが事前定義されたリストからオプションを選択できるようにします。Ignite UI for Angular ComboBox コンポーネントは、フィルタリング機能、項目の選択、グループ化、ドロップダウン リストにカスタム値の追加などの機能をサポートします。HTML select タグの代わりに使用でき、データ バインディング (ローカルおよびリモート)、フィルタリング、グループ化、カスタム テンプレート、カスタム値など、すぐに使用できる機能がいくつかあります。 +Angular ComboBox コンポーネントは、編集可能な機能を提供するドロップダウン リストを表し、ユーザーが事前定義されたリストから複数のオプションを選択できるようにします。Ignite UI for Angular ComboBox コンポーネントは、フィルタリング機能、グループ化、ドロップダウン リストへのカスタム値の追加などの機能も提供します。HTML select タグの代わりに使用でき、データ バインディング (ローカルおよびリモート)、フィルタリング、グループ化、項目、ヘッダー、フッターのカスタム テンプレート、カスタム値など、すぐに使用できる機能がいくつかあります。 ## Angular ComboBox の例 -この Angular ComboBox の例では、ユーザーが項目をフィルターし、提供されたデータを使用して選択を実行する方法を表します。さらに、ComboBox は、キーボード ナビゲーションとカスタム スタイル設定機能を公開します。 +この Angular ComboBox の例では、ユーザーが項目をフィルターし、提供されたデータを使用して選択を実行する方法を確認できます。さらに、ComboBox は、キーボード ナビゲーションとカスタム スタイル設定機能を公開します。 @@ -27,7 +27,8 @@ Angular ComboBox コンポーネントは、編集可能な機能を提供する ## Angular ComboBox 機能 コンボボックス コントロールは以下の機能を公開します。 -- データ バインディング- ローカル データおよび[リモート データ](/combo-remote) + +- データ バインディング - ローカル データおよび[リモート データ](/combo-remote) - [値バインディング](/combo-features#データ-バインディング) - [フィルタリング](/combo-features#フィルタリング) - [グループ化](/combo-features#グループ化) @@ -35,14 +36,6 @@ Angular ComboBox コンポーネントは、編集可能な機能を提供する - [テンプレート](/combo-templates) - [テンプレート駆動フォーム](/input-group)および[リアクティブ フォーム](/angular-reactive-form-validation)との統合 -- Data Binding - local data and [remote data](/combo-remote) -- [Value Binding](/combo-features#data-binding) -- [Filtering](/combo-features#filtering) -- [Grouping](/combo-features#grouping) -- [Custom Values](/combo-features#custom-values) -- [Templates](/combo-templates) -- Integration with [Template Driven Forms](/input-group) and [Reactive Forms](/angular-reactive-form-validation) - ## Ignite UI for Angular ComboBox を使用した作業の開始 Ignite UI for Angular ComboBox コンポーネントを使用した作業を開始するには、Ignite UI for Angular をインストールする必要があります。既存の Angular アプリケーションで、以下のコマンドを入力します。 @@ -111,7 +104,7 @@ export class ComboDemo implements OnInit { } ``` -コンボボックスは都市の配列にバインドされましたが、項目のテキストにどのプロパティを使用するか、値にどのプロパティを使用するかをコンポーネントにまだ伝えていません。実際に変更してみましょう。 +コンボボックスは都市の配列にバインドされましたが、項目のテキストにどのプロパティを使用するか、値にどのプロパティを使用するかをコンポーネントにまだ伝えていません。それでは設定してみましょう。 ### データ値と表示プロパティ @@ -120,7 +113,7 @@ export class ComboDemo implements OnInit { - `valueKey` - **オプション、オブジェクト配列に推奨。** - コンボボックスの選択のために保存されるデータ エントリのプロパティを指定します。`valueKey` が省略された場合、コンボボックス値はデータ エントリへの参照を使用します (選択は `igxCombo.data` からのエントリの配列になります)。 - `displayKey` - **オブジェクト配列に必須。** - アイテムのテキストに使用するプロパティを指定します。`displayKey` に値が指定されていない場合、コンボボックスは指定された `valueKey` (存在する場合) を使用します。 -この例では、コンボボックスに各都市の `name` を表示し、コンボボックス値には各都市の `id` を格納します。格納するには、これらのプロパティをコンボボックスの`displayKey` と `valueKey` にそれぞれ提供します。 +この例では、コンボボックスに各都市の `name` を表示し、コンボボックス値には各都市の `id` を格納します。そのため、これらのプロパティをコンボボックスの `displayKey` と `valueKey` にそれぞれ指定します。 ```html @@ -132,9 +125,9 @@ export class ComboDemo implements OnInit { ### 双方向バインディング -コンボボックス コンポーネントは、`[(ngModel)]` との双方向のデータ バインディングを完全にサポートし、[テンプレート駆動型](https://angular.io/guide/forms)および[リアクティブ型](https://angular.io/guide/reactive-forms)での使用もサポートします。コンボボックス選択には、双方向バインディングまたは[選択 API](#選択-api)を使用してアクセスできます。コンボボックスの選択項目 (`valueKey` に基づく) と同じタイプの項目の配列を渡すことができ、いずれかが変更されるたびに、他方がそれに応じて更新されます。 +コンボボックス コンポーネントは、`[(ngModel)]` との双方向のデータ バインディングを完全にサポートし、[テンプレート駆動](https://angular.io/guide/forms)フォームおよび[リアクティブ](https://angular.io/guide/reactive-forms)フォームでの使用もサポートします。コンボボックス選択には、双方向バインディングまたは[選択 API](#選択-api)を使用してアクセスできます。コンボボックスの選択項目 (`valueKey` に基づく) と同じタイプの項目の配列を渡すことができ、いずれかが変更されるたびに、他方がそれに応じて更新されます。 -以下の例は、cities の Sofia と London があらかじめ選択済みになります。コンボボックスの選択におけるそれ以上の変更は、`selectedCities` 配列に反映されます。 +以下の例では、都市 Sofia と London が最初に選択されます。コンボボックスの選択に対するその後の変更は、`selectedCities` 配列に反映されます。 ```html @@ -166,7 +159,7 @@ export class MyCombo { コンボボックス コンポーネントは、コントロールの現在の選択状態を取得および操作できる API を公開します。 -コンボボックスの選択を取得する 1 つの方法は、 プロパティを使用することです。指定された [valueKey](#data-value-and-display-properties) (存在する場合) に応じて、選択された項目に対応する値の配列を返します。 +コンボボックスの選択を取得する 1 つの方法は、 プロパティを使用することです。指定された [valueKey](#データ値と表示プロパティ) (存在する場合) に応じて、選択された項目に対応する値の配列を返します。 例では、`selection` は選択された都市の `id` の配列を返します。 @@ -177,7 +170,7 @@ export class MyCombo { } ``` -選択 API を使用すると、コントロールのユーザー操作なしで、コンボボックスの選択された項目を変更できます - ボタン クリックを介して、Observable 変更への応答としてなどです。たとえば、 メソッドを使用して複数の都市を選択するボタンを実装できます。 +選択 API を使用すると、ボタンのクリックや Observable の変更への応答などにより、ユーザーがコントロールを操作しなくても、コンボボックスの選択された項目を変更できます。たとえば、 メソッドを使用して複数の都市を選択するボタンを実装できます。 ```html @@ -197,7 +190,7 @@ export class MyExampleCombo { } ``` -また、コンボボックスは、選択が変更されるたびにイベントを発生させます - 。発行されたイベント引数 には、変更前の選択、現在の選択、追加または削除された項目に関する情報が含まれています。また、イベントをキャンセルして、新しいアイテムの配列で選択を更新できないようにすることもできます。 +また、コンボボックスは、選択が変更されるたびに イベントを発生させます。発行されたイベント引数 には、変更前の選択、現在の選択、追加または削除された項目に関する情報が含まれています。また、イベントをキャンセルして、新しいアイテムの配列で選択を更新できないようにすることもできます。 イベントへのバインドは、`igx-combo` タグの適切な `@Output` プロパティを介して実行できます。 @@ -207,7 +200,7 @@ export class MyExampleCombo { ``` -以下の例では、都市が選択に追加または選択から削除されると、統計の可視化を更新するハンドラーが発生します。 +以下の例では、都市が選択に追加または選択から削除されると、統計の可視化を更新するハンドラーが呼び出されます。 ```typescript export class MyExampleCombo { @@ -223,7 +216,7 @@ export class MyExampleCombo { } ``` -また、コンボボックスは、選択が確定されてコンポーネントの状態が更新された後に イベントを発生させます。発行されたイベント引数 には、以前の選択、現在の選択、および追加または削除されたアイテム に関する情報が含まれています。`selectionChanging` とは異なり、このイベントはキャンセル不可であり、最終的に確定した選択の状態を反映することが保証されています。コンボボックスが `ngModel` や Angular フォームとともに使用される場合、`selectionChanged` は値変更コールバックが呼び出された後に発行されます。 +また、コンボボックスは、選択が確定されてコンポーネントの状態が更新された後に イベントを発生させます。発行されたイベント引数 には、以前の選択、現在の選択、および追加または削除されたアイテムに関する情報が含まれています。`selectionChanging` とは異なり、このイベントはキャンセル不可であり、最終的に確定した選択の状態を反映することが保証されています。コンボボックスが `ngModel` や Angular フォームとともに使用される場合、`selectionChanged` は値変更コールバックが呼び出された後に発行されます。 イベントへのバインドは、`igx-combo` タグの適切な `@Output` プロパティを介して行うことができます。 @@ -270,13 +263,14 @@ public singleSelection(event: IComboSelectionChangingEventArgs) { } ``` -> 注: igxCombo を変更する代わりに、[igxSimpleCombo](/simple-combo) を使用することをお勧めします (上記を参照)。 +> 注: 上記のように igxCombo を変更する代わりに、[igxSimpleCombo](/simple-combo) を使用することをお勧めします。
## キーボード ナビゲーション -コンボボックスを閉じてフォーカスされている場合: +コンボボックスが閉じていてフォーカスがある場合: + - `下矢印`または `Alt` キー + `下矢印`はコンボボックス ドロップダウンを開き、検索入力にフォーカスを移動します。 - `Esc` キーは、コンボボックスにフォーカスを保持したまま、選択された値をクリアします。 @@ -290,6 +284,7 @@ public singleSelection(event: IComboSelectionChangingEventArgs) { - `Tab` キーは、リストを閉じて次のフォーカス可能な要素にフォーカスを移動します。 コンボボックスを開いて検索入力にフォーカスがある場合: + - `上矢印`または `Alt` キー + `上矢印`はコンボボックス ドロップダウンを閉じ、フォーカスを閉じたコンボボックスに移動します。 - `下矢印`は、フォーカスを検索入力から最初のリスト項目に移動します。リストが空でカスタム値が有効な場合、新しい項目の追加ボタンに移動します。 @@ -299,6 +294,7 @@ public singleSelection(event: IComboSelectionChangingEventArgs) { コンボボックスを開いてリスト項目にフォーカスがある場合: + - `下矢印`は次のリスト項目に移動します。アクティブな項目がリストの最後の項目で、カスタム値が有効な場合、フォーカスは [項目の追加] ボタンに移動します。 - `上矢印`は前のリスト項目に移動します。アクティブな項目がリストの最初の項目である場合、フォーカスは検索入力に戻ります。 @@ -311,17 +307,11 @@ public singleSelection(event: IComboSelectionChangingEventArgs) { - `Enter` キーはすでに選択した項目を確定し、リストを閉じます。 -コンボボックスを開くと、カスタム値が有効になり、項目の追加ボタンがフォーカスされます。 +コンボボックスが開いていて、カスタム値が有効で、項目の追加ボタンにフォーカスがある場合: - `Enter` キーは、検索入力のテキストと等しい `valueKey` と `displayKey` を持つ新しい項目を追加し、その項目を選択します。 -- `上矢印` - フォーカスは最後のリスト項目に戻るか、あるいはリストが空の場合、検索入力に移動します。 - -When combobox is opened, allow custom values are enabled and add item button is focused: - -- `Enter` will add a new item with `valueKey` and `displayKey` equal to the text in the search input and will select the new item. - -- `ArrowUp` focus will be moved back to the last list item or if the list is empty, will be moved to the search input. +- `上矢印`は、フォーカスを最後のリスト項目に戻します。リストが空の場合は、検索入力に移動します。 ## スタイル設定 @@ -329,19 +319,19 @@ When combobox is opened, allow custom values are enabled and add item button is プライマリ プロパティを変更すると、関連するすべての依存プロパティが自動的に更新されます。 -| Primary Property | Dependent Property | Description | +| プライマリ プロパティ | 依存プロパティ | 説明 | | --- | --- | --- | -| **$empty-list-background** | $empty-list-placeholder-color | The combo placeholder text color. | -| **$toggle-button-background** | $toggle-button-foreground | The combo toggle button foreground color. | -| | $toggle-button-background-focus | The combo toggle button background color when focused. | -| | $toggle-button-background-focus--border | The combo toggle button background color when focused (border variant). | -| | $toggle-button-foreground-filled | The combo toggle button foreground color when filled. | -| | $toggle-button-background-disabled | The combo toggle button background color when disabled. | -| | $toggle-button-foreground-disabled | The combo toggle button foreground color when disabled. | -| **$toggle-button-background-focus** | $toggle-button-foreground-focus | The combo toggle button foreground color when focused. | -| **$clear-button-background-focus** | $clear-button-foreground-focus | The combo clear button foreground color when focused. | - -[`Ignite UI for Angular テーマ`](themes/index.mdx)を使用して、コンボボックスの外観を変更できます。はじめに、テーマ エンジンによって公開されている関数を使用するために、スタイル ファイルに `index` ファイルをインポートする必要があります。 +| **$empty-list-background** | $empty-list-placeholder-color | コンボのプレースホルダーのテキストの色 | +| **$toggle-button-background** | $toggle-button-foreground | コンボのトグル ボタンの前景色 | +| | $toggle-button-background-focus | フォーカス時のコンボのトグル ボタンの背景色 | +| | $toggle-button-background-focus--border | フォーカス時のコンボのトグル ボタンの背景色 (border バリアント) | +| | $toggle-button-foreground-filled | 入力済みのコンボのトグル ボタンの前景色 | +| | $toggle-button-background-disabled | 無効時のコンボのトグル ボタンの背景色 | +| | $toggle-button-foreground-disabled | 無効時のコンボのトグル ボタンの前景色 | +| **$toggle-button-background-focus** | $toggle-button-foreground-focus | フォーカス時のコンボのトグル ボタンの前景色 | +| **$clear-button-background-focus** | $clear-button-foreground-focus | フォーカス時のコンボのクリア ボタンの前景色 | + +[`Ignite UI for Angular テーマ`](themes/index.mdx)を使用して、コンボボックスの外観を大幅に変更できます。はじめに、テーマ エンジンによって公開されている関数を使用するために、スタイル ファイルに `index` ファイルをインポートする必要があります。 ```scss @use "igniteui-angular/theming" as *; @@ -350,7 +340,7 @@ When combobox is opened, allow custom values are enabled and add item button is // @import '~igniteui-angular/lib/core/styles/themes/index'; ``` -最もシンプルな方法として、 を拡張する新しいテーマを作成します。`$toggle-button-background` を設定することで、新しいテーマがボタンに対する状態色や前景の色を自動的に決定します。必要に応じて、`$search-separator-border-color` などの追加パラメーターを指定することも可能です。 +最もシンプルな方法として、 を拡張する新しいテーマを作成します。`$toggle-button-background` を設定することで、テーマがボタンに適した状態の色とコントラストのある前景色を自動的に決定します。必要に応じて、`$search-separator-border-color` などの追加パラメーターを指定することも可能です。 ```scss $custom-combo-theme: combo-theme( @@ -359,7 +349,7 @@ $custom-combo-theme: combo-theme( ); ``` - は、項目コンテナーとして を内部使用します。 および コンポーネントも含まれます。これらのコンポーネントのテーマを拡張する新しいテーマを作成し、それぞれのクラスの下にスコープすることで、コンボボックスのスタイル設定を変更できます。 + は、項目コンテナーとして を内部使用します。 および コンポーネントも含まれます。これらのコンポーネントのテーマを拡張する新しいテーマを作成し、それぞれのクラスの下にスコープすることで、コンボボックスのスタイル設定を変更できます。 ```scss $custom-drop-down-theme: drop-down-theme( @@ -384,7 +374,9 @@ $custom-checkbox-theme: checkbox-theme( ``` - は、[`IgxOverlay`](/overlay) サービスを使用して、コンボボックス項目のリスト コンテナーを保持および表示します。スタイルを適切にスコープするには、 を使用してください。詳細については、[`IgxOverlay スタイル ガイド`](/overlay-styling)を確認してください。また、コンポーネントのスタイルを設定するときに `::ng-deep` を使用する必要があります。 + は、[`IgxOverlay`](/overlay) サービスを使用してリストを表示します。表示のカプセル化 (View Encapsulation) の設定や、生成されるセレクターが一致する必要がある場所によっては、ローカルでのテーマの include に引き続き `::ng-deep` が必要になる場合があります。また、デフォルトのデタッチされたアウトレットにアタッチされたリストは、コンボのホストからスタイルを継承できません。テーマを適用したコンテナーの下に を構成するか、アウトレットに一致するセレクターからテーマを出力してください。詳細については、[`IgxOverlay スタイル ガイド`](/overlay-styling)を参照してください。 +[!Note] +`IgxCombo` のデフォルトの `type` は `box` です。これは、デフォルトが `line` である [`IgxSelect`](/select) とは異なります。 ### デモ @@ -424,7 +416,7 @@ class="!light-combo ``` -ユーティリティ クラスが優先されるようにするには、感嘆符 (`!`) が必要です。Tailwind はスタイルをレイヤーに適用しますが、これらのスタイルを重要としてマークしないと、コンポーネントのデフォルトのテーマによってオーバーライドしてしまいます。 +ユーティリティ クラスが優先されるようにするには、感嘆符 (`!`) が必要です。Tailwind はスタイルをレイヤーに適用しますが、これらのスタイルを重要としてマークしないと、コンポーネントのデフォルトのテーマによってオーバーライドされてしまいます。 最終的に、combo は次のようになります: @@ -433,12 +425,12 @@ class="!light-combo ## 既知の問題 -- 選択した項目を表示するコンボボックス入力は編集できません。ただし、IE および FireFox のブラウザー仕様により、カーソルは表示されます。 +- 選択した項目を表示するコンボボックス入力は編集できません。ただし、FireFox のブラウザー仕様により、カーソルは表示されます。 - コンボボックスが `undefined` (例: `[ undefined, ...]`) を含むプリミティブ データの配列にバインドされる場合、`undefined` はドロップダウンに表示されません。複合データ (オブジェクトなど) の配列にバインドされ、`valueKey` に使用される値が `undefined` の場合、項目はドロップダウンに表示されますが、選択はできません。 - コンボボックスがリモート サービスにバインドされ、定義済みの選択がある場合、要求されたデータが読み込まれるまでその入力は空白のままになります。 -コンボボックスは内部で `igxForOf` ディレクティブを使用するため、すべての `igxForOf` の制限がコンボボックスで有効です。詳細については、[`igxForOf 既知の制限`](/for-of#既知の制限)セクションを参照してください。 +コンボボックスは内部でリストの仮想化に [Virtual Scroll](./layouts/virtual-scroll.mdx) コンポーネントを使用するため、すべての Virtual Scroll の制限がコンボボックスで有効です。詳細については、[Virtual Scroll の既知の制限](./layouts/virtual-scroll.mdx#既知の制限)セクションを参照してください。 ## API リファレンス @@ -465,7 +457,7 @@ class="!light-combo
-- [コンボボックス機能](/combo-features#data-binding) +- [コンボボックス機能](/combo-features) - [コンボボックス リモート バインディング](/combo-remote) - [コンボボックス テンプレート](/combo-templates) - [テンプレート駆動フォームの統合](/input-group) diff --git a/docs/angular/src/content/jp/components/dialog.mdx b/docs/angular/src/content/jp/components/dialog.mdx index aee2c5d934..127c67742e 100644 --- a/docs/angular/src/content/jp/components/dialog.mdx +++ b/docs/angular/src/content/jp/components/dialog.mdx @@ -288,7 +288,7 @@ $my-dialog-theme: dialog-theme( ``` -ダイアログ ウィンドウのコンテンツの一部として使用される追加コンポーネント ([`IgxButton`](/button) など) をスタイルするには、それぞれのコンポーネントに固有の追加テーマを作成し、ダイアログ ウィンドウのスコープ内のみに配置する必要があります (残りのアプリケーションの影響を受けません)。 +ダイアログ ウィンドウのコンテンツの一部として使用される追加コンポーネント ([`IgxButton`](./inputs/button.mdx) など) をスタイルするには、それぞれのコンポーネントに固有の追加テーマを作成し、ダイアログ ウィンドウのスコープ内のみに配置する必要があります (残りのアプリケーションの影響を受けません)。 ```scss diff --git a/docs/angular/src/content/jp/components/drop-down-virtual.mdx b/docs/angular/src/content/jp/components/drop-down-virtual.mdx index e7904b73c2..10559c02ec 100644 --- a/docs/angular/src/content/jp/components/drop-down-virtual.mdx +++ b/docs/angular/src/content/jp/components/drop-down-virtual.mdx @@ -1,11 +1,11 @@ --- -title: ドロップダウン コンポーネント | MITライセンス -description: Angular 仮想化 Drop Down の Ignite UI を使用して、単一の項目選択をサポートする非常に大きな項目のリストを表示します。 -keywords: Ignite UI for Angular, UI コントロール, Angular ウィジェット, web ウィジェット, UI ウィジェット, Angular, ネイティブ Angular コンポーネント スイート, ネイティブ Angular コントロール, ネイティブ Angular コンポーネント ライブラリ, Angular Drop Down コンポーネント, Angular Drop Down コントロール, Angular コントロール Large Item List, Angular コントロール Singe Selection +title: Angular Drop Down コンポーネント – Ignite UI for Angular | インフラジスティックス | MITライセンス +description: Ignite UI for Angular の仮想化 Drop Down を使用して、単一項目の選択をサポートする非常に大きな項目のリストを表示します。 +keywords: Ignite UI for Angular, UI コントロール, Angular ウィジェット, web ウィジェット, UI ウィジェット, Angular, ネイティブ Angular コンポーネント スイート, ネイティブ Angular コントロール, ネイティブ Angular コンポーネント ライブラリ, Angular Drop Down コンポーネント, Angular Drop Down コントロール, Angular コントロール 大規模項目リスト, Angular コントロール 単一選択 license: MIT _language: ja llms: - description: "Ignite UI for Angular Drop Down コンポーネントは、選択可能な項目リストを表示するために、IgxForOf ディレクティブの使用方法を完全に統合できます。" + description: "Ignite UI for Angular Drop Down コンポーネントは、選択可能な項目の非常に大きなリストを表示するために Virtual Scroll コンポーネントをホストできます。" --- import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; @@ -14,92 +14,87 @@ import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; # 仮想ドロップダウン -Ignite UI for Angular Drop Down コンポーネントは、選択可能な項目リストを表示するために、[`IgxForOf`](/for-of) ディレクティブの使用方法を完全に統合できます。 +Ignite UI for Angular Drop Down コンポーネントは、選択可能な項目の非常に大きなリストを表示するために [Virtual Scroll](./layouts/virtual-scroll.mdx) コンポーネントをホストできます。ドロップダウンのビューポート内の項目のみがレンダリングされ、選択とキーボード ナビゲーションはリスト全体に対して機能します。 ## Angular 仮想ドロップダウンの例 -
- ## 使用方法 ### はじめに -仮想アイテムのリストを表示するようにドロップダウンを設定するには、いくつかの前提条件を満たす必要があります。 -はじめにドロップダウンを宣言するコンポーネントのモジュールに `IgxForOfModule` をインポートする必要があります。 + と、リスト項目のテンプレートをマークする `IgxVirtualItemDirective` をドロップダウンと一緒にインポートします。 ```typescript -// app.module.ts -import { IgxForOfModule } from 'igniteui-angular/directives'; -// import { IgxForOfModule } from '@infragistics/igniteui-angular'; for licensed package +// drop-down-virtual.component.ts +import { Component } from '@angular/core'; +import { IgxButtonDirective, IgxToggleActionDirective } from 'igniteui-angular/directives'; +import { IgxDropDownComponent, IgxDropDownItemComponent, IgxDropDownItemNavigationDirective } from 'igniteui-angular/drop-down'; +import { IgxVirtualItemDirective, IgxVirtualScrollComponent } from 'igniteui-angular/virtual-scroll'; +// import { IgxVirtualItemDirective, IgxVirtualScrollComponent } from '@infragistics/igniteui-angular'; for licensed package -@NgModule({ +@Component({ + selector: 'app-drop-down-virtual', + templateUrl: './drop-down-virtual.component.html', + styleUrls: ['./drop-down-virtual.component.scss'], imports: [ - ... - IgxForOfModule + IgxButtonDirective, IgxToggleActionDirective, IgxDropDownItemNavigationDirective, + IgxDropDownComponent, IgxDropDownItemComponent, + IgxVirtualScrollComponent, IgxVirtualItemDirective ] }) -export class AppModule {} +export class DropDownVirtualComponent { } ``` ### テンプレートの構成 -次に、`*ngFor` の代わりに を使用してデータをループ処理し、ドロップダウン コンポーネントのテンプレートを作成する必要があります。`*igxFor` ディレクティブは、すべての項目を正しく表示するために追加の構成が必要です。 +次に、ドロップダウンの内側に `igx-virtual-scroll` を配置し、`igxVirtualItem` でマークされた `ng-template` で各項目をレンダリングします。ドロップダウンは投影された Virtual Scroll を検出し、スクロール、キーボード ナビゲーション、選択にそれを使用します。 ```html - - + + + + {{ item.name }} + + +
Selected Model: {{ dropdown.selectedItem?.value.name }}
``` -以下は、`*igxFor` ディレクティブに渡される追加パラメーターです。 -- `index` - データセット内の現在の項目のインデックスを取得します。 -- `scrollOrientation` - 常に `'vertical'` にする必要があります。 -- `containerSize` - 仮想化コンテナーのサイズ (ピクセル単位)。これは、ラッピング `
` にも適用する必要があります。 -- `itemSize` - 表示される項目のサイズ (ピクセル単位)。 +ここで使用されている `igx-virtual-scroll` の入力は次のとおりです。 + +- `data` - 項目全体のリスト。参照によって比較されるため、変更するには新しい配列を割り当てます。 +- `estimatedItemSize` - レンダリングされて測定される前の項目の高さ (`px` 単位)。スクロールバーとキーボード ナビゲーションが最初から正確になるように、ドロップダウン項目の実際の高さに設定します。 -項目の一意性を確保するために、 input の内の `item` および `igx-drop-down-item` の 内の `index` を渡します。 -スクロールしながら選択を維持するには、ドロップダウン 項目はそれがバインドされているデータ項目への参照を持つ必要があります。 +項目の一意性を確保するために、`igx-drop-down-item` の 入力に `item` を、 入力に `index` を渡します。 +スクロールしながら選択を維持するには、ドロップダウン項目はそれがバインドされているデータ項目への参照を持つ必要があります。 -ドロップダウンが項目の仮想化リストで機能するためには、 および の入力をすべての項目に渡す必要があります。 +ドロップダウンが項目の仮想化リストで機能するためには、 および の入力をすべての項目に渡す**必要があります**。 - -各項目に対して `[value]` 入力に渡される一意の値を持たない場合、予想外の結果 (誤った選択) となる場合があります。 +各項目に対して `[value]` 入力に一意の値を渡すことを強くお勧めします。渡さない場合、予想外の結果 (誤った選択) になる可能性があります。 -ドロップダウンが仮想化項目を使用する場合、 の種類は `{ value: any, index: number }` になります。ここで、`value` はデータ項目への参照です。`[value]` input の内に渡され、`index` はデータセット内の項目のインデックスです。 +ドロップダウンが仮想化された項目を使用する場合、 の型は `{ value: any, index: number }` になります。ここで、`value` は `[value]` 入力に渡されたデータ項目への参照であり、`index` はデータセット内の項目のインデックスです。 ### コンポーネント定義 -コンポーネントの constructor 内で、ドロップダウンに表示される、適度に大きな項目のリスト (ヘッダーと無効なアイテムの両方を含む) を宣言します。`itemHeight` と `itemsMaxHeight` を宣言する必要があります。 +コンポーネントの内部で、ドロップダウンに表示される、適度に大きな項目のリスト (ヘッダーと無効な項目の両方を含む) と、項目の高さを宣言します。 ```typescript -// drop-drop-virtual.component.ts +// drop-down-virtual.component.ts export class DropDownVirtualComponent { public items: DataItem[]; - public itemHeight = 48; - public itemsMaxHeight = 320; + public itemHeight = 40; constructor() { const itemsCollection: DataItem[] = []; @@ -127,160 +122,137 @@ export class DropDownVirtualComponent { ### スタイル -最後に、ラッピング div に `overflow: hidden` を設定して、2 つのスクロールバー (`igxFor` のスクロールバーとコンテナー自体のスクロールバー) が表示されないようにします。 +`igx-virtual-scroll` 要素はリストのスクロール コンテナーであるため、固定の高さが必要です。ラッピング要素や `overflow` ルールは必要ありません。 ```scss -// drop-drop-virtual.component.scss +// drop-down-virtual.component.scss .drop-down-virtual-wrapper { - overflow: hidden; + height: 240px; + width: 180px; } ``` ## リモート データ -`igx-drop-down` は、`*igxFor` 構造ディレクティブを使用したリモート データの部分的な読み込みをサポートします。構成はローカル項目の構成に似ていますが、主な違いはデータ部分の読み込み方法です。 +`igx-drop-down` は、リモート データのページの読み込みもサポートしています。Virtual Scroll の 入力を読み込まれたページにバインドし、 出力が報告する範囲から次のページを読み込みます。リストはリモート コレクション全体と同じ長さになるため、スクロールバーはすべての項目にまたがりますが、読み込まれたページのみがメモリー内にあります。 ### テンプレート -ドロップダウン テンプレートは、以前の例 と比べてそれほど変更する必要はありません。それでも、ラッピング div を指定し、それに応じてスタイルを設定し、`*igxFor` の完全な設定を書き出す必要があります。リモートソースからデータを取得するので、データが観測可能になるように指定して Angular の `async` パイプに渡す必要があります。 +このテンプレートは、データ バインディングの点でのみ前の例と異なります。`dataWindow` が `data` の代わりとなり、`stateChange` がページを要求します。`index` テンプレート変数は、リモート コレクション全体における項目のインデックスです。 ```html - + + + + {{ item.ProductName }} + + + ``` -### チャンクロードの処理 - -ご覧のとおり、テンプレートは前の例のテンプレートとほとんど同じです。このリモートデータのシナリオでは、背後にあるコードが大部分の負担を軽減します。 +### ページの読み込み -まず、データを取得するためのリモートサービスを定義する必要があります。 +まず、コレクションのページとレコードの総数を返すリモート サービスを定義します。 ```typescript // remote.service.ts import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { IForOfState } from 'igniteui-angular/directives'; -// import { IForOfState } from '@infragistics/igniteui-angular'; for licensed package -import { BehaviorSubject, Observable } from 'rxjs'; +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; @Injectable() export class RemoteService { - public remoteData: Observable; - private _remoteData: BehaviorSubject; - - constructor(private http: HttpClient) { - this._remoteData = new BehaviorSubject([]); - this.remoteData = this._remoteData.asObservable(); + private http = inject(HttpClient); + + // Assuming that the API service is RESTful and can take the following: + // skip: start index of the data that we fetch + // count: number of records we fetch + public getPage(skip: number, count: number): Observable<{ value: any[]; '@odata.count': number }> { + return this.http.get<{ value: any[]; '@odata.count': number }>( + `https://dummy.db/dummyEndpoint?$skip=${skip}&$top=${count}&$count=true` + ); } - - public getData(data?: IForOfState, cb?: (any) => void): any { - // Assuming that the API service is RESTful and can take the following: - // skip: start index of the data that we fecth - // count: number of records we fetch - this.http.get(`https://dummy.db/dummyEndpoint?skip=${data.startIndex}&count=${data.chunkSize}`).subscribe((data) => { - // emit the values through the _remoteData subject - this._remoteData.next(data); - }) } ``` -このサービスは、`remoteData` の下に `Observable` を公開します。リモート ドロップダウン コンポーネントでサービスを注入し、そのプロパティにバインドします。 +コンポーネントでは、読み込まれたページを `VirtualDataWindow` 型のシグナルに保持します。初期化時に最初のページを読み込み、`stateChange` が読み込み済みのページがカバーしていない範囲を報告するたびに新しいページを読み込みます。以前のリクエストをキャンセルすることで、遅い応答が新しいページを上書きしないようにします。 ```typescript -// remote-drop-down.component.ts +// drop-down-remote.component.ts +import { Component, OnDestroy, OnInit, inject, signal } from '@angular/core'; +import { VirtualDataWindow, VirtualScrollState } from 'igniteui-angular/virtual-scroll'; +import { Subscription } from 'rxjs'; + +/** Extra records requested on each side of the range the viewport wants. */ +const BUFFER = 10; + @Component({ providers: [RemoteService], selector: 'app-drop-down-remote', templateUrl: './drop-down-remote.component.html', - styleUrls: ['./drop-down-remote.component.scss'] + styleUrls: ['./drop-down-remote.component.scss'], + imports: [/* the same imports as in the local example */] }) export class DropDownRemoteComponent implements OnInit, OnDestroy { - @ViewChild(IgxForOfDirective, { read: IgxForOfDirective }) - public remoteForDir: IgxForOfDirective; - @ViewChild('remoteDropDown', { read: IgxDropDownComponent }) - public remoteDropDown: IgxDropDownComponent; - public itemHeight = 48; - public itemsMaxHeight = 480; - public prevRequest: Subscription; - public rData: any; - - private destroy$ = new Subject(); - constructor(private remoteService: RemoteService) { } - - public ngAfterViewInit() { - const initialState = { startIndex: 0, chunkSize: Math.ceil(this.itemsMaxHeight / this.itemHeight) } - this.remoteService.getData(initialState, (data) => { - this.remoteForDir.totalItemCount = data['@odata.count']; - }); - // Subscribe to igxForOf.chunkPreload and load new data from service - this.remoteForDir.chunkPreload.pipe(takeUntil(this.destroy$)).subscribe((data) => { - this.dataLoading(data); - }); + private remoteService = inject(RemoteService); + public itemHeight = 40; + public readonly page = signal>({ items: [], startIndex: 0, totalCount: 0 }); + private pending?: Subscription; + + public ngOnInit() { + this.loadPage(0, 2 * BUFFER); } - public dataLoading(evt) { - if (this.prevRequest) { - this.prevRequest.unsubscribe(); + public onStateChange(state: VirtualScrollState) { + const page = this.page(); + if (state.startIndex >= page.startIndex && state.endIndex < page.startIndex + page.items.length) { + return; // The loaded page already covers the range. } - this.prevRequest = this.remoteService.getData( - evt, - (data) => { - this.remoteForDir.totalItemCount = data['@odata.count']; - }); + const startIndex = Math.max(0, state.startIndex - BUFFER); + this.loadPage(startIndex, state.endIndex - startIndex + 1 + BUFFER); } - public ngOnInit() { - this.rData = this.remoteService.remoteData; + public ngOnDestroy() { + this.pending?.unsubscribe(); } - public ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); + private loadPage(startIndex: number, count: number) { + this.pending?.unsubscribe(); + this.pending = this.remoteService.getPage(startIndex, count).subscribe(data => { + this.page.set({ items: data.value, startIndex, totalCount: data['@odata.count'] }); + }); } } ``` -`ngAfterViewInit` フックの内部で、初期状態のデータを取得し、`igxForOf` ディレクティブの エミッターをサブスクライブするために呼び出します。このサブスクリプションは、ロードされたチャンクが変更されるたびにデータを取得します。コンポーネントの破棄時にエミッターから簡単にサブスクライブ解除できるように、`pipe(takeUntil(this.destroy$))` を使用します。 +ドロップダウンが、例えば `End` キーでまだ読み込まれていない項目にナビゲートすると、Virtual Scroll はその項目までスクロールし、`stateChange` が新しい範囲を報告し、その項目を含むページが読み込まれます。 ### リモートの仮想化 - デモ -上記の設定の結果は、スクロールバーの状態に応じて表示されるはずのデータを動的にロードするドロップダウンです。 - - +上記の設定の結果は、スクロールバーの状態に応じて、表示するデータを動的に読み込むドロップダウンです。 -
+ ## 注意と制限 -仮想化された項目のリストでドロップダウンを使用すると、いくつかの制限があります。`*igxFor` を使用してドロップダウン リストを設定するときは、次の点に注意してください。 -- ループされているロップダウン項目は、次の css を持つラッピング要素 (`
` など) で渡す必要があります。`overflow: hidden` と `height` が `containerSize` に等しい (`px` で) 。 +仮想化された項目のリストでドロップダウンを使用すると、いくつかの制限があります。`igx-virtual-scroll` を使用してドロップダウン リストを設定するときは、次の点に注意してください。 + +- `igx-virtual-scroll` 要素はリストのスクロール コンテナーであるため、固定の `height` を持つ必要があります。 - リストが仮想化されている場合、`` を項目のグループ化に使用することはできません。代わりに `isHeader` プロパティを使用します。 -- `items` アクセサーは、現在仮想化ビューにあるヘッダー以外のロップダウン項目のリストのみを返します。 -- は、タイプ `{ value: any, index: number }` です。 -- によって発行されたオブジェクトは、`const emittedEvent: { newSelection: { value: any, index: number }, oldSelection: { value: any, index: number }, cancel: boolean, }` に変更されます。 +- `items` アクセサーは、現在仮想化ビューにあるヘッダー以外のドロップダウン項目のリストのみを返します。 +- の型は `{ value: any, index: number }` です。 +- によって発行されるオブジェクトは、`const emittedEvent: { newSelection: { value: any, index: number }, oldSelection: { value: any, index: number }, cancel: boolean, }` に変わります。 - `dropdown.setSelectedItem` は、**データセット内の項目のインデックス**を使用して呼び出す必要があります。 -- ドロップダウン項目の `[selected]` 入力を設定しても、ドロップダウン選択内の項目はマークされません。 +- ドロップダウン項目の `[selected]` 入力を設定しても、ドロップダウンの選択内で項目がマークされること**はありません**。 -- The drop-down items that are being looped need to be passed in a wrapping element (e.g. `
`) which has the following css: `overflow: hidden` and `height` equal to `containerSize` in `px` -- `` cannot be used for grouping items when the list is virtualized. Use the `isHeader` property instead -- The `items` accessor will return only the list of non-header drop-down items that are currently in the virtualized view. -- is of type `{ value: any, index: number }` -- The object emitted by changes to `const emittedEvent: { newSelection: { value: any, index: number }, oldSelection: { value: any, index: number }, cancel: boolean, }` -- `dropdown.setSelectedItem` should be called with the **item's index in the data set** -- setting the drop-down item's `[selected]` input will **not** mark the item in the drop-down selection +ドロップダウンは、以前のバージョンと同様に、投影された [`*igxFor`](./for-of.mdx) ディレクティブでも動作します。このディレクティブは非推奨となり、Virtual Scroll に置き換えられているため、新しいドロップダウンには `igx-virtual-scroll` を使用してください。 ## API リファレンス - -- +- - diff --git a/docs/angular/src/content/jp/components/for-of.mdx b/docs/angular/src/content/jp/components/for-of.mdx index ce89377896..0df800b00e 100644 --- a/docs/angular/src/content/jp/components/for-of.mdx +++ b/docs/angular/src/content/jp/components/for-of.mdx @@ -5,16 +5,21 @@ keywords: Angular Virtual ForOf ディレクティブ, ネイティブ Angular license: MIT _language: ja llms: - description: "Ignite UI for Angular は ngFor と同様の仮想 igxFor ディレクティブを公開します。" + description: "Ignite UI for Angular の igxForOf ディレクティブは、大量のデータをテンプレート化するための ngForOf の代替となる非推奨のディレクティブです。Virtual Scroll コンポーネントがこれに代わります。" --- +import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; # Angular Virtual ForOf (仮想 ForOf) ディレクティブの概要 + +`igxForOf` ディレクティブは非推奨であり、[Virtual Scroll](./layouts/virtual-scroll.mdx) コンポーネントに置き換えられます。既存のリストは引き続き動作しますが、単一の軸を仮想化する新しいリストには Virtual Scroll を使用してください。Virtual Scroll は実行時に項目を測定するため項目ごとに異なるサイズを使用でき、独自のスクロール コンテナーも作成します。既存のリストを移行する方法については、[igxForOf リストを Virtual Scroll に置き換えるにはどうすればよいですか?](./layouts/virtual-scroll.mdx#igxforof-リストを-virtual-scroll-に置き換えるにはどうすればよいですか)を参照してください。 + +
-The Ignite UI for Angular igxForOf directive is an alternative to ngForOf for templating large amounts of data. It uses virtualization behind the scenes to optimize DOM rendering and memory consumption. +Ignite UI for Angular の igxForOf ディレクティブは、大量のデータをテンプレート化するための ngForOf の代替となるディレクティブです。内部で仮想化を使用して、DOM のレンダリングとメモリ消費を最適化します。
## Angular 仮想スクロール ディレクティブの例 @@ -113,7 +118,7 @@ Ignite UI for Angular ForOf モジュールまたはディレクティブをイ ``` -**注:** テンプレートの親コンテナーには、次の CSS ルールが適用されていることを強く推奨します: 垂直方向には `height`、水平方向には `width`、`overflow: hidden` および `position: relative`。スムーズ スクロール動作が、表示されたままの場合にページのその他の部分に視覚的に影響を与えることが可能なコンテンツ オフセットによって実装されるためです。 +**注:** テンプレートの親コンテナーには、次の CSS ルールが適用されていることを強く推奨します: 垂直方向には `height`、水平方向には `width`、`overflow: hidden` および `position: relative`。これは、スムーズ スクロール動作がコンテンツのオフセットによって実現されており、オフセットされたコンテンツが表示されたままになると、ページの他の部分に視覚的な影響を与える可能性があるためです。 ### 水平仮想化 @@ -166,11 +171,11 @@ Ignite UI for Angular ForOf モジュールまたはディレクティブをイ `igxFor` ディレクティブは、`igxGrid` 内のデータを垂直方向と水平方向の両方向に仮想化するために使用されます。 -より詳細な情報とデモについては、[グリッド仮想化](/grid/virtualization)トピックに従ってください。 +より詳細な情報とデモについては、[グリッド仮想化](/grid/virtualization)トピックを参照してください。 ### リモート サービスにバインドされる igxFor - ディレクティブは、`Observable` プロパティ- `remoteData`を使用してリモート サービスにバインドできます。(次の例の場合) `chunkLoading` イベントも、データのリクエストをトリガーするために利用する必要があります。 + ディレクティブは、`Observable` プロパティ (次の例では `remoteData`) を使用してリモート サービスにバインドできます。データのリクエストをトリガーするには、`chunkLoading` イベントも使用する必要があります。 ```html
@@ -243,7 +248,7 @@ private buildUrl(dataState: any): string { } ``` - イベントが発生するたびに、新しいデータのチャンクがリクエストされます。 + イベントが発生するたびに、新しいデータのチャンクをリクエストする必要があります。 ```typescript chunkLoading(evt) { @@ -258,7 +263,7 @@ chunkLoading(evt) { ## ローカル変数 -igxFor ディレクティブのコンテキストには、`even`、`odd`、`first`、`last` のヘルパー プロパティが含まれています。これらは、コレクション内の現在の要素の位置を識別するために使用されます。次のコードスニペットは、`ng-template` で `even` プロパティを使用する方法を示しています。すべての偶数の div 要素に `even` クラスが割り当てられます: +`igxFor` ディレクティブのコンテキストには、`even`、`odd`、`first`、`last` のヘルパー プロパティが含まれています。これらは、コレクション内の現在の要素の位置を識別するために使用されます。次のコード スニペットは、`ng-template` で `even` プロパティを使用する方法を示しています。すべての偶数の div 要素に `even` クラスが割り当てられます: ```html + コミュニティに参加して新しいアイデアをご提案ください。 + +- [Ignite UI for Angular **フォーラム** (英語)](https://www.infragistics.com/community/forums/f/ignite-ui-for-angular) +- [Ignite UI for Angular **GitHub** (英語)](https://github.com/IgniteUI/igniteui-angular) diff --git a/docs/angular/src/content/jp/components/hierarchicalgrid/hierarchical-grid.mdx b/docs/angular/src/content/jp/components/hierarchicalgrid/hierarchical-grid.mdx index 9dd5d73873..de56415c61 100644 --- a/docs/angular/src/content/jp/components/hierarchicalgrid/hierarchical-grid.mdx +++ b/docs/angular/src/content/jp/components/hierarchicalgrid/hierarchical-grid.mdx @@ -373,7 +373,7 @@ This way, due to Angular's [`ViewEncapsulation`](https://angular.io/api/core/Com ### スコープ コンポーネント テーマ - + カスタム テーマが特定のコンポーネントのみに影響するように、定義したすべてのスタイルをグローバル スタイル ファイルからカスタム コンポーネントのスタイルファイルに移動できます (`index` ファイルのインポートを含む)。 このように、Angular の [ViewEncapsulation](https://angular.io/api/core/Component#encapsulation) により、スタイルはカスタム コンポーネントにのみ適用されます。 diff --git a/docs/angular/src/content/jp/components/layouts/avatar.mdx b/docs/angular/src/content/jp/components/layouts/avatar.mdx deleted file mode 100644 index 86868c15a1..0000000000 --- a/docs/angular/src/content/jp/components/layouts/avatar.mdx +++ /dev/null @@ -1,297 +0,0 @@ ---- -title: "Angular Avatar コンポーネント | レイアウト | インフラジスティックス" -description: "Angular Avatar コンポーネントを使用して、ユーザー、エンティティ、またはオブジェクトを画像、イニシャル、アイコン、またはカスタム コンテンツで表します。" -keywords: "Angular Avatar, アバター コンポーネント, プロフィール画像, イニシャル, Ignite UI for Angular, Infragistics" -last_updated: "2026-07-29" -license: MIT -mentionedTypes: ["Avatar", "Badge", "Icon"] -relatedComponents: ["Badge"] -_language: ja -llms: - description: "Ignite UI for Angular Avatar トピックでは、画像、イニシャル、アイコン、カスタム コンテンツ、形状、サイズ、スタイル設定、アクセシビリティ ガイダンスを使用してユーザー、エンティティ、またはオブジェクトのアイデンティティをレンダリングする方法を示します。" ---- -import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; -import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; -import Anatomy from 'igniteui-astro-components/components/mdx/Anatomy.astro'; -import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; -import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; -import { Image } from 'astro:assets'; -import avatarAnatomy from '@xplat-images/anatomy-content-light/avatar-lt-a.png'; -import avatarDo from '@xplat-images/avatar/avatar_do1.png'; -import avatarDo2x from '@xplat-images/avatar/avatar_do1@2x.png'; -import avatarDoNot from '@xplat-images/avatar/avatar_do_not1.png'; -import avatarDoNot2x from '@xplat-images/avatar/avatar_dont1@2x.png'; - -# Avatar (アバター) コンポーネント - -Ignite UI for Angular Avatar は、画像、イニシャル、またはカスタム コンテンツを使用してユーザー、エンティティ、またはオブジェクトを表します。 - -アバターを使用して、リスト、カード、プロフィール メニュー、アクティビティ フィードでコンパクトな視覚的アイデンティティを提供します。 - -## ライブ デモ - - - -## 構造 - -アバターは、画像のセマンティクスを適用し、サポートされているコンテンツ パターンのいずれかをレンダリングする単一のホスト要素です。 - - - - - -1. 画像コンテナー: 画像コンテンツ タイプを表示します。
-2. アイコン コンテナー: アイコン コンテンツ タイプを表示します。
-3. イニシャル コンテナー: テキスト コンテンツ タイプを表示します。
- -```text -igx-avatar[role="img"] // ホスト - アバターを公開 -└─ 優先順位順に以下のいずれか: - ├─ div.igx-avatar__image // `src` が設定されている場合 - 背景として画像をレンダリング - ├─ igx-icon // `icon` が設定されている場合 - ├─ span // `initials` が設定されている場合 - 最初の 2 文字 - └─ ng-content // カスタム プロジェクション コンテンツ -``` - -## 作業の開始 - -`` をレンダリングする前に Angular アバター コンポーネントをインポートします。Ignite UI for Angular をまだセットアップしていない場合は、最初に共有 [作業の開始](../general/getting-started.mdx) トピックを完了してください。 - -```ts -import { IgxAvatarComponent } from 'igniteui-angular/avatar'; -``` - -## 使用方法 - -デフォルト スロットに画像ソース、イニシャル、またはカスタム コンテンツを使用してアバターをレンダリングします。 - -### バリアント - -表示するコンテンツ ソースのみを設定します。Angular アバターは、最初に `src` をレンダリングし、次に `icon`、次に `initials` をレンダリングし、これらのいずれの入力も設定されていない場合はプロジェクションされたカスタム コンテンツにフォールバックします。 - -```html - - - - - -``` - - - -### 形状 - - を `square`、`rounded`、または `circle` に設定します。 - -```html - -``` - - - -### サイズ - -プリセット アバター サイズが必要な場合は、`--ig-size` を共有サイズ トークンのいずれかに設定します。 - -```html - -``` - - - -### 使用すべき場合と使用すべきでない場合 - -**使用すべき場合:** プロフィール画像、イニシャル、アイコンなど、UI が人物、組織、オブジェクト、またはアカウントの小さな表現を必要とする場合にアバターを使用します。繰り返し表示されるアイデンティティを簡単に識別できるように、同じ UI 領域内で一貫したアバター戦略を維持します。 - -**使用すべきでない場合:** エンティティを表す代わりにカウント、ステータス、または通知インジケーターを表示する必要がある場合は、[Badge](../inputs/badge.mdx) コンポーネントを使用します。アイデンティティとステータスの両方を一緒に表示する必要がある場合、バッジはアバターを装飾することもできます。 - -
- - - - - - - - - - - - - -
使用すべき使用すべきでない
Angular Avatar の使用ガイダンスAngular Avatar の不使用ガイダンス
-
- -## プロパティ - -アバターは、コンテンツと形状のための小さな入力セットを公開します。 - -| 名前 | 型 | デフォルト | 説明 | -| -- | -- | -- | -- | -| | `string` | n/a | アバターがレンダリングするアイコンを設定します。 | -| | `string` | n/a | アバターがレンダリングするテキスト イニシャルを設定します。 | -| | `"square" \| "rounded" \| "circle"` | `"square"` | アバターの形状を設定します。 | -| | `"small" \| "medium" \| "large"` | `"small"` | アバターのサイズを設定します。 | -| | `string` | n/a | 画像ソース URL を設定します。 | - -## スタイル設定 - - - -アバターの外観はテーマ変数とプラットフォーム固有のスタイル設定フックを通じて制御されます。 - -トークン レベルの変更にはアバター CSS 変数を使用し、特定のレンダリング タイプや形状をターゲットにする必要がある場合は Angular ホスト クラスを使用します。 - -| 変数 | 変更内容 | -| -- | -- | -| `--ig-avatar-background` | アバターの背景色。 | -| `--ig-avatar-color` | テキストとイニシャルの色。 | -| `--ig-avatar-icon-color` | アイコンの色。 | -| `--ig-avatar-border-radius` | 丸みのあるアバターで使用される境界線の半径。 | -| `--ig-avatar-size` | アバターの幅と高さ。 | -| `--ig-size` | プリセット アバター サイズを導出するために使用する共有コンポーネント サイズ トークン。 | - -| セレクター | 説明 | -| -- | -- | -| `igx-avatar` | アバターのホスト要素。 | -| `.igx-avatar--rounded` | `shape` が `rounded` の場合に適用されます。 | -| `.igx-avatar--circle` | `shape` が `circle` の場合に適用されます。 | -| `.igx-avatar--image` | アバターが画像をレンダリングするときに適用されます。 | -| `.igx-avatar--icon` | アバターがアイコンをレンダリングするときに適用されます。 | -| `.igx-avatar--initials` | アバターがイニシャルをレンダリングするときに適用されます。 | -| `.igx-avatar__image` | 画像アバター要素。 | - -### Sass テーマ - -アプリケーションが Sass を通じて Ignite UI テーマをカスタマイズする場合は、 関数を使用します。 - -```scss -@use "igniteui-theming/sass/themes" as *; - -$custom-avatar-theme: avatar-theme( - $background: #72da67, - $border-radius: 16px, - $size: 3rem -); - -:root { - @include tokens($custom-avatar-theme); -} -``` - -### CSS 変数 - -Sass ビルド ステップなしでローカルでのスタイル設定が必要な場合は、コンポーネント CSS 変数を直接設定します。 - -```css -igx-avatar { - --ig-avatar-background: var(--ig-success-500); - --ig-avatar-color: var(--ig-success-500-contrast); - --ig-avatar-border-radius: 20px; -} -``` - -### Tailwind によるスタイル設定 - -アプリケーションが Tailwind クラスを通じて Ignite UI コンポーネントのスタイルを設定する場合は、Angular Tailwind ユーティリティ構文を使用します。 - - - -## アクセシビリティ - -アバターは、アクセシブルな画像セマンティクスを持つ非インタラクティブなアイデンティティ表示要素です。 - -### キーボード インタラクション - -アバターはフォーカスを受け取らず、キーボード インタラクションはありません。 - -| キー | アクション | -| -- | -- | -| n/a | アバターはキーボードによるインタラクティブ操作に対応していません。 | - -### スクリーン リーダー / ARIA - -アバターは画像のセマンティクスと `avatar` のデフォルトのアクセシブル ラベルで初期化されます。 - -- 画像アバターがアイデンティティを伝える場合、周囲のテキストを使用して表現される人物、エンティティ、またはオブジェクトを識別します。 -- 隣接するテキストがすでに同じエンティティを識別している場合、装飾的なアバターを冗長として扱います。 - -### アクセシビリティ準拠 - -Infragistics は、[アクセシビリティ準拠](../interactivity/accessibility-compliance.mdx) トピックで、Section 508 および WCAG 2.1 ガイドライン領域における Ignite UI for Angular のアクセシビリティ サポートを文書化しています。 - -| 基準 | コンポーネントの準拠方法 | -| -- | -- | -| [1.1.1 非テキスト コンテンツ](https://www.w3.org/WAI/WCAG22/Understanding/non-text-content) | アバターにはアクセシブル ラベルがあり、表現されるエンティティを識別する周囲のテキストと組み合わせることができます。 | -| [4.1.2 名前、役割、値](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value) | コンポーネントは `role="img"` とデフォルトのアクセシブル ラベルで初期化されます。 | - -ユーザー側の責任: - -- スタイルをオーバーライドするときに、アバターの背景とテキストまたはアイコンの色のコントラストを十分に保ちます。 -- 隣接するテキストがすでに人物またはエンティティの名前を示している場合、同じアイデンティティのアナウンスを重複させないようにします。 - -- アバター画像がアイデンティティを伝える場合、近くのテキストが表現されるエンティティを識別していることを確認します。 - -## トラブルシューティング - -Avatar をインタラクティブまたはステータス コンポーネントとして扱う前に、このセクションを使用して境界と一般的な決定を確認してください。 - -### 既知の制限 - -アバターは視覚的なアイデンティティのプリミティブであり、それ自体ではインタラクション、ステータス、または通知動作を追加しません。 - -- 表現されるエンティティがクリック可能でなければならない場合は、ボタンやリスト アイテムなどのインタラクティブなコンテナーを使用します。 -- ステータス、カウント、または通知インジケーターを表示する必要がある場合は、アバターにバッジを使用します。 - -## API リファレンス - -完全なアバター API サーフェスについては、これらの API リファレンスを使用してください。 - - - -## 依存関係 - -Sass スタイル設定ワークフローは、 および API を使用します。 - -## その他のリソース - -サポートおよび関連する Ignite UI ドキュメントについては、これらのリソースを使用してください。 - -- [Ignite UI for Angular **フォーラム** (英語)](https://www.infragistics.com/community/forums/f/ignite-ui-for-angular) -- [Ignite UI for Angular **GitHub** (英語)](https://github.com/IgniteUI/igniteui-angular) - -## 関連コンポーネント - -アイデンティティをステータス、アクション、またはより豊富なレイアウトと組み合わせる必要がある場合は、これらの関連コンポーネントを使用してください。 - -- [Badge](../inputs/badge.mdx) - カウント、ステータス、または通知インジケーターを表示するには Badge を使用します。UI にアイデンティティとステータスの両方が必要な場合、Badge は Avatar を装飾できます。 - -## FAQ - - - - UI が人物、アカウント、組織、またはオブジェクトを表す必要がある場合に Avatar を使用します。UI がカウント、ステータス、または通知インジケーターを表示する必要がある場合は Badge を使用します。 - - - - いいえ。Avatar は非インタラクティブであり、それ自体ではフォーカスを受け取りません。表現されるエンティティがアクションを必要とする場合は、インタラクティブなコンポーネント内に配置してください。 - - - - アバター画像が特定のエンティティを識別する場合は、意味のある代替テキストを提供します。隣接するテキストがすでにそのエンティティの名前を示している場合、同じアイデンティティのアナウンスを繰り返さないようにします。 - - diff --git a/docs/angular/src/content/jp/components/pivotgrid/pivot-grid.mdx b/docs/angular/src/content/jp/components/pivotgrid/pivot-grid.mdx index c470ab8996..b87031e9e0 100644 --- a/docs/angular/src/content/jp/components/pivotgrid/pivot-grid.mdx +++ b/docs/angular/src/content/jp/components/pivotgrid/pivot-grid.mdx @@ -387,7 +387,7 @@ igx-pivot-grid { ### デモ - + より詳細なカスタマイズが必要な場合は、 に追加のパラメーターがあります。 diff --git a/docs/angular/src/content/jp/components/simple-combo.mdx b/docs/angular/src/content/jp/components/simple-combo.mdx index e0971cfb60..732e7c02e5 100644 --- a/docs/angular/src/content/jp/components/simple-combo.mdx +++ b/docs/angular/src/content/jp/components/simple-combo.mdx @@ -1,11 +1,11 @@ --- title: 単一選択 ComboBox コンポーネント - MITライセンス -description: Ignite UI for Angular ComboBox は、基本的な HTML 入力、選択、フィルタリング、およびカスタム ドロップダウン リストの機能を組み合わせた強力な入力を提供します。無料でお試しください。 +description: Ignite UI for Angular Simple ComboBox は、基本的な HTML 入力、選択、フィルタリング、およびカスタム ドロップダウン リストの機能を組み合わせた強力な入力を提供します。無料でお試しください。 keywords: angular 単一選択 combobox, angular combobox コンポーネント, angular 単一選択 combobox コンポーネント, angular combo, angular ui コンポーネント, ignite ui for angular, インフラジスティックス license: MIT _language: ja llms: - description: "Angular Single Select ComboBox コンポーネントは、単一の選択を可能にする ComboBox コンポーネントの変更です。" + description: "Angular Single Select ComboBox コンポーネントは、ComboBox コンポーネントを単一選択用に変更したものです。" --- import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; @@ -14,7 +14,7 @@ import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; # Angular Single Select ComboBox (単一選択のコンボボックス) コンポーネントの概要 -Angular Single Select ComboBox コンポーネントは、単一の選択を可能にする [ComboBox コンポーネント](/combo)の変更です。これを「シンプルなコンボ」と呼びます。元の ComboBox コンポーネントの単一選択モードに対する需要が高かったため、ユーザーが事前定義された項目リストからオプションを選択し、カスタム値を入力できるようにする編集可能な検索入力を提供する拡張コンポーネントを作成しました。 +Angular Single Select ComboBox コンポーネントは、[ComboBox コンポーネント](/combo)を単一選択用に変更したものです。これを「シンプルなコンボ」と呼びます。元の ComboBox コンポーネントの単一選択モードに対する需要が高かったため、ユーザーが事前定義された項目リストからオプションを選択し、カスタム値を入力できるようにする編集可能な検索入力を提供する拡張コンポーネントを作成しました。 ## Angular Simple ComboBox の例 @@ -102,28 +102,28 @@ export class MySimpleComboComponent implements OnInit { ``` -これで、Simple ComboBox が cities の配列にバインドされました。 +これで、Simple ComboBox が都市の配列にバインドされました。 ### データ値と表示プロパティ Simple ComboBox は複雑なデータ (つまりオブジェクト) の配列にバインドされているため、選択した項目を処理するためにコントロールが使用するプロパティを指定する必要があります。このコントロールは、 と の 2 つの `@Input` プロパティを公開します: - `valueKey` - **オプション、オブジェクト配列に推奨** - Simple ComboBox の選択のためにデータ エントリのどのプロパティを保存するかを指定します。`valueKey` を省略すると、Simple ComboBox 値はデータ エントリへの参照を使用します (つまり、選択は `igxSimpleCombo.data` からのエントリの配列になります)。 -- `displayKey` - **オブジェクト配列に必要** - 項目のテキストに使用されるプロパティを指定します。`displayKey` に値が指定されていない場合、Simple ComboBox は指定された `valueKey` (存在する場合) を使用します。 +- `displayKey` - **オブジェクト配列に必須** - 項目のテキストに使用されるプロパティを指定します。`displayKey` に値が指定されていない場合、Simple ComboBox は指定された `valueKey` (存在する場合) を使用します。 -この場合、Simple ComboBox に各都市の `name` を表示し、Simple ComboBox の値に各都市の `id` を保存する必要があります。したがって、これらのプロパティを Simple ComboBox の `displayKey` と `valueKey` にそれぞれ提供します。 +この場合、Simple ComboBox に各都市の `name` を表示し、Simple ComboBox の値に各都市の `id` を保存する必要があります。そのため、これらのプロパティを値として Simple ComboBox の `displayKey` と `valueKey` にそれぞれバインドします。 ```html ``` -データ ソースが単純なタイプ (`string[]`、`number[]` など)で構成されている場合、`valueKey` と `displayKey` を**指定しないでください**。 +データ ソースが単純なタイプ (`string[]`、`number[]` など)で構成されている場合、`valueKey` と `displayKey` を**指定しないでください**。 ### 双方向バインディング -Simple ComboBox コンポーネントは、`[(ngModel)]` を使用した双方向のデータ バインディングと、[テンプレート駆動型](https://angular.io/guide/forms)および[リアクティブ フォーム](https://angular.io/guide/reactive-forms)での使用を完全にサポートします。Simple ComboBox の選択には、双方向バインディングまたは[選択 API](#選択-api) を介してアクセスできます。(`valueKey` に基づいて) Simple ComboBox の選択にあるものと同じタイプの項目を渡すことができ、一方が変更されるたびに、もう一方もそれに応じて更新されます。 +Simple ComboBox コンポーネントは、`[(ngModel)]` を使用した双方向のデータ バインディングと、[テンプレート駆動](https://angular.io/guide/forms)フォームおよび[リアクティブ](https://angular.io/guide/reactive-forms)フォームでの使用を完全にサポートします。Simple ComboBox の選択には、双方向バインディングまたは[選択 API](#選択-api) を介してアクセスできます。(`valueKey` に基づいて) Simple ComboBox の選択にあるものと同じタイプの項目を渡すことができ、一方が変更されるたびに、もう一方もそれに応じて更新されます。 次の例では、提供されたデータの最初の都市が最初に選択されます。Simple ComboBox の選択をさらに変更すると、`selectedCities` に反映されます。 @@ -170,14 +170,14 @@ export class MySimpleComboComponent { } ``` -選択 API を使用すると、ユーザーがコントロールを操作せずに、Simple ComboBox の選択された項目を変更することもできます (ボタンのクリックを介して、Observable の変更への応答としてなどです)。たとえば、 メソッドを使用して、都市を選択するボタンを実装できます。 +選択 API を使用すると、ボタンのクリックや Observable の変更への応答などにより、ユーザーがコントロールを操作しなくても、Simple ComboBox の選択された項目を変更することもできます。たとえば、 メソッドを使用して、都市を選択するボタンを実装できます。 ```html ``` -ボタンをクリックすると、London の都市が Simple ComboBox の選択に追加されます。 +ボタンをクリックすると、`London` が Simple ComboBox の選択に追加されます。 ```typescript export class MySimpleComboComponent { @@ -190,7 +190,7 @@ export class MySimpleComboComponent { } ``` -Simple ComboBox は、選択が変更されるたびに イベントを発生させます。発行されたイベント引数 には、変更前の選択、現在の選択、および表示された項目に関する情報が含まれています。イベントをキャンセルして、新しい項目による選択の更新を防ぐこともできます。 +Simple ComboBox は、選択が変更されるたびに イベントを発生させます。発行されたイベント引数 には、変更前の選択、現在の選択、および表示された項目に関する情報が含まれています。イベントをキャンセルして、選択が行われないようにすることもできます。 イベントへのバインドは、`igx-simple-combo` タグの適切な `@Output` プロパティを介して行うことができます。 @@ -204,8 +204,9 @@ Simple ComboBox は、選択が変更されるたびに が使用されるシナリオを示しています。 -[カスケード コンボを使用した Angular Grid のサンプル](../components/grid/cascading-combos.mdx)を参照してください。 +[カスケード コンボを使用した Angular Grid のサンプル](/grid/cascading-combos)を参照してください。
@@ -331,7 +329,7 @@ Ignite UI for Angular Simple ComboBox コンポーネントは、コンボボッ ```scss @use 'igniteui-angular/theming' as *; -// IMPORTANT: Prior to Ignite UI for Angular version 13 use: +// 重要: Ignite UI for Angular 13 より前のバージョンは、次を使用してください。 // @import '~igniteui-angular/lib/core/styles/themes/index'; ``` @@ -375,10 +373,12 @@ $custom-drop-down-theme: drop-down-theme( ``` - コンポーネントは、[`IgxOverlay`](/overlay) サービスを使用して、Simple ComboBox 項目リスト コンテナーを保持および表示します。スタイルを適切にスコープするには、 を使用してください。詳細については、[`IgxOverlay スタイル ガイド`](/overlay-styling)を確認してください。また、コンポーネントのスタイルを設定するときに `::ng-deep` を使用する必要があります。 + は、[`IgxOverlay`](/overlay) サービスを使用してリストを表示します。表示のカプセル化 (View Encapsulation) の設定や、生成されるセレクターが一致する必要がある場所によっては、ローカルでのテーマの include に引き続き `::ng-deep` が必要になる場合があります。また、デフォルトのデタッチされたアウトレットにアタッチされたリストは、コンボのホストからスタイルを継承できません。テーマを適用したコンテナーの下に を構成するか、アウトレットに一致するセレクターからテーマを出力してください。詳細については、[`IgxOverlay スタイル ガイド`](/overlay-styling)を参照してください。 +[!Note] +`IgxSimpleCombo` のデフォルトの `type` は `box` です。これは、デフォルトが `line` である [`IgxSelect`](/select) とは異なります。 -### サンプル +### デモ @@ -387,12 +387,12 @@ $custom-drop-down-theme: drop-down-theme( ## 既知の問題 - Simple ComboBox には、高さのサイズを設定するための入力がありません。将来、 コンポーネントは、カスタムのサイズ変更オプションを公開し、 は適切なスタイル設定と外観の統一に同じ機能を使用します。 -- シンプルなコンボボックスが `undefined` (例: `[ undefined, ...]`) を含むプリミティブ データの配列にバインドされる場合、`undefined` はドロップダウンに表示されません。複合データ (オブジェクトなど) の配列にバインドされ、`valueKey` に使用される値が `undefined` の場合、項目はドロップダウンに表示されますが、選択はできません。 -- シンプルなコンボボックスが `ngModel` でバインドされ、`required` とマークされている場合、`null`、`undefined`、`''` の値は選択できません。 -- シンプルなコンボボックスがリモート サービスにバインドされ、定義済みの選択がある場合、要求されたデータが読み込まれるまでその入力は空白のままになります。 +- Simple ComboBox が `undefined` (例: `[ undefined, ...]`) を含むプリミティブ データの配列にバインドされる場合、`undefined` はドロップダウンに表示されません。複合データ (オブジェクトなど) の配列にバインドされ、`valueKey` に使用される値が `undefined` の場合、項目はドロップダウンに表示されますが、選択はできません。 +- Simple ComboBox が `ngModel` でバインドされ、`required` とマークされている場合、`null`、`undefined`、`''` の値は選択できません。 +- Simple ComboBox がリモート サービスにバインドされ、定義済みの選択がある場合、要求されたデータが読み込まれるまでその入力は空白のままになります。 -Simple ComboBox は内部で `igxForOf` ディレクティブを使用するため、すべての `igxForOf` 制限は Simple ComboBox に対して有効です。詳細については、[igxForOf 既知の制限](/for-of#既知の制限) の既知の問題のセクションを参照してください。 +Simple ComboBox は内部でリストの仮想化に [Virtual Scroll](./layouts/virtual-scroll.mdx) コンポーネントを使用するため、すべての Virtual Scroll の制限が Simple ComboBox に対して有効です。詳細については、[Virtual Scroll の既知の制限](./layouts/virtual-scroll.mdx#既知の制限)セクションを参照してください。 ## API リファレンス @@ -409,15 +409,15 @@ Simple ComboBox は内部で `igxForOf` ディレクティブを使用するた ## テーマの依存関係 -- -- -- +- +- +- ## その他のリソース
-- [コンボボックス コンポーネント](/combo-features) +- [コンボボックス機能](/combo-features) - [コンボボックス リモート バインディング](/combo-remote) - [コンボボックス テンプレート](/combo-templates) - [テンプレート駆動フォームの統合](/input-group) diff --git a/docs/angular/src/content/jp/components/themes/misc/angular-material-theming.mdx b/docs/angular/src/content/jp/components/themes/misc/angular-material-theming.mdx index 915b65552d..7838fc8b6d 100644 --- a/docs/angular/src/content/jp/components/themes/misc/angular-material-theming.mdx +++ b/docs/angular/src/content/jp/components/themes/misc/angular-material-theming.mdx @@ -418,7 +418,7 @@ $custom-mat-light-theme: mat.define-light-theme(( - [コンポーネント テーマ](../sass/component-themes.mdx) - [タイポグラフィ](../sass/typography.mdx) - [Avatar コンポーネント](../../layouts/avatar.mdx) -- [Button コンポーネント](../../button.mdx) +- [Button コンポーネント](../../inputs/button.mdx) - [Dialog コンポーネント](../../dialog.mdx) - [Icon コンポーネント](../../icon.mdx) - [Expansion Panel コンポーネント](../../expansion-panel.mdx) diff --git a/docs/angular/src/content/jp/components/themes/misc/bootstrap-theming.mdx b/docs/angular/src/content/jp/components/themes/misc/bootstrap-theming.mdx index 92b63f123f..e3ef3c4d7f 100644 --- a/docs/angular/src/content/jp/components/themes/misc/bootstrap-theming.mdx +++ b/docs/angular/src/content/jp/components/themes/misc/bootstrap-theming.mdx @@ -368,7 +368,7 @@ Ignite UI for Angular は、テーマごとに 4 つのデフォルト タイプ - [コンポーネント テーマ](../sass/component-themes.mdx) - [タイポグラフィ](../sass/typography.mdx) - [Avatar コンポーネント](../../layouts/avatar.mdx) -- [Button コンポーネント](../../button.mdx) +- [Button コンポーネント](../../inputs/button.mdx) - [Dialog コンポーネント](../../dialog.mdx) - [Icon コンポーネント](../../icon.mdx) - [List コンポーネント](../../list.mdx) diff --git a/docs/angular/src/content/jp/components/themes/palettes.mdx b/docs/angular/src/content/jp/components/themes/palettes.mdx index c34c330171..08967f2fee 100644 --- a/docs/angular/src/content/jp/components/themes/palettes.mdx +++ b/docs/angular/src/content/jp/components/themes/palettes.mdx @@ -61,17 +61,17 @@ Ignite UI for Angular は、`primary`、`secondary`、`surface`、`gray`、`info :root { //... --ig-primary-500: #09f; - --ig-primary-500-contrast: hsl(from color(from var(--ig-primary-500) var(--y-contrast)) h 0 l); + --ig-primary-500-contrast: hsla(from color(from var(--ig-primary-500) var(--y-contrast)) h 0 l / 1); --ig-primary-600: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-primary-600-contrast: hsl(from color(from var(--ig-primary-600) var(--y-contrast)) h 0 l); + --ig-primary-600-contrast: hsla(from color(from var(--ig-primary-600) var(--y-contrast)) h 0 l / 1); --ig-primary-700: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.81)); //... --ig-secondary-400: hsl(from var(--ig-secondary-500) h calc(s * 0.875) calc(l * 1.08)); - --ig-secondary-400-contrast: hsl(from color(from var(--ig-secondary-400) var(--y-contrast)) h 0 l); + --ig-secondary-400-contrast: hsla(from color(from var(--ig-secondary-400) var(--y-contrast)) h 0 l / 1); --ig-secondary-500: #df1b74; - --ig-secondary-500-contrast: hsl(from color(from var(--ig-secondary-500) var(--y-contrast)) h 0 l); + --ig-secondary-500-contrast: hsla(from color(from var(--ig-secondary-500) var(--y-contrast)) h 0 l / 1); --ig-secondary-600: hsl(from var(--ig-secondary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-secondary-600-contrast: hsl(from color(from var(--ig-secondary-600) var(--y-contrast)) h 0 l); + --ig-secondary-600-contrast: hsla(from color(from var(--ig-secondary-600) var(--y-contrast)) h 0 l / 1); //... --ig-wcag-a: 0.31; --ig-wcag-aa: 0.185; diff --git a/docs/angular/src/content/jp/components/themes/roundness.mdx b/docs/angular/src/content/jp/components/themes/roundness.mdx index 98b8d2cf50..09fed4eb15 100644 --- a/docs/angular/src/content/jp/components/themes/roundness.mdx +++ b/docs/angular/src/content/jp/components/themes/roundness.mdx @@ -22,7 +22,7 @@ Ignite UI for Angular では、丸みを 0 から 1 の間の値で調整する `--ig-radius-factor` を 0 に設定すると、コンポーネントは最小の border-radius を使用し、角がシャープなブロック状に表示されます。1 に設定すると、最大の border-radius が適用され、より丸みを帯びた外観になります。 以下は、定義済みの最小および最大の境界半径値を持ち、`--ig-radius-factor` 変数を使用して変更できるコンポーネントのリストです。
-• [Action Strip](../action-strip.mdx) • [Button](../button.mdx) • [Button Group](../inputs/button-group.mdx) • [Calendar](../calendar.mdx) • [Card](../card.mdx) • [Carousel](../carousel.mdx) • [Checkbox](../checkbox.mdx) • [Chip](../chip.mdx) • [Combo](../combo.mdx) • [Date Picker](../date-picker.mdx) • [Date Range Picker](../date-range-picker.mdx) • [Grid](../grid/grid.mdx) • [Input Group](../input-group.mdx) • [Linear Progress](../linear-progress.mdx) • [List](../list.mdx) • [Month Picker](../month-picker.mdx) • [Navigation Drawer](../navdrawer.mdx) • [Radio](../radio-button.mdx) • [Ripple](../ripple.mdx) • [Snackbar](../snackbar.mdx) • [Switch](../switch.mdx) • [Toast](../toast.mdx) +• [Action Strip](../action-strip.mdx) • [Button](../inputs/button.mdx) • [Button Group](../inputs/button-group.mdx) • [Calendar](../calendar.mdx) • [Card](../card.mdx) • [Carousel](../carousel.mdx) • [Checkbox](../checkbox.mdx) • [Chip](../chip.mdx) • [Combo](../combo.mdx) • [Date Picker](../date-picker.mdx) • [Date Range Picker](../date-range-picker.mdx) • [Grid](../grid/grid.mdx) • [Input Group](../input-group.mdx) • [Linear Progress](../linear-progress.mdx) • [List](../list.mdx) • [Month Picker](../month-picker.mdx) • [Navigation Drawer](../navdrawer.mdx) • [Radio](../radio-button.mdx) • [Ripple](../ripple.mdx) • [Snackbar](../snackbar.mdx) • [Switch](../switch.mdx) • [Toast](../toast.mdx) ## 使用方法 diff --git a/docs/angular/src/content/jp/components/time-picker.mdx b/docs/angular/src/content/jp/components/time-picker.mdx index c0954cf9b9..6f99ff17ef 100644 --- a/docs/angular/src/content/jp/components/time-picker.mdx +++ b/docs/angular/src/content/jp/components/time-picker.mdx @@ -407,7 +407,7 @@ $my-time-picker-theme: time-picker-theme( ``` -Time Picker ウィンドウのコンテンツの一部として使用される追加コンポーネント ([`IgxButton`](/button) など) をスタイルするには、それぞれのコンポーネントに固有の追加テーマを作成し、ダイアログ ウィンドウのスコープ内のみに配置する必要があります (残りのアプリケーションの影響を受けません)。 +Time Picker ウィンドウのコンテンツの一部として使用される追加コンポーネント ([`IgxButton`](./inputs/button.mdx) など) をスタイルするには、それぞれのコンポーネントに固有の追加テーマを作成し、ダイアログ ウィンドウのスコープ内のみに配置する必要があります (残りのアプリケーションの影響を受けません)。 Time Picker ウィンドウは [`IgxOverlayService`](/overlay) を使用するため、カスタム テーマがスタイルを設定する Time Picker ウィンドウに適用されるように、ダイアログ ウィンドウが表示されたときに DOM に配置される特定のアウトレットを提供します。 diff --git a/docs/angular/src/content/jp/components/toc.json b/docs/angular/src/content/jp/components/toc.json index 4824dd0c4b..4f739d3f66 100644 --- a/docs/angular/src/content/jp/components/toc.json +++ b/docs/angular/src/content/jp/components/toc.json @@ -483,6 +483,12 @@ "updated": false, "premium": true }, + { + "name": "テーマ設定", + "href": "grid/theming.mdx", + "new": true, + "premium": true + }, { "name": "キーボード ナビゲーション", "href": "grid/keyboard-navigation.mdx", @@ -759,6 +765,12 @@ "updated": false, "premium": true }, + { + "name": "テーマ設定", + "href": "treegrid/theming.mdx", + "new": true, + "premium": true + }, { "name": "グループ化", "href": "treegrid/groupby.mdx", @@ -1013,6 +1025,12 @@ "updated": false, "premium": true }, + { + "name": "テーマ設定", + "href": "hierarchicalgrid/theming.mdx", + "new": true, + "premium": true + }, { "name": "サイズ", "href": "hierarchicalgrid/display-density.mdx", @@ -1079,6 +1097,12 @@ "new": false, "updated": true, "premium": true + }, + { + "name": "テーマ設定", + "href": "pivotgrid/theming.mdx", + "new": true, + "premium": true } ] }, @@ -1809,6 +1833,11 @@ "href": "themes/spacing.mdx", "new": false }, + { + "name": "アクセシビリティ", + "href": "themes/accessibility.mdx", + "new": true + }, { "name": "Sass", "new": false, @@ -1953,7 +1982,7 @@ }, { "name": "Button", - "href": "button.mdx" + "href": "inputs/button.mdx" }, { "name": "Button Group", @@ -1970,7 +1999,7 @@ }, { "name": "Switch", - "href": "switch.mdx" + "href": "inputs/switch.mdx" }, { "name": "Query Builder", @@ -2045,6 +2074,11 @@ "name": "仮想スクロール ディレクティブ", "href": "for-of.mdx" }, + { + "name": "仮想スクロール", + "href": "layouts/virtual-scroll.mdx", + "new": true + }, { "name": "Chip", "href": "chip.mdx", diff --git a/docs/angular/src/content/jp/components/tooltip.mdx b/docs/angular/src/content/jp/components/tooltip.mdx index 4f3990798e..7cb762afa4 100644 --- a/docs/angular/src/content/jp/components/tooltip.mdx +++ b/docs/angular/src/content/jp/components/tooltip.mdx @@ -466,7 +466,7 @@ $dark-tooltip: tooltip-theme( ``` -ダイアログ ウィンドウのコンテンツの一部として使用される追加コンポーネント ([`IgxButton`](/button)、[`IgxSwitch`](/switch) など) をスタイルするには、それぞれのコンポーネントに固有の追加テーマを作成し、ツールチップのスコープ内のみに配置する必要があります (残りのアプリケーションの影響を受けません)。 +ダイアログ ウィンドウのコンテンツの一部として使用される追加コンポーネント ([`IgxButton`](./inputs/button.mdx)、[`IgxSwitch`](/switch) など) をスタイルするには、それぞれのコンポーネントに固有の追加テーマを作成し、ツールチップのスコープ内のみに配置する必要があります (残りのアプリケーションの影響を受けません)。 ツールチップは [`IgxOverlayService`](/overlay) を使用するため、スタイル設定するツールチップにカスタム テーマが適用されるよう、ダイアログ ウィンドウが表示されたときに DOM に配置される特定のアウトレットを提供します。 diff --git a/docs/angular/src/content/jp/components/treegrid/tree-grid.mdx b/docs/angular/src/content/jp/components/treegrid/tree-grid.mdx index e546e82ff7..63173da4cf 100644 --- a/docs/angular/src/content/jp/components/treegrid/tree-grid.mdx +++ b/docs/angular/src/content/jp/components/treegrid/tree-grid.mdx @@ -328,7 +328,7 @@ $custom-grid: grid-theme( ### Angular ツリー グリッド スタイル設定のデモ - + より詳細なカスタマイズが必要な場合は、 に追加のパラメーターがあります。 diff --git a/docs/angular/src/content/jp/grids_templates/row-editing.mdx b/docs/angular/src/content/jp/grids_templates/row-editing.mdx index 21f2e5d773..75b827a571 100644 --- a/docs/angular/src/content/jp/grids_templates/row-editing.mdx +++ b/docs/angular/src/content/jp/grids_templates/row-editing.mdx @@ -324,9 +324,9 @@ export class HGridRowEditingSampleComponent implements OnInit { [Ignite UI for Angular テーマ ライブラリ](/themes)を使用して、行編集オーバーレイを大幅に変更できます。 行編集オーバーレイは複合要素です。UI は、他の 2 つのコンポーネントで構成されています。 - コンテンツをレンダリングするための [`igx-banner`](/banner) - - [`igx-button`](/button) はデフォルトのテンプレートでレンダリングされます (`[完了]` ボタンと `[キャンセル]` ボタンの場合)。 + - [`igx-button`](inputs/button) はデフォルトのテンプレートでレンダリングされます (`[完了]` ボタンと `[キャンセル]` ボタンの場合)。 -以下の例では、これら 2 つのコンポーネントのスタイル設定オプション ([`ボタンのスタイル設定`](/button#スタイル設定) & [`バナーのスタイル設定`](/banner#スタイル設定)) を使用して、{ComponentName} の行編集のエクスペリエンスをカスタマイズします。 +以下の例では、これら 2 つのコンポーネントのスタイル設定オプション ([`ボタンのスタイル設定`](inputs/button#スタイル設定) & [`バナーのスタイル設定`](/banner#スタイル設定)) を使用して、{ComponentName} の行編集のエクスペリエンスをカスタマイズします。 次に、現在のセルのエディターと背景をより明確にするためにスタイルを設定します。セル スタイリングの詳細については、[こちら](/{igPath}/cell-editing#スタイル設定)をご覧ください。 ### テーマのインポート diff --git a/docs/angular/src/content/jp/grids_templates/search.mdx b/docs/angular/src/content/jp/grids_templates/search.mdx index 960f7f1d8e..a9270a90c2 100644 --- a/docs/angular/src/content/jp/grids_templates/search.mdx +++ b/docs/angular/src/content/jp/grids_templates/search.mdx @@ -253,7 +253,7 @@ public updateExactSearch() { ### アイコンの追加 その他のコンポーネントを使用するためにユーザー インターフェイスを作成し、検索バー全体のデザインを向上します。検索入力の左側に検索または削除アイコン、検索オプションのチップ、右側にはマテリアル デザイン アイコンと Ripple スタイルのボタンを組み合わせたナビゲーションを表示できます。入力グループ内のコンポーネントをラップしてより洗練されたデザインにすることができます。 -[**IgxInputGroup**](/input-group)、[**IgxIcon**](/icon)、[**IgxRipple**](/ripple)、[**IgxButton**](/button)、[**IgxChip**](/chip) のモジュールを使用します。 +[**IgxInputGroup**](/input-group)、[**IgxIcon**](/icon)、[**IgxRipple**](/ripple)、[**IgxButton**](inputs/button)、[**IgxChip**](/chip) のモジュールを使用します。 ```typescript // app.module.ts diff --git a/docs/angular/src/content/jp/grids_templates/theming.mdx b/docs/angular/src/content/jp/grids_templates/theming.mdx new file mode 100644 index 0000000000..4fdc24c93e --- /dev/null +++ b/docs/angular/src/content/jp/grids_templates/theming.mdx @@ -0,0 +1,248 @@ + + +--- +title: Angular Grid テーマ設定 - Ignite UI for Angular +description: Ignite UI for Angular Grid は grid-theme() を通じてテーマが適用されます。この Sass 関数は、3 つの主要トークンからコンポーネントのすべての色を導出します。 +keywords: angular グリッド テーマ, angular グリッド スタイル設定, グリッド テーマ, ignite ui for angular, infragistics +license: commercial +last_updated: "2026-08-27" +_language: ja +llms: + description: "Ignite UI for Angular Grid は grid-theme() を通じてテーマが適用されます。この関数は背景、前景、アクセント トークンからすべての色を導出します。" +--- + + + + +--- +title: Angular Tree Grid テーマ設定 - Ignite UI for Angular +description: Ignite UI for Angular Tree Grid は grid-theme() を通じてテーマが適用されます。この Sass 関数は、3 つの主要トークンからコンポーネントのすべての色を導出します。 +keywords: angular ツリー グリッド テーマ, angular ツリー グリッド スタイル設定, グリッド テーマ, ignite ui for angular, infragistics +license: commercial +_canonicalLink: grid/theming +last_updated: "2026-08-27" +_language: ja +llms: + description: "Ignite UI for Angular Tree Grid は grid-theme() を通じてテーマが適用されます。この関数は背景、前景、アクセント トークンからすべての色を導出します。" +--- + + + + +--- +title: Angular Hierarchical Grid テーマ設定 - Ignite UI for Angular +description: Ignite UI for Angular Hierarchical Grid は grid-theme() を通じてテーマが適用されます。この Sass 関数は、3 つの主要トークンからコンポーネントのすべての色を導出します。 +keywords: angular 階層グリッド テーマ, angular 階層グリッド スタイル設定, グリッド テーマ, ignite ui for angular, infragistics +license: commercial +_canonicalLink: grid/theming +last_updated: "2026-08-27" +_language: ja +llms: + description: "Ignite UI for Angular Hierarchical Grid は grid-theme() を通じてテーマが適用されます。この関数は背景、前景、アクセント トークンからすべての色を導出します。" +--- + + + + +--- +title: Angular Pivot Grid テーマ設定 - Ignite UI for Angular +description: Ignite UI for Angular Pivot Grid は grid-theme() を通じてテーマが適用されます。この Sass 関数は、3 つの主要トークンからコンポーネントのすべての色を導出します。 +keywords: angular ピボット グリッド テーマ, angular ピボット グリッド スタイル設定, グリッド テーマ, ignite ui for angular, infragistics +license: commercial +_canonicalLink: grid/theming +last_updated: "2026-08-27" +_language: ja +llms: + description: "Ignite UI for Angular Pivot Grid は grid-theme() を通じてテーマが適用されます。この関数は背景、前景、アクセント トークンからすべての色を導出します。" +--- + + + +import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; +import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; +import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; + +# Angular {ComponentTitle} テーマ設定 + +Ignite UI for Angular {ComponentTitle} は を通じてテーマが適用されます。この関数は背景、前景、アクセント トークンの 3 つからすべての色を導出します。これら 3 つの主要トークンは、ヘッダー、行、境界線、集計、ツールバー、ページネーター、フィルタリング ポップアップなど、コンポーネントがレンダリングするすべてに反映されます。 + + +グリッドごとに個別のテーマ関数はありません。Data Grid、Tree Grid、Hierarchical Grid、Pivot Grid はすべて `grid-theme()` を読み取ります。そのため、同じテーマを変更なしにどのグリッドにも適用できます。 + + +## Angular {ComponentTitle} テーマ設定の例 + +以下の 4 つのテーマはカスタム テーマです。ライブラリに付属のものではなく、このサンプル用に作成されました。各テーマは色に関しては 3 つの主要トークンのみを設定しているため、テーマを切り替えると 3 つの値がどこまで影響するかを確認できます。 + + + + + + + + + + + + + + + + + + + + + + +## はじめに + +テーマ関数と `tokens()` ミックスインがエクスポートされているテーマ エントリ ポイントをインポートします。 + +```scss +@use "igniteui-angular/theming" as *; +``` + +次に、テーマを宣言して適用したい要素に含めます。 + +```scss +:host { + @include tokens(grid-theme( + $background: #08002e, + $accent-color: #ff7d52 + )); +} +``` + +これで完全なテーマになります。{ComponentTitle} は濃いインディゴにコーラル アクセントで表示され、テキスト、ヘッダー、行の境界線、ホバー状態、選択の色合い、ポップアップの外枠はすべて自動的に計算されます。 + +## 主要トークン + +{ComponentTitle} テーマは 3 つのトークンから構築されます。他のすべての色はそれらから導出されます。 + +| トークン | 制御対象 | +| -- | -- | +| `$background` | コンポーネント全体が構築されるサーフェス。他のすべてのサーフェスとデフォルトの前景色はこれから導出されます。 | +| `$foreground` | テキストとアイコン。未設定の場合は `$background` からコントラストで導出されます。 | +| `$accent-color` | インタラクティブな色: ソート インジケーター、選択、ホバーの色合い、フォーカス。 | + +`$foreground` は主要トークンとして挙げられていますが、設定が必要になることはほとんどありません。指定しない場合、背景に対してコントラストが確保されるように選択されます。暗い背景には明るいテキスト、明るい背景には暗いテキストが適用されます。 + +## 導出の仕組み + +テーマを宣言すると、導出トークンはビルド時に固定の色に解決されるのではなく、指定した主要トークンを参照する CSS 式として出力されます。 + +```css +.my-grid { + --ig-grid-foreground: hsla(from color(from var(--ig-grid-background) var(--y-contrast)) h 0 l/1); + --ig-grid-header-background: color-mix(in srgb, var(--ig-grid-foreground) 6%, var(--ig-grid-background)); + --ig-grid-row-hover-background: color-mix(in srgb, var(--ig-grid-accent-color) 8%, var(--ig-grid-row-odd-background)); + --ig-grid-sorted-header-icon-color: hsl(from var(--ig-grid-accent-color) h s l/0.7); +} +``` + +これには 2 つの効果があります。主要トークンを変更すると、そこから導出されるすべての値が再計算されます。CSS カスタム プロパティを通じて、ランタイムでも再計算されます。また、どのような値を指定しても関係性が維持されるため、テーマが自己矛盾を起こすことはありません。 + +## さらに詳しく + +一部のトークンは、それ自体が導出の起点になります。宣言すると背景から切り離され、その上にあるものは新しい値から導出されます。 + +`$header-background` が最もわかりやすい例です。未設定の場合は `$background` から混合され、ヘッダーのテキストは `$foreground` に従います。宣言すると、ヘッダーのテキストはヘッダー自体に対してコントラストを取るように再導出されます。 + +```scss +:host { + @include tokens(grid-theme( + $background: #08002e, + $accent-color: #ff7d52, + $header-background: #ff7d52 + )); +} +``` + + +これらのトークンは、サーフェスが背景に追従しないようにしたい場合にのみ使用してください。テーマが自動導出としてドキュメント化しているほとんどのトークンは、そのままにしておくのが最善です。1 つを上書きすると、本来はテーマの他の部分と連動するはずだった値が固定されてしまいます。 + + +## 構造 + +色はテーマの半分にすぎません。密度と丸みは `grid-theme()` パラメーターではなく、グローバルなデザイン システム トークンで制御されるため、プレーンなカスタム プロパティとして設定します。 + +```scss +:host { + --ig-size: var(--ig-size-small); // small | medium | large + --ig-radius-factor: 0; // 0 ~ 1 + + @include tokens(grid-theme( + $background: #08002e, + $accent-color: #ff7d52 + )); +} +``` + +グリッド線はテーマ パラメーターです。非表示にするには、削除するのではなく背後のサーフェスと同じ色になじませます。こうすることで、テーマが変わっても行のメトリクスが変化しません。 + +```scss +@include tokens(grid-theme( + // 水平区切り線をなじませる + $row-border-color: var(--ig-grid-background), + // 垂直区切り線を、テーマが行に対して導出する色で描画する + $body-column-border-color-odd: hsl(from color-mix(in srgb, var(--ig-grid-foreground) 16%, var(--ig-grid-background)) h s l/0.38), + $body-column-border-color-even: hsl(from color-mix(in srgb, var(--ig-grid-foreground) 16%, var(--ig-grid-background)) h s l/0.38) +)); +``` + +## CSS 変数 + +デフォルトの外観は意図的なもので、導出によるものではありません。初期状態では {ComponentTitle} は Ignite UI デザイン仕様に正確に一致し、背景から色を計算するのではなく、ベース パレットに対して解決されます。導出が働くのは、独自のテーマを宣言したときだけです。 + +このことは、CSS のみでテーマ設定する場合に実用上の影響が 1 つあります。テーマを宣言するまで、上書きすべき導出式がありません。コンポーネントは `var(--ig-grid-header-background, var(--ig-gray-100))` などを読み取るため、いくつかのカスタム プロパティを手動で設定するだけでは**カスケードしません**。 + +```css +/* これだけでは不十分: 背景は変わるが、ヘッダーはグレーのまま。 */ +.my-grid { + --ig-grid-background: #08002e; + --ig-grid-accent-color: #ff7d52; +} +``` + +Sass ビルドなしでテーマを適用するには、**完全なトークン セット** (ルートとそれを参照する導出式) を宣言します。各導出トークンはルートに対する式であるため、このブロックは自己完結しています。 + +```css +.my-grid { + --ig-grid-background: #08002e; + --ig-grid-accent-color: #ff7d52; + --ig-grid-foreground: hsla(from color(from var(--ig-grid-background) var(--y-contrast)) h 0 l/1); + --ig-grid-header-background: color-mix(in srgb, var(--ig-grid-foreground) 6%, var(--ig-grid-background)); + /* … その他のテーマ トークン */ +} +``` + +手動で生成するのは現実的ではないため、以下のプレイグラウンドを使用してください。選択した色に対する完全なブロックが出力されます。 + + +可能な場合は Sass の方法を優先してください。`grid-theme()` が導出トークンを記述し、ライブラリとの同期を維持します。手動で管理する CSS ブロックはスナップショットであり、テーマへの変更を自動的に反映しません。 + + +## 試してみる + +色を変更して、ヘッダー、行、集計、ページネーター、フィルタリング ポップアップにどこまで影響するか確認してください。グリッドを切り替えて、同じトークンがすべてのグリッドで機能することを確認し、気に入ったら生成されたテーマをコピーしてください。 + + + +## API リファレンス + +- +- + +## その他のリソース + +- [{ComponentTitle} 概要](/{igPath}/{ComponentMainTopic}) +- [パレット](/themes/sass/palettes) +- [タイポグラフィ](/themes/typography) + + + +- [サイズ](/{igPath}/display-density) +- [条件付きスタイル設定](/{igPath}/conditional-cell-styling) + + diff --git a/docs/angular/src/content/jp/images/anatomy-content-light/button-lt-a.png b/docs/angular/src/content/jp/images/anatomy-content-light/button-lt-a.png new file mode 100644 index 0000000000..05656c6c3e Binary files /dev/null and b/docs/angular/src/content/jp/images/anatomy-content-light/button-lt-a.png differ diff --git a/docs/angular/src/content/jp/images/anatomy-content-light/qr-code-lt-a.png b/docs/angular/src/content/jp/images/anatomy-content-light/qr-code-lt-a.png new file mode 100644 index 0000000000..3ffa3c018b Binary files /dev/null and b/docs/angular/src/content/jp/images/anatomy-content-light/qr-code-lt-a.png differ diff --git a/docs/angular/src/content/jp/images/anatomy-content-light/switch-lt-a.png b/docs/angular/src/content/jp/images/anatomy-content-light/switch-lt-a.png new file mode 100644 index 0000000000..a52a0c650e Binary files /dev/null and b/docs/angular/src/content/jp/images/anatomy-content-light/switch-lt-a.png differ diff --git a/docs/angular/src/content/jp/images/button/button-do-1.png b/docs/angular/src/content/jp/images/button/button-do-1.png new file mode 100644 index 0000000000..9243c7edbd Binary files /dev/null and b/docs/angular/src/content/jp/images/button/button-do-1.png differ diff --git a/docs/angular/src/content/jp/images/button/button-do-2.png b/docs/angular/src/content/jp/images/button/button-do-2.png new file mode 100644 index 0000000000..d833307a65 Binary files /dev/null and b/docs/angular/src/content/jp/images/button/button-do-2.png differ diff --git a/docs/angular/src/content/jp/images/button/button-do-3.png b/docs/angular/src/content/jp/images/button/button-do-3.png new file mode 100644 index 0000000000..d833307a65 Binary files /dev/null and b/docs/angular/src/content/jp/images/button/button-do-3.png differ diff --git a/docs/angular/src/content/jp/images/button/button-do-not-1.png b/docs/angular/src/content/jp/images/button/button-do-not-1.png new file mode 100644 index 0000000000..2f37198ea3 Binary files /dev/null and b/docs/angular/src/content/jp/images/button/button-do-not-1.png differ diff --git a/docs/angular/src/content/jp/images/button/button-do-not-2.png b/docs/angular/src/content/jp/images/button/button-do-not-2.png new file mode 100644 index 0000000000..aa39725522 Binary files /dev/null and b/docs/angular/src/content/jp/images/button/button-do-not-2.png differ diff --git a/docs/angular/src/content/jp/images/button/button-do-not-3.png b/docs/angular/src/content/jp/images/button/button-do-not-3.png new file mode 100644 index 0000000000..473d3e6ed6 Binary files /dev/null and b/docs/angular/src/content/jp/images/button/button-do-not-3.png differ diff --git a/docs/angular/src/content/jp/images/qr-code/qr-code-do-not1.png b/docs/angular/src/content/jp/images/qr-code/qr-code-do-not1.png new file mode 100644 index 0000000000..70764cd765 Binary files /dev/null and b/docs/angular/src/content/jp/images/qr-code/qr-code-do-not1.png differ diff --git a/docs/angular/src/content/jp/images/qr-code/qr-code-do-not1@2x.png b/docs/angular/src/content/jp/images/qr-code/qr-code-do-not1@2x.png new file mode 100644 index 0000000000..52a584d1de Binary files /dev/null and b/docs/angular/src/content/jp/images/qr-code/qr-code-do-not1@2x.png differ diff --git a/docs/angular/src/content/jp/images/qr-code/qr-code-do-not2.png b/docs/angular/src/content/jp/images/qr-code/qr-code-do-not2.png new file mode 100644 index 0000000000..aca377f3a3 Binary files /dev/null and b/docs/angular/src/content/jp/images/qr-code/qr-code-do-not2.png differ diff --git a/docs/angular/src/content/jp/images/qr-code/qr-code-do-not2@2x.png b/docs/angular/src/content/jp/images/qr-code/qr-code-do-not2@2x.png new file mode 100644 index 0000000000..ef33cbe601 Binary files /dev/null and b/docs/angular/src/content/jp/images/qr-code/qr-code-do-not2@2x.png differ diff --git a/docs/angular/src/content/jp/images/qr-code/qr-code-do1.png b/docs/angular/src/content/jp/images/qr-code/qr-code-do1.png new file mode 100644 index 0000000000..86e7240d5b Binary files /dev/null and b/docs/angular/src/content/jp/images/qr-code/qr-code-do1.png differ diff --git a/docs/angular/src/content/jp/images/qr-code/qr-code-do1@2x.png b/docs/angular/src/content/jp/images/qr-code/qr-code-do1@2x.png new file mode 100644 index 0000000000..d512af1fc2 Binary files /dev/null and b/docs/angular/src/content/jp/images/qr-code/qr-code-do1@2x.png differ diff --git a/docs/angular/src/content/jp/images/qr-code/qr-code-do2.png b/docs/angular/src/content/jp/images/qr-code/qr-code-do2.png new file mode 100644 index 0000000000..67f8c0c220 Binary files /dev/null and b/docs/angular/src/content/jp/images/qr-code/qr-code-do2.png differ diff --git a/docs/angular/src/content/jp/images/qr-code/qr-code-do2@2x.png b/docs/angular/src/content/jp/images/qr-code/qr-code-do2@2x.png new file mode 100644 index 0000000000..91b49814fe Binary files /dev/null and b/docs/angular/src/content/jp/images/qr-code/qr-code-do2@2x.png differ diff --git a/docs/angular/src/content/jp/images/switch/switch-do-not.png b/docs/angular/src/content/jp/images/switch/switch-do-not.png new file mode 100644 index 0000000000..236f605389 Binary files /dev/null and b/docs/angular/src/content/jp/images/switch/switch-do-not.png differ diff --git a/docs/angular/src/content/jp/images/switch/switch-do.png b/docs/angular/src/content/jp/images/switch/switch-do.png new file mode 100644 index 0000000000..111adf80b9 Binary files /dev/null and b/docs/angular/src/content/jp/images/switch/switch-do.png differ diff --git a/docs/xplat/package.json b/docs/xplat/package.json index 8fa2b2ecf7..2f8cd3a762 100644 --- a/docs/xplat/package.json +++ b/docs/xplat/package.json @@ -62,10 +62,9 @@ "node": ">=22.12.0" }, "dependencies": { - "astro": "^7.2.2", + "astro": "^7.3.4", "docs-template": "file:../../", - "igniteui-astro-components": "1.0.2", - "sharp": "^0.35.3" + "igniteui-astro-components": "1.3.0" }, "devDependencies": { "cross-env": "^10.1.0", diff --git a/docs/xplat/src/assets/images/accordion/accordion_do1.png b/docs/xplat/src/assets/images/accordion/accordion_do1.png new file mode 100644 index 0000000000..148543500f Binary files /dev/null and b/docs/xplat/src/assets/images/accordion/accordion_do1.png differ diff --git a/docs/xplat/src/assets/images/accordion/accordion_do1@2x.png b/docs/xplat/src/assets/images/accordion/accordion_do1@2x.png new file mode 100644 index 0000000000..a7cf23b8cc Binary files /dev/null and b/docs/xplat/src/assets/images/accordion/accordion_do1@2x.png differ diff --git a/docs/xplat/src/assets/images/accordion/accordion_do_not1.png b/docs/xplat/src/assets/images/accordion/accordion_do_not1.png new file mode 100644 index 0000000000..2cd85c19bc Binary files /dev/null and b/docs/xplat/src/assets/images/accordion/accordion_do_not1.png differ diff --git a/docs/xplat/src/assets/images/accordion/accordion_dont1@2x.png b/docs/xplat/src/assets/images/accordion/accordion_dont1@2x.png new file mode 100644 index 0000000000..61f5c80b74 Binary files /dev/null and b/docs/xplat/src/assets/images/accordion/accordion_dont1@2x.png differ diff --git a/docs/xplat/src/assets/images/anatomy-content-light/qr-code-lt-a.png b/docs/xplat/src/assets/images/anatomy-content-light/qr-code-lt-a.png new file mode 100644 index 0000000000..3ffa3c018b Binary files /dev/null and b/docs/xplat/src/assets/images/anatomy-content-light/qr-code-lt-a.png differ diff --git a/docs/xplat/src/assets/images/anatomy-frame-light/Accordion-lt.png b/docs/xplat/src/assets/images/anatomy-frame-light/Accordion-lt.png new file mode 100644 index 0000000000..d13af44d2a Binary files /dev/null and b/docs/xplat/src/assets/images/anatomy-frame-light/Accordion-lt.png differ diff --git a/docs/xplat/src/assets/images/button/button-do-1.png b/docs/xplat/src/assets/images/button/button-do-1.png new file mode 100644 index 0000000000..9243c7edbd Binary files /dev/null and b/docs/xplat/src/assets/images/button/button-do-1.png differ diff --git a/docs/xplat/src/assets/images/button/button-do-2.png b/docs/xplat/src/assets/images/button/button-do-2.png new file mode 100644 index 0000000000..d833307a65 Binary files /dev/null and b/docs/xplat/src/assets/images/button/button-do-2.png differ diff --git a/docs/xplat/src/assets/images/button/button-do-3.png b/docs/xplat/src/assets/images/button/button-do-3.png new file mode 100644 index 0000000000..d833307a65 Binary files /dev/null and b/docs/xplat/src/assets/images/button/button-do-3.png differ diff --git a/docs/xplat/src/assets/images/button/button-do-not-1.png b/docs/xplat/src/assets/images/button/button-do-not-1.png new file mode 100644 index 0000000000..2f37198ea3 Binary files /dev/null and b/docs/xplat/src/assets/images/button/button-do-not-1.png differ diff --git a/docs/xplat/src/assets/images/button/button-do-not-2.png b/docs/xplat/src/assets/images/button/button-do-not-2.png new file mode 100644 index 0000000000..aa39725522 Binary files /dev/null and b/docs/xplat/src/assets/images/button/button-do-not-2.png differ diff --git a/docs/xplat/src/assets/images/button/button-do-not-3.png b/docs/xplat/src/assets/images/button/button-do-not-3.png new file mode 100644 index 0000000000..473d3e6ed6 Binary files /dev/null and b/docs/xplat/src/assets/images/button/button-do-not-3.png differ diff --git a/docs/xplat/src/assets/images/qr-code/qr-code-do-not1.png b/docs/xplat/src/assets/images/qr-code/qr-code-do-not1.png new file mode 100644 index 0000000000..70764cd765 Binary files /dev/null and b/docs/xplat/src/assets/images/qr-code/qr-code-do-not1.png differ diff --git a/docs/xplat/src/assets/images/qr-code/qr-code-do-not1@2x.png b/docs/xplat/src/assets/images/qr-code/qr-code-do-not1@2x.png new file mode 100644 index 0000000000..52a584d1de Binary files /dev/null and b/docs/xplat/src/assets/images/qr-code/qr-code-do-not1@2x.png differ diff --git a/docs/xplat/src/assets/images/qr-code/qr-code-do-not2.png b/docs/xplat/src/assets/images/qr-code/qr-code-do-not2.png new file mode 100644 index 0000000000..aca377f3a3 Binary files /dev/null and b/docs/xplat/src/assets/images/qr-code/qr-code-do-not2.png differ diff --git a/docs/xplat/src/assets/images/qr-code/qr-code-do-not2@2x.png b/docs/xplat/src/assets/images/qr-code/qr-code-do-not2@2x.png new file mode 100644 index 0000000000..ef33cbe601 Binary files /dev/null and b/docs/xplat/src/assets/images/qr-code/qr-code-do-not2@2x.png differ diff --git a/docs/xplat/src/assets/images/qr-code/qr-code-do1.png b/docs/xplat/src/assets/images/qr-code/qr-code-do1.png new file mode 100644 index 0000000000..86e7240d5b Binary files /dev/null and b/docs/xplat/src/assets/images/qr-code/qr-code-do1.png differ diff --git a/docs/xplat/src/assets/images/qr-code/qr-code-do1@2x.png b/docs/xplat/src/assets/images/qr-code/qr-code-do1@2x.png new file mode 100644 index 0000000000..d512af1fc2 Binary files /dev/null and b/docs/xplat/src/assets/images/qr-code/qr-code-do1@2x.png differ diff --git a/docs/xplat/src/assets/images/qr-code/qr-code-do2.png b/docs/xplat/src/assets/images/qr-code/qr-code-do2.png new file mode 100644 index 0000000000..67f8c0c220 Binary files /dev/null and b/docs/xplat/src/assets/images/qr-code/qr-code-do2.png differ diff --git a/docs/xplat/src/assets/images/qr-code/qr-code-do2@2x.png b/docs/xplat/src/assets/images/qr-code/qr-code-do2@2x.png new file mode 100644 index 0000000000..91b49814fe Binary files /dev/null and b/docs/xplat/src/assets/images/qr-code/qr-code-do2@2x.png differ diff --git a/docs/xplat/src/assets/images/switch/switch-do-not.png b/docs/xplat/src/assets/images/switch/switch-do-not.png new file mode 100644 index 0000000000..236f605389 Binary files /dev/null and b/docs/xplat/src/assets/images/switch/switch-do-not.png differ diff --git a/docs/xplat/src/assets/images/switch/switch-do.png b/docs/xplat/src/assets/images/switch/switch-do.png new file mode 100644 index 0000000000..111adf80b9 Binary files /dev/null and b/docs/xplat/src/assets/images/switch/switch-do.png differ diff --git a/docs/xplat/src/content/en/components/ai/theming-mcp.mdx b/docs/xplat/src/content/en/components/ai/theming-mcp.mdx index 8dd50be3cd..138235752d 100644 --- a/docs/xplat/src/content/en/components/ai/theming-mcp.mdx +++ b/docs/xplat/src/content/en/components/ai/theming-mcp.mdx @@ -275,6 +275,10 @@ To see the current full list of tools and their parameters at any time, ask your Here is a brief overview of each tool: + +When it generates a palette, the server checks the contrast ratio between your surface and gray colors against WCAG thresholds and warns you when the pairing falls short. See [Accessibility](../themes/accessibility.mdx) for the contrast behavior built into the theming engine itself. + + | Tool | Description | |------|-------------| | `detect_platform` | Identifies the project framework and selects the correct import paths and selectors. For Angular, React, and Web Components projects, reads `package.json`. For Blazor projects, which do not have a `package.json`, returns `generic` - tell the AI explicitly: _"Use the Blazor platform."_ | diff --git a/docs/xplat/src/content/en/components/inputs/badge.mdx b/docs/xplat/src/content/en/components/inputs/badge.mdx index 34563f06e4..abd476caaf 100644 --- a/docs/xplat/src/content/en/components/inputs/badge.mdx +++ b/docs/xplat/src/content/en/components/inputs/badge.mdx @@ -29,13 +29,13 @@ The {Platform} Badge demo shows how the component can communicate a compact stat - + - + @@ -77,20 +77,20 @@ The component renders its content inside the `base` CSS part. Use the component' ## Getting Started -To use the {Platform} Badge, follow the [{ProductName} Getting Started](../general-getting-started.mdx) topic for the basic project setup, then register the component for your target platform. +To use the {Platform} Badge, follow the [{ProductName} Getting Started](../general/getting-started.mdx)[{ProductName} Getting Started](../general-getting-started.mdx) topic for the basic project setup, then register the component for your target platform. -### Prerequisites and Version Compatibility - -Use a supported version of the {ProductName} package for your target framework. Keep the framework package, the Badge package, and the theme package on the same release version. The examples below identify the framework and package used by each code block so that the snippets remain self-contained when read without the surrounding page context. - - + -For Web Components using the **{PackageWebComponents}** package, install the package: +For {Platform} using the **{PackageCommon}** package, install the package: ```cmd -npm install {PackageWebComponents} +npm install {PackageCommon} ``` + + + + You will then need to import the , its theme CSS, and register the component, like so: ```ts @@ -104,12 +104,6 @@ defineComponents(IgcBadgeComponent); -For React using the **igniteui-react** package, install the package: - -```cmd -npm install igniteui-react -``` - You will then need to import the Badge wrapper and its theme CSS, like so: ```tsx @@ -145,16 +139,18 @@ For Angular using the **igniteui-angular** package, install the package: npm install igniteui-angular ``` -Then import the Badge component: +Then import `IgxBadgeComponent` in the component `imports` collection. ```ts import { IgxBadgeComponent } from 'igniteui-angular/badge'; ``` -Add `IgxBadgeComponent` to the component `imports` collection, then use the `igx-badge` element in your template. + The simplest way to start using the is as follows: + + ```html ``` @@ -163,8 +159,6 @@ The simplest way to start using the is as fo -The simplest way to start using the is as follows: - ```html ``` @@ -255,7 +249,7 @@ You can also project content directly. When projecting both an icon and text, wr ``` - + #### Icon In addition to Material Icons, the Angular Badge supports Material Icons Extended and other custom icon sets. Register the custom icon with `IgxIconService`, then specify its name and icon set: @@ -268,7 +262,7 @@ this._iconService.addSvgIconFromText(heartMonitor.name, heartMonitor.value, 'imx ``` - + #### Dot @@ -280,7 +274,7 @@ Set the attribute t ``` - + ### Size @@ -295,7 +289,7 @@ igx-badge { } ``` - + ### Shape @@ -305,7 +299,7 @@ The Badge shape can be set to `rounded` (the default) or `square` with the ``` - + When the Badge has a `square` shape, it can be further customized by setting a custom border radius using the `--border-radius` CSS variable. @@ -317,7 +311,7 @@ The Angular Badge supports the Primary, Info, Success, Warn, and Error types. Se ``` - + @@ -460,7 +454,7 @@ You can also project content directly. When projecting both an icon and text, wr - + #### Icon @@ -536,7 +530,7 @@ registerIconFromText( - + #### Dot @@ -568,7 +562,7 @@ Set the attribute t - + ### Size @@ -583,7 +577,7 @@ igc-badge { } ``` - + ### Shape @@ -615,7 +609,7 @@ The badge component supports `rounded`(default) and `square` shapes. These value - + When the badge has a `square` shape, it can be further customized by setting a custom border radius using the `--border-radius` CSS variable. @@ -649,7 +643,7 @@ The {ProductName} Badge supports several pre-defined stylistic variants (Primary - + @@ -691,13 +685,13 @@ The badge can also have a subtle border around it when the - + - + The border color of the outlined badge can also be customized using the `--border-color` CSS variable. @@ -794,18 +788,16 @@ Use the {ProductName} theme system to style the Badge consistently with the rest ### CSS Variables -```css -igc-badge::part(base) { - --background-color: var(--ig-error-A100); - --border-radius: 2px; -} -``` - | variable | what it changes | | --- | --- | | `--background-color` | The badge background color. | +| `--border-color` | The badge border color. | | `--border-radius` | The badge corner radius. | -| `--border-color` | The outlined badge border color. | +| `--elevation` | The badge shadow. | +| `--icon-color` | The badge icon color. | +| `--text-color` | The badge text color. | +| `--size` | The badge size. | +| `--dot-size` | The size of the dot-type badge. | ### Style Parts @@ -813,6 +805,13 @@ igc-badge::part(base) { | --- | --- | | `base` | The Badge root element. | +```css +igc-badge::part(base) { + --background-color: var(--ig-error-A100); + --border-radius: 2px; +} +``` + @@ -933,7 +932,7 @@ Your responsibilities: ## Troubleshooting -The {Platform} Badge troubleshooting guidance follows a problem → cause → fix format for common styling and content issues. +Use this section to check boundaries and common decisions before treating Badge as an interactive control or the only indication of status. ### Why does my custom background color not change the Badge? @@ -975,18 +974,20 @@ The {Platform} Badge is commonly used with related components such as Avatar whe ## FAQ -These frequently asked questions cover common {Platform} Badge content, indicator, and package choices. - - Yes. Use the platform-specific value and icon APIs shown in **Usage**. When projecting content directly, keep the icon and text in the component's default content area. + Yes. Use the Badge's content area for the text and the supported icon content for the visual indicator. Keep the combination short so it remains a compact status or category label. Set the platform-specific `dot` property or attribute. A dot Badge intentionally renders without text or other content. + + Use a dot Badge when the status is communicated by presence alone. Use a text Badge when users need the status, category, or count to be understandable without relying on color or position. + + Use `igniteui-angular` for Angular, `igniteui-react` for React, `igniteui-webcomponents` for Web Components, and `IgniteUI.Blazor` for Blazor. Keep related Ignite UI packages on the same release version. diff --git a/docs/xplat/src/content/en/components/inputs/button-group.mdx b/docs/xplat/src/content/en/components/inputs/button-group.mdx index ececfaa36c..77f9764554 100644 --- a/docs/xplat/src/content/en/components/inputs/button-group.mdx +++ b/docs/xplat/src/content/en/components/inputs/button-group.mdx @@ -27,19 +27,25 @@ import buttonGroupDoNot3 from '@xplat-images/button-group/button-group-do-not-3. # Button Group Component + +The {Platform} Button Group component is used to organize buttons with the directive into styled button groups with horizontal/vertical alignment, single/multiple selection and toggling. + + + The {Platform} Button Group component is used to organize 's into styled button groups with horizontal/vertical alignment, single/multiple selection and toggling. + ## Live Demo - + - + @@ -92,18 +98,18 @@ To use the {Platform} Button Group, follow the [{ProductName} Getting Started](. -### Prerequisites and Version Compatibility - -Use a supported version of the {ProductName} package for your target framework. Keep the framework package, the Button Group package, and the theme package on the same release version. + - - -For Web Components using the **{PackageWebComponents}** package, install the package: +For {Platform} using the **{PackageCommon}** package, install the package: ```cmd -npm install {PackageWebComponents} +npm install {PackageCommon} ``` + + + + Then import the , its theme CSS, and register the component: ```ts @@ -117,12 +123,6 @@ defineComponents(IgcButtonGroupComponent); -For React using the **igniteui-react** package, install the package: - -```cmd -npm install igniteui-react -``` - Then import the Button Group wrapper and its theme CSS: ```tsx @@ -134,7 +134,7 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; -For Blazor using the **IgniteUI.Blazor** package, register the Button Group module as follows: +For {Platform} using the **IgniteUI.Blazor** package, register the Button Group module as follows: ```csharp // in Program.cs file @@ -158,18 +158,22 @@ For Angular using the **igniteui-angular** package, install the package: ng add igniteui-angular ``` -Then import `IgxButtonGroupModule` in an NgModule application, or import `IGX_BUTTON_GROUP_DIRECTIVES` and the required standalone components in the component `imports` collection. +Then import `IGX_BUTTON_GROUP_DIRECTIVES` and the required standalone components in the component `imports` collection. ```ts import { IGX_BUTTON_GROUP_DIRECTIVES } from 'igniteui-angular/button-group'; import { IgxIconComponent } from 'igniteui-angular/icon'; ``` -For a complete introduction to Ignite UI for Angular, read the [**Getting Started**](/general/getting-started) topic. + + +The simplest way to start using the is as follows: + The simplest way to start using the is as follows: + @@ -205,7 +209,13 @@ The simplest way to start using the is ## Usage + +Use the to wrap buttons using the directive. Set the `selected` input on a button to select it by default: + + + Use the to wrap your components. To select a button by default, use the attribute: + @@ -305,7 +315,13 @@ Use the to wrap your +The Button Group supports horizontal and vertical layouts. Use the property to set the orientation of the buttons in the group. + + + The Button Group supports horizontal and vertical layouts. Use the property to set the orientation of the buttons in the group. + @@ -326,18 +342,31 @@ public alignment = ButtonGroupAlignment.vertical; ``` - + - + ### Selection -In order to configure the {ProductName} selection, use its platform-specific selection property. For Angular, use . For React, Web Components, and Blazor, use . The available modes are: +In order to configure the {ProductName} Button Group selection, use its platform-specific selection property. + + +For {Platform}, use the property. The available modes are: + + + +For {Platform}, use the property. The available modes are: + + + +For {Platform}, use the property. The available modes are: + + - **single** - default selection mode of the button group. A single button can be selected/deselected by the user. - **single-required** - mimics a radio group behavior. Only one button can be selected and once initial selection is made, deselection is not possible through user interaction. - **multiple** - multiple buttons in the group can be selected and deselected. @@ -358,17 +387,23 @@ Set the Angular `selectionMode` input to configure the selection behavior: ``` - + - + + +An can be marked as selected via its `selected` input or through the input of the Button Group. + + + A could be marked as selected via its attribute or through the attribute: + @@ -437,38 +472,55 @@ A could be marked as selected via its -Setting attribute is mandatory for using the property of the . + +Set a unique `value` for each button when initializing the Button Group with its input. + + +Setting the attribute is mandatory for using the property of the . + ### States + +Each button in the group supports enabled and disabled variants, which can also be selected or not selected. Use the state behavior provided by the contained components. + + + Each button in the group supports enabled and disabled variants, which can also be selected or not selected. Use the state behavior provided by the contained components. + - + - + ### Interaction States + +The enabled buttons in the group support idle, hover, and focused interaction states. Use the state behavior provided by the contained components. + + + The enabled buttons in the group support idle, hover, and focused interaction states. Use the state behavior provided by the contained components. + - + - + @@ -478,13 +530,13 @@ Each button can use text, an icon, or both. Keep the content style consistent ac - + - + @@ -520,13 +572,13 @@ public bordersButtons: IButton[] = [ See the Angular Button Group sample for the complete `values` model and configuration. - + -For Web Components, use individual Toggle Buttons to create a custom Button Group. Each button can define its own value, icon, label, selected state, and disabled state. +For {Platform}, use individual Toggle Buttons to create a custom Button Group. Each button can define its own value, icon, label, selected state, and disabled state. Register the Button Group and Toggle Button components: @@ -552,13 +604,13 @@ Then define the custom buttons in markup: ``` - + -For React, use individual Toggle Buttons to create a custom Button Group. Each button can define its own value, icon, label, selected state, and disabled state. +For {Platform}, use individual Toggle Buttons to create a custom Button Group. Each button can define its own value, icon, label, selected state, and disabled state. Import the Button Group, Toggle Button, and Icon components: @@ -582,13 +634,13 @@ Then define the custom buttons in JSX: ``` - + -For Blazor, use individual Toggle Buttons to create a custom Button Group. Each button can define its own value, icon, label, selected state, and disabled state. +For {Platform}, use individual Toggle Buttons to create a custom Button Group. Each button can define its own value, icon, label, selected state, and disabled state. Register the Button Group module in `Program.cs`: @@ -612,7 +664,7 @@ Then define the custom buttons in Razor markup: ``` - + @@ -631,7 +683,7 @@ igx-buttongroup { ``` - + @@ -662,7 +714,7 @@ igx-buttongroup { - + @@ -699,15 +751,40 @@ igx-buttongroup { ## Properties -The Button Group properties are generated from the component API reference. + + +The Angular Button Group exposes the following properties. + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| | `ButtonGroupAlignment` | `horizontal` | Sets the orientation of the buttons in the group. | +| | `IButton[]` | `[]` | Defines the button items displayed in the group. | + + + + -The property rows are injected from the typed API source during the documentation build. +The {Platform} Button Group exposes the following properties. | Name | Type | Default | Description | | --- | --- | --- | --- | -| | `ButtonGroupAlignment` | `horizontal` | Sets the orientation of the buttons in the group. | -| | `ButtonGroupSelection` | `single` | Sets the selection mode for the buttons in the group. | -| | `string[]` | `[]` | Gets or sets the values of the selected buttons. Each Toggle Button must have a unique `value`. | +| | `ButtonGroupAlignment` | `horizontal` | Sets the orientation of the buttons in the group. | +| | `ButtonGroupSelection` | `single` | Sets the selection mode for the buttons in the group. | +| | `string[]` | `[]` | Gets or sets the values of the selected buttons. | + + + + + +The Blazor Button Group exposes the following properties. + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| | `ButtonGroupAlignment` | `horizontal` | Sets the orientation of the buttons in the group. | +| | `ButtonGroupSelection` | `single` | Sets the selection mode for the buttons in the group. | +| | `string[]` | `[]` | Gets or sets the values of the selected buttons. | + + ## Styling @@ -1002,7 +1079,7 @@ Your responsibilities: ## Troubleshooting -The {Platform} Button Group troubleshooting guidance follows a problem, cause, and fix format for common selection issues. +Use this section to check boundaries and common decisions before treating Button Group as a single toggle, form field, or action group. ### Why does selectedItems not select a button? @@ -1018,16 +1095,53 @@ The {Platform} Button Group coordinates Toggle Buttons but does not replace thei ## API References -The {Platform} Button Group API reference provides the complete API surface for the component and its related Toggle Button functionality. +The {Platform} Button Group API reference provides the complete API surface for the component and its related button functionality. + + + + + + + + + + + + + + + - + + + + + + + + + ## Dependencies -The {Platform} Button Group requires the platform package and its theme stylesheet. The examples also use Toggle Button, Icon, and Ripple components. + +The Angular Button Group requires the Angular package and its theme stylesheet. The examples also use the , , and components. + + + +The React Button Group requires the React package and its theme stylesheet. The examples also use the , , and components. + + + +The Web Components Button Group requires the Web Components package and its theme stylesheet. The examples also use the , , and components. + + + +The Blazor Button Group requires the Blazor package and its theme stylesheet. The examples also use the , , and components. + ## Additional Resources @@ -1038,26 +1152,22 @@ Use the following {Platform} resources for API details and project support: ## Related Components -The {Platform} Button Group is built from selectable Toggle Buttons. Use the following related component when you need an individual toggle action instead of a group: - -- +- [Button](./button.mdx) - Use Button when you need an individual action instead of a selectable group. ## FAQ -These frequently asked questions cover common {Platform} Button Group selection, content, and setup scenarios. - - -The Button Group supports `single`, `single-required`, and `multiple` selection modes. Use the `selection` property to choose the mode that matches the interaction you need. + +Give every button item a unique value, then use the platform-specific selected-items setting to identify the items that should start selected. Unique values allow the group to track selection consistently across all supported platforms. - -Assign a unique `value` to every and set the corresponding values through the Button Group's `selectedItems` property. + +Yes. Each button item can contain an icon, a label, or both. Keep the content pattern consistent across the group and provide a visible label or accessible name when an icon alone does not explain the option. - -Yes. Add an icon to each and keep the button content consistent across the group. + +Yes. Set the platform-specific alignment property to the vertical option. Use horizontal alignment when the related choices should be presented in a single row. diff --git a/docs/xplat/src/content/en/components/inputs/button.mdx b/docs/xplat/src/content/en/components/inputs/button.mdx index 838d023665..8b49cd970d 100644 --- a/docs/xplat/src/content/en/components/inputs/button.mdx +++ b/docs/xplat/src/content/en/components/inputs/button.mdx @@ -1,45 +1,179 @@ --- -title: "{Platform} Button Component | {ProductName}" +title: "Button Component" description: Get started with the {Platform} Button Component. Select button variants, configure sizes, define styling, and gain flexibility through the {Platform} Button OnClick event. keywords: "{Platform}, UI controls, web widgets, UI widgets, {Platform} Button Components, Infragistics" mentionedTypes: ["Button", "ButtonBase"] license: MIT +last_updated: 2026-08-13 +relatedComponents: ["IconButton"] llms: description: "The {Platform} Button Component lets you enable clickable elements that trigger actions in your {Platform} app." --- import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; +import Anatomy from 'igniteui-astro-components/components/mdx/Anatomy.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; +import { Image } from 'astro:assets'; +import buttonAnatomy from '@xplat-images/anatomy-content-light/button-lt-a.png'; +import buttonDo1 from '@xplat-images/button/button-do-1.png'; +import buttonDo2 from '@xplat-images/button/button-do-2.png'; +import buttonDo3 from '@xplat-images/button/button-do-3.png'; +import buttonDoNot1 from '@xplat-images/button/button-do-not-1.png'; +import buttonDoNot2 from '@xplat-images/button/button-do-not-2.png'; +import buttonDoNot3 from '@xplat-images/button/button-do-not-3.png'; +# Button Component -# {Platform} Button Overview +The {Platform} Button component lets you enable clickable elements that trigger actions in your {Platform} app. You get full control over button variants, styling, and sizes. The Button component also lets you handle clicks, toggle the button, and disable it when needed. - +## Live Demo -The {Platform} Button Component lets you enable clickable elements that trigger actions in your {Platform} app. You get full control over how you set button variants, configure styles for the wrapped element, and define sizes. The Button Component also gives flexibility through the {Platform} Button OnClick event, toggle the {Platform} button, disable the {Platform} button, and more. + + + - + -The {Platform} Button Component lets you enable clickable elements that trigger actions in your {Platform} app. You get full control over how you set button variants, configure styles for the wrapped element, and define sizes. The Button Component also gives flexibility through the {Platform} Button clicked callback, toggle the {Platform} button, disable the {Platform} button, and more. + -## {Platform} Button Example +## Anatomy - +The {Platform} Button renders its label and optional prefix and suffix content in the component shadow DOM. -## Usage + - + + +
+
+ A - Contained Button + 1. Icon (optional) + 2. Label + 3. Container +
+
+ B - Outlined Button + 4. Icon (optional) + 5. Label + 6. Container +
+
+ C - Flat Button + 7. Icon (optional) + 8. Label +
+
+ D - Fab Icon Button + 9. Icon + 10. Container +
+
+ +The Button renders its content inside the `base` CSS part. Use the default slot for the label and the `prefix` and `suffix` slots for optional content before and after the label. + +```text + +├── ::part(base) +├── prefix slot +├── default slot content +└── suffix slot + +``` + +## Getting Started + +To use the {Platform} Button, follow the [{ProductName} Getting Started](../general/getting-started.mdx)[{ProductName} Getting Started](../general-getting-started.mdx) topic for the basic project setup, then register the component for your target platform. + + + +For Angular using the **igniteui-angular** package, install the package: + +```cmd +npm install igniteui-angular +``` + +Then import `IgxButtonDirective` and add it to the component `imports` collection. + +```ts +import { Component } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; + +@Component({ + selector: 'app-button', + imports: [IgxButtonDirective], + template: '' +}) +export class ButtonComponent {} +``` + + + + + +For {Platform} using the **{PackageCommon}** package, install the package: ```cmd -npm install {PackageWebComponents} +npm install {PackageCommon} ``` + + + + You will then need to import the , its necessary CSS, and register its module, like so: ```ts @@ -49,18 +183,10 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; defineComponents(IgcButtonComponent); ``` -For a complete introduction to the {ProductName}, read the [**Getting Started**](../general-getting-started.mdx) topic. - -First, you need to the install the corresponding {ProductName} npm package by running the following command: - -```cmd -npm install igniteui-react -``` - You will then need to import the and its necessary CSS, like so: ```tsx @@ -72,7 +198,7 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; -Before using the , you need to register it as follows: +For Blazor using the **IgniteUI.Blazor** package, register the Button module as follows: ```csharp // in Program.cs file @@ -90,10 +216,18 @@ You will also need to link an additional CSS file to apply the styling to the
is as follows: + + +```html + +``` + + + ```html -Click me + ``` @@ -114,11 +248,59 @@ The simplest way to start using the is as f -## Prefix / Suffix +## Usage + +Use the {Platform} Button to trigger an action, submit form data, or navigate to another page. Choose the appropriate button type and variant for the action, then add optional content such as icons when needed. + +The Button content is placed in its default slot. Add the action label as the button content so that the purpose of the action is clear to all users. + + + +```html + +``` + + + + + +```tsx +Save changes +``` + + + + + +```html +Save changes +``` + + + + + +```razor +Save changes +``` + + With `prefix` and `suffix` slots of the component, we can add different content before and after the main content of the button. -We recommend using a `` element when adding simple text, symbols, or emojis, and an [``](../layouts/icon.mdx) component when adding icons to the `prefix` and `suffix` slots. +We recommend using a `` element when adding simple text, symbols, or emojis, and an component when adding icons to the `prefix` and `suffix` slots. + + + +```html + +``` + + @@ -153,7 +335,7 @@ We recommend using a `` element when adding simple text, symbols, or emoji -## Type +### Type The button component will change its internal structure from a [` +``` + + + + + + + +```tsx +Disabled ``` @@ -304,71 +532,87 @@ defineComponents(IgcButtonComponent, IgcRadioComponent, IgcRadioGroupComponent); ```html - - Small - Medium - Large - +Disabled ``` - + -```ts -this.radioGroup = document.getElementById('radio-group') as IgcRadioGroupComponent; -this.outlinedButton = document.getElementById('outlined-btn') as IgcButtonComponent; -this.flatButton = document.getElementById('flat-btn') as IgcButtonComponent; -this.containedButton = document.getElementById('contained-btn') as IgcButtonComponent; -this.fabButton = document.getElementById('fab-btn') as IgcButtonComponent; +```razor +Disabled +``` + + + + + + + + + +### Interaction States + +In Figma the Enabled buttons support **Idle**, **Hover**, **Focused** and **Focused & Hover** states which can be switched between by changing the `State` property. In code, these interaction states are provided by the platform Button component and should preserve a visible focus indicator for keyboard users. -this.radioGroup.addEventListener('click', (radio: any) => { - this.outlinedButton.style.setProperty('--ig-size', `var(--ig-size-${radio.target.value})`); - this.flatButton.style.setProperty('--ig-size', `var(--ig-size-${radio.target.value})`); - this.containedButton.style.setProperty('--ig-size', `var(--ig-size-${radio.target.value})`); - this.fabButton.style.setProperty('--ig-size', `var(--ig-size-${radio.target.value})`); -}); + + +```html + ``` + + + + + + +```html +Ripple and focus states +``` + + + + + +### Layout Template + +Contained, Outlined, Flat, and Floating Action Buttons support flexible icon and label templates. In Figma, to show or hide the icons, you can use the `Left Icon` and `Right Icon` boolean properties. If you want to have an Icon Button, you can set the `Content` property to `Icon`. + + + +```html + + Span button + +``` + + + ```tsx -import { IgrButton, IgrRadio, IgrRadioGroup } from 'igniteui-react'; - -const [size, setSize] = useState("small"); - -const onRadioChange = (e: IgrRadioChangeEventArgs) => { - setSize(e.detail.value); -}; - - - - Small - - - Medium - - - Large - - - -
- - Flat - - - Contained - - - Outlined - - - Fab - -
+ + ★ + Save changes + → + +``` + +
+ + + +```html + + ★ + Save changes + → + ``` @@ -376,45 +620,100 @@ const onRadioChange = (e: IgrRadioChangeEventArgs) => { ```razor - - Small - Medium - Large - + + ★ + Save changes + → + +``` -@code { - private SizableComponentSize SizableComponentSize = SizableComponentSize.Large; + - protected override void OnInitialized() - { - } + - public void OnSmallClick(EventArgs e) - { - SizableComponentSize = SizableComponentSize.Small; - } + - public void OnMediumClick(EventArgs e) - { - SizableComponentSize = SizableComponentSize.Medium; - } + - public void OnLargeClick(EventArgs e) - { - SizableComponentSize = SizableComponentSize.Large; - } -} +### Size + +Users can change the size of the using the `--ig-size` CSS variable. + + + +```html + + Small + +``` + + + + + +```tsx + + Small + ``` + + +```razor + + Small + +``` + + + +```css +.button-size-small { + --ig-size: var(--ig-size-small); +} +``` + The result of implementing the above code should look like the following: - + + + + + + + + + + + + ### Download -Setting the property will prompt the user to save the linked URL instead of navigating to it. + +Setting the Button attribute will prompt the user to save the linked URL instead of navigating to it. + + + +Setting the attribute will prompt the user to save the linked URL instead of navigating to it. +Setting the property will prompt the user to save the linked URL instead of navigating to it. + + + + +```html + +``` + + @@ -454,11 +753,126 @@ Setting the - + + + + + + + + + + + + +### Do/Don't + +**When to use:** Use Button for actions that change state, submit data, or trigger an application command. + +**When not to use:** Use [Icon Button](./icon-button.mdx) when the action is represented only by an icon and does not require a text label. + +
+ + + + + + + + + + + + + + + + + + + + + +
DoDon't
Button do example 1Button don't example 1
Button do example 2Button don't example 2
Button do example 3Button don't example 3
+
+ + +## Properties + +The {Platform} Button exposes platform-specific properties for controlling its content, appearance, and behavior. + + + +The Angular Button is provided as a directive and exposes the following properties. Use the API reference for the complete type definitions. + +| name | type | default | description | +| --- | --- | --- | --- | +| | string | `flat` | Sets the Button visual variant. | +| | string | `button` | Sets the native button type. | + + + + + +The {Platform} Button exposes the following properties. + +| Name | Type | Default | Description | +|--|--|--|--| +| | ButtonVariant | `contained` | Selects the Button visual variant. | +| | string | `button` | Sets the native button type when the component renders as a button. | +| | string | — | Sets the destination and uses the Button for navigation. | +| | string | — | Sets the relationship between the current document and the linked destination. | +| | string | — | Sets where the linked destination opens when `href` is set. | +| | string | — | Prompts the user to download the linked resource when `href` is set. | + + + + +The {Platform} Button exposes the following properties. + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| | ButtonVariant | `contained` | Selects the Button visual variant. | +| | string | `button` | Sets the native button type. | +| | string | — | Sets the destination for navigation. | + + + + + +The Blazor Button exposes the following properties. + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| | ButtonVariant | `contained` | Selects the Button visual variant. | +| | string | `button` | Sets the native button type. | +| | string | — | Sets the destination for navigation. | + + ## Styling +Customize the Button with theme settings, CSS variables, or CSS parts to match the visual language of your application. + +### Sass Theming + +Use the standard {ProductName} theme workflow to customize the Button consistently with the rest of the application. + +### CSS Variables + +Use the generated CSS variables on the Button element to override the theme values for a specific instance. The variant-specific theme functions derive related interaction-state values from the primary theme parameters. + +| Primary property | Dependent property | Description | +| --- | --- | --- | +| `$background` | `$hover-background`, `$focus-background`, `$active-background` | Button background colors for the interaction states. | +| `$foreground` | `$hover-foreground`, `$focus-foreground`, `$active-foreground` | Button text colors for the interaction states. | +| `$border-color` | `$hover-border-color`, `$focus-border-color`, `$active-border-color` | Button border colors for the interaction states. | +| `$shadow-color` | `$resting-shadow`, `$hover-shadow`, `$focus-shadow`, `$active-shadow` | Button shadow colors and elevations. | +| `$disabled-background` | `$disabled-foreground`, `$disabled-icon-color`, `$disabled-border-color` | Button colors when it is disabled. | + +### Style Parts + The exposes three CSS parts which we can use for styling: |Name|Description| @@ -477,13 +891,206 @@ igc-button::part(base) { } ``` - + + + + + + + + + + + + +### Styling with Tailwind + + + +You can style the Button using custom Tailwind utility classes. Make sure to [set up Tailwind](/themes/tailwind) first. + +Along with the Tailwind import in your global stylesheet, include the utility file: + +```scss +@import "tailwindcss"; +@use 'igniteui-theming/tailwind/utilities/material.css'; +``` + +Use the variant-specific classes such as `light-flat-button`, `light-contained-button`, `light-outlined-button`, and `light-fab-button`: + +```html + +``` + +The exclamation mark (`!`) ensures that the utility class takes precedence over the Button's default theme. + + + + + + + +You can style the Button with the custom Tailwind utility classes from `igniteui-theming`. Make sure to [set up Tailwind](/themes/tailwind) first, then import the Ignite UI utilities in your global stylesheet: + +```css +@import "tailwindcss"; +@import "igniteui-theming/tailwind/utilities/material.css"; +``` + + + +```jsx +Contained Button +``` + + + + + +```html +Contained Button +``` + + + + + +```razor +Contained Button +``` + + + +The exclamation mark (`!`) gives the Tailwind utility precedence over the Button's default theme styles. + + + + + +## Accessibility + +The {Platform} Button is an interactive control for actions and, when `href` is set, navigation. +Use the native button behavior for commands and preserve the link behavior for navigation. + +### Keyboard Interaction + +The Button uses the keyboard behavior of its rendered native control. A disabled Button is not +interactive, and a Button with `href` is rendered as a link instead of a command button. + +| Key | Action | +| -- | -- | +| Tab / Shift+Tab | Moves focus to or away from the Button when it is keyboard-focusable. | +| Enter / Space | Activates a focused command Button. Enter activates a Button used as a link. | + +### Screen Readers / ARIA + +The Button renders a native `button` for command actions and an `a` element when `href` is set. +The native element supplies the appropriate role and keyboard semantics. + + + +- The Button's visible content is used as its accessible name when it contains meaningful text. +- Provide an `aria-label` or another accessible naming mechanism for an icon-only Button. +- A disabled Button exposes its disabled state through the rendered native control. +- Button click event handlers perform application actions; they do not replace the Button's + accessible name, role, or state. + + + + + +- The Button uses the native `button` or `a` element, so assistive technology receives the + corresponding native role and keyboard semantics. +- Provide an `aria-label` or another accessible naming mechanism for an icon-only Button. +- A disabled Button is not keyboard interactive. +- Click event handlers perform application actions; add an accessible name and state separately + when the action is not conveyed by the visible content or native attributes. + + + +### Accessibility Compliance + +This topic does not make a product-level WCAG, Section 508, or EN 301 549 conformance claim. Verify the rendered Button and its surrounding application against the accessibility requirements that apply to the target project. + +| Criterion | How the component supports the requirement | +| -- | -- | +| [2.1.1 Keyboard](https://www.w3.org/WAI/WCAG21/Understanding/keyboard) | The native command button supports keyboard activation, and a Button with `href` uses native link activation. | +| [4.1.2 Name, Role, Value](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value) | The rendered native element supplies the role and state semantics. The visible Button content supplies the accessible name when it is meaningful. | +| [2.4.4 Link Purpose](https://www.w3.org/WAI/WCAG21/Understanding/link-purpose-in-context) | When `href` is set, the Button becomes a navigation link; provide a name that identifies its destination or purpose. | + +Your responsibilities: + +- Give every Button a meaningful accessible name, especially icon-only Buttons. +- Use a command Button for actions and `href` for navigation; do not emulate one with the other. +- Do not rely on color, hover, or focus styling alone to communicate the action or state. +- Preserve sufficient contrast and a visible focus indicator when customizing the Button theme. + +## Troubleshooting + +Use this section to check boundaries and common decisions before treating Button as a command, navigation link, or form control. + +### Why does the Button behave like a link? + +When `href` is set, the Button is used for navigation rather than for a command action. Remove `href` when the control should trigger application logic instead of navigating to a URL. + +### Why is the Button not keyboard-focusable? + +Check whether the Button is disabled or whether the surrounding application changes its focus behavior. Use a focusable Button for actions that must be available through keyboard navigation. + +### Known Limitations + +The Button has the following platform-independent boundaries: + +- Use a text label or another accessible naming mechanism for every action; an unlabeled icon-only Button does not communicate its purpose by itself. +- Setting `href` changes the Button from an action control to a navigation control. Use [Icon Button](./icon-button.mdx) for icon-only actions and verify its accessible name separately. +- The Button's visual appearance does not determine whether the surrounding application action is available or valid; application logic must provide that state and feedback. ## API References + +The {Platform} Button API reference lists the complete verified API surface for the target platform. + + + + + - - + + +## Dependencies + + +The {Platform} Button requires the corresponding {Platform} package and theme stylesheet. The sizing example also uses the and components. + + + +The {Platform} Button requires the corresponding {Platform} package and theme stylesheet. The sizing example also uses the and components. + + ## Additional Resources +The following resources provide additional {Platform} Button guidance and project support. + - [{ProductName} **Forums**]({ForumsLink}) - [{ProductName} **GitHub**]({GithubLink}) + +## Related Components + +The {Platform} Button is commonly used with related components when an action needs a specialized presentation. + +- [Icon Button](./icon-button.mdx) is intended for icon-only actions. + +## FAQ + + + + Use the [Icon Button](./icon-button.mdx) component and provide an accessible name for the action. + + + Set the verified `disabled` property to make the Button unavailable and prevent it from being activated. + + + Use the platform's supported sizing options or the `--ig-size` CSS variable to customize the Button density. + + diff --git a/docs/xplat/src/content/en/components/inputs/qr-code.mdx b/docs/xplat/src/content/en/components/inputs/qr-code.mdx new file mode 100644 index 0000000000..e689e64709 --- /dev/null +++ b/docs/xplat/src/content/en/components/inputs/qr-code.mdx @@ -0,0 +1,796 @@ +--- +title: "{Platform} QR Code" +description: "The {ProductName} QR Code renders a scannable QR (Quick Response) code as an inline SVG, generated on the client from any string value, with customizable size, error correction, and a center logo." +keywords: "{Platform} QR Code, {ProductName}, QR code, scannable code, SVG QR code, QR generator, logo, error correction" +license: MIT +mentionedTypes: ["QrCode"] +last_updated: "2026-09-23" +llms: + description: "The {ProductName} QR Code renders a scannable QR (Quick Response) code as an inline SVG, generated on the client from any string value, with customizable size, error correction, and a center logo." +--- +import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; +import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; +import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; +import Anatomy from 'igniteui-astro-components/components/mdx/Anatomy.astro'; +import Badge from 'igniteui-astro-components/components/mdx/Badge.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; +import { Image } from 'astro:assets'; +import qrCodeAnatomy from '@xplat-images/anatomy-content-light/qr-code-lt-a.png'; +import qrCodeDo1 from '@xplat-images/qr-code/qr-code-do1.png'; +import qrCodeDo1_2x from '@xplat-images/qr-code/qr-code-do1@2x.png'; +import qrCodeDoNot1 from '@xplat-images/qr-code/qr-code-do-not1.png'; +import qrCodeDoNot1_2x from '@xplat-images/qr-code/qr-code-do-not1@2x.png'; +import qrCodeDo2 from '@xplat-images/qr-code/qr-code-do2.png'; +import qrCodeDo2_2x from '@xplat-images/qr-code/qr-code-do2@2x.png'; +import qrCodeDoNot2 from '@xplat-images/qr-code/qr-code-do-not2.png'; +import qrCodeDoNot2_2x from '@xplat-images/qr-code/qr-code-do-not2@2x.png'; + +{/* +React and Blazor are excluded in toc.json until their QR Code wrappers ship. Their blocks below are staged; verify them against the released wrapper APIs before removing the exclusion. +*/} + +# QR Code Component + +The {ProductName} QR Code renders a scannable QR (Quick Response) code as an inline SVG, generated on the client from any string value, with customizable size, error correction, and center logo. + +## Live Demo + +The {Platform} QR Code demo renders a code from a URL string and lets you switch its module shape, size, and center logo. + + + + + + + + + + + + + +## Anatomy + +The {Platform} QR Code is a square SVG graphic made of three finder-pattern corners, the encoded data modules, a quiet-zone margin, and an optional center logo. + + + + + + +1. QR Code container: the host element that renders the SVG.
+2. QR Matrix: the encoded matrix that stores the destination or data payload.
+3. Quiet Zone: the empty space around the code that ensures scanners can read it reliably.
+4. Center Logo (optional): an optional central container used to display a brand logo or custom icon.
+5. Finder-pattern corners: square markers at the corners that help scanners detect and orient the code correctly.
+ +```text + +└── svg[role="img"] + ├── // "QR code: <value>" or the aria-label value + ├── ::part(background) // background rect + ├── <mask> // rendered when logo-src is set + ├── <g> // masked when logo-src is set + │ ├── ::part(dots) // data modules path + │ ├── ::part(corner-square) // outer finder-pattern squares (×3) + │ └── ::part(corner-dot) // inner finder-pattern dots (×3) + └── <image> // center logo, rendered when logo-src is set +``` + +## Getting Started + +To use the {Platform} QR Code, complete the <PlatformBlock for="Angular">[{ProductName} Getting Started]({environment:infragisticsBaseUrl}/products/ignite-ui-angular/angular/components/general/getting-started)</PlatformBlock><PlatformBlock for="WebComponents, React, Blazor">[{ProductName} Getting Started](../general-getting-started.mdx)</PlatformBlock> topic for the basic project setup, then register the component. + +### Prerequisites and Version Compatibility + +<PlatformBlock for="WebComponents, Angular"> + +The QR Code requires `igniteui-webcomponents` 7.3.0 or later. The `toBlob()` and `toImage()` export methods require 7.3.2 or later. + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +{ProductName} renders the QR Code as a web component, so install `igniteui-webcomponents` in your Angular project: + +```cmd +npm install igniteui-webcomponents +``` + +</PlatformBlock> + +{/* +TODO: add the React and Blazor wrapper versions when they are released. +*/} + +<PlatformBlock for="WebComponents, Angular"> + +Import [`IgcQrCodeComponent`]({environment:infragisticsBaseUrl}/api/webcomponents/igniteui-webcomponents/latest/classes/IgcQrCodeComponent) and a theme, then register the component: + +```ts +import { defineComponents, IgcQrCodeComponent } from 'igniteui-webcomponents'; +import 'igniteui-webcomponents/themes/light/bootstrap.css'; + +defineComponents(IgcQrCodeComponent); +``` + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +Add `CUSTOM_ELEMENTS_SCHEMA` to the Angular component that renders `igc-qr-code`: + +```ts +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; + +@Component({ + schemas: [CUSTOM_ELEMENTS_SCHEMA], +}) +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +Import the <ApiLink pkg="core" type="QrCode" /> wrapper and a theme: + +```tsx +import { IgrQrCode } from 'igniteui-react'; +import 'igniteui-webcomponents/themes/light/bootstrap.css'; +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +Register the <ApiLink pkg="core" type="QrCode" /> module in **Program.cs**: + +```csharp +builder.Services.AddIgniteUIBlazor(typeof(IgbQrCodeModule)); +``` + +Link the theme stylesheet in **wwwroot/index.html** (Blazor WebAssembly) or **Pages/_Host.cshtml** (Blazor Server): + +```razor +<link href="_content/IgniteUI.Blazor/themes/light/bootstrap.css" rel="stylesheet" /> +``` + +</PlatformBlock> + +Render the QR Code with a value: + +<PlatformBlock for="WebComponents, Angular"> + +```html +<igc-qr-code value="https://www.infragistics.com"></igc-qr-code> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrQrCode value="https://www.infragistics.com"></IgrQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbQrCode Value="https://www.infragistics.com"></IgbQrCode> +``` + +</PlatformBlock> + +By default, this renders a 128×128 pixel QR code with a 4-module quiet-zone margin, `M` error correction, and square modules and corners. + +## Usage + +Set `value` to any string to render a scannable QR code. The component picks the most compact encoding mode (numeric, alphanumeric, or byte) and the smallest QR version that fits the value. Clearing `value` removes the SVG. + +### Error Correction + +Use `errorLevel` to choose the `L`, `M` (default), `Q`, or `H` error correction level. Higher levels recover more of a damaged or covered code but produce a denser code. Use `version` to pin a QR version from `1` to `40` when you need predictable module dimensions; leave it unset to use the smallest version that fits `value`. + +<PlatformBlock for="WebComponents, Angular"> + +```html +<igc-qr-code + value="https://www.infragistics.com" + version="4" + error-level="H"> +</igc-qr-code> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrQrCode + value="https://www.infragistics.com" + version={4} + errorLevel="H"> +</IgrQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbQrCode + Value="https://www.infragistics.com" + Version="4" + ErrorLevel="QrCodeErrorLevel.H"> +</IgbQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +<Sample src="/data-display/qr-code-error-correction" height={320} position="center" noBackground={false} noBorder={false} spacing="md" alt="Angular QR Code error correction example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/qr-code/error-correction" height={320} position="center" noBackground={false} noBorder={false} spacing="md" alt="{Platform} QR Code error correction example" /> + +</PlatformBlock> + +### Size + +Use `size` to set the rendered width and height in pixels, and `margin` to set the quiet zone in QR modules. The quiet zone is drawn inside `size`, so a larger `margin` makes the modules smaller. + +<PlatformBlock for="WebComponents, Angular"> + +```html +<igc-qr-code + value="https://www.infragistics.com" + size="256" + margin="2"> +</igc-qr-code> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrQrCode + value="https://www.infragistics.com" + size={256} + margin={2}> +</IgrQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbQrCode + Value="https://www.infragistics.com" + Size="256" + Margin="2"> +</IgbQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +<Sample src="/data-display/qr-code-size" height={515} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular QR Code size example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/qr-code/size" height={515} position="center" noBorder={false} spacing="md" noBackground={false} alt="{Platform} QR Code size example" /> + +</PlatformBlock> + +### Center Logo + +Set `logoSrc` to render an image at the center of the code; the component masks the modules beneath it. `logoSize` sets the logo size as a ratio from `0` to `1` of the largest safe logo area, which is 9% of the code at the `H` level. `logoMargin` adds whitespace around the logo in pixels. + +The logo never covers more than the current `errorLevel` allows. At the default `M` level, `logoSize` values above about `0.44` render at the same capped size, so set `errorLevel` to `H` for the largest logo. + +`logoSrc` accepts regular URLs and `data:image/*` URIs. Sources with unsafe schemes (such as `javascript:` or `vbscript:`) and non-image `data:` URIs are rejected, and no logo is rendered. + +<PlatformBlock for="WebComponents, Angular"> + +```html +<igc-qr-code + value="https://www.infragistics.com" + error-level="H" + logo-src="/assets/logo.png" + logo-size="0.5" + logo-margin="4"> +</igc-qr-code> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrQrCode + value="https://www.infragistics.com" + errorLevel="H" + logoSrc="/assets/logo.png" + logoSize={0.5} + logoMargin={4}> +</IgrQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbQrCode + Value="https://www.infragistics.com" + ErrorLevel="QrCodeErrorLevel.H" + LogoSrc="/assets/logo.png" + LogoSize="0.5" + LogoMargin="4"> +</IgbQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +<Sample src="/data-display/qr-code-logo" height={245} position="center" noBackground={false} noBorder={false} spacing="md" alt="Angular QR Code logo example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/qr-code/logo" height={245} position="center" noBackground={false} noBorder={false} spacing="md" alt="{Platform} QR Code logo example" /> + +</PlatformBlock> + +### Shapes + +Use `dotStyle` to shape the data modules and the inner finder-pattern dots, and `squareStyle` to shape the outer finder-pattern squares. Both accept `square` (default), `circle`, or `rounded`. + +<PlatformBlock for="WebComponents, Angular"> + +```html +<igc-qr-code + value="https://www.infragistics.com" + dot-style="rounded" + square-style="rounded"> +</igc-qr-code> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrQrCode + value="https://www.infragistics.com" + dotStyle="rounded" + squareStyle="rounded"> +</IgrQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbQrCode + Value="https://www.infragistics.com" + DotStyle="QrCodeDotStyle.Rounded" + SquareStyle="QrCodeSquareStyle.Rounded"> +</IgbQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +<Sample src="/data-display/qr-code-dot-shapes" height={320} position="center" noBackground={false} noBorder={false} spacing="md" alt="Angular QR Code dot shapes example" /> + +<Sample src="/data-display/qr-code-corner-shapes" height={320} position="center" noBackground={false} noBorder={false} spacing="md" alt="Angular QR Code corner shapes example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/qr-code/dot-shapes" height={320} position="center" noBackground={false} noBorder={false} spacing="md" alt="{Platform} QR Code dot shapes example" /> + +<Sample src="/inputs/qr-code/corner-shapes" height={320} position="center" noBackground={false} noBorder={false} spacing="md" alt="{Platform} QR Code corner shapes example" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents, Angular"> + +### Export + +Call `toImage()` to export the QR code as a PNG, JPEG, WebP, or SVG file, or `toBlob()` to get it as an SVG `Blob`. Both methods resolve theme colors and inline the logo, so the export matches the rendered code. + +```ts +const qrCode = document.querySelector('igc-qr-code') as IgcQrCodeComponent; + +// Downloads a 512×512 PNG from a 256px QR code. +await qrCode.toImage({ format: 'png', scale: 2, fileName: 'my-qr-code', download: true }); +``` + +</PlatformBlock> + +### Do/Don't + +**When to use:** QR codes give users a fast bridge from print or static screens to a digital action, such as opening a page, downloading an app, or verifying a link. + +**When not to use:** Avoid QR codes for information that must be readable without a scanner, or when a direct button, link, or short URL serves the destination better. + +<table class="table" style="width: 100%; max-width: 1100px; margin: 0 auto 26px;"> + <tbody> + <tr> + <td style="width: 50%; border: none; padding: 0 13px 13px 0;"><Image src={qrCodeDo1} srcset={`${qrCodeDo1.src} 1x, ${qrCodeDo1_2x.src} 2x`} alt="QR Code with a heading, a call to action, and a fallback short URL" style="border: 1px solid #D2DBE8; margin: unset;"/> + </td> + <td style="width: 50%; border: none; padding: 0 0 13px 13px;"><Image src={qrCodeDoNot1} srcset={`${qrCodeDoNot1.src} 1x, ${qrCodeDoNot1_2x.src} 2x`} alt="QR Code as the only way to finish a required step, with no link or button" style="border: 1px solid #D2DBE8; margin: unset;"/> + </td> + </tr> + <tr> + <td style="border: none; padding: 13px 13px 13px 0; color: green;"> + <strong>Do</strong> + </td> + <td style="border: none; padding: 13px 0 13px 13px; color: red;"> + <strong>Don't</strong> + </td> + </tr> + <tr> + <td style="border: none; padding: 13px 13px 13px 0; text-align: left;"> + Use QR codes for short, high-intent actions with a clear destination and enough surrounding whitespace. + </td> + <td style="border: none; padding: 13px 0 13px 13px; text-align: left;"> + Avoid using QR codes for critical content on their own, or in places where users cannot easily scan them. + </td> + </tr> + <tr> + <td style="width: 50%; border: none; padding: 0 13px 13px 0;"><Image src={qrCodeDo2} srcset={`${qrCodeDo2.src} 1x, ${qrCodeDo2_2x.src} 2x`} alt="Black QR Code on a white background" style="border: 1px solid #D2DBE8; margin: unset;"/> + </td> + <td style="width: 50%; border: none; padding: 0 0 13px 13px;"><Image src={qrCodeDoNot2} srcset={`${qrCodeDoNot2.src} 1x, ${qrCodeDoNot2_2x.src} 2x`} alt="Light QR Code on a low-contrast slate background" style="border: 1px solid #D2DBE8; margin: unset;"/> + </td> + </tr> + <tr> + <td style="border: none; padding: 13px 13px 13px 0; color: green;"> + <strong>Do</strong> + </td> + <td style="border: none; padding: 13px 0 13px 13px; color: red;"> + <strong>Don't</strong> + </td> + </tr> + <tr> + <td style="border: none; padding: 13px 13px 13px 0; text-align: left;"> + Keep the foreground dark and the background light (ideally black on white) so phone cameras can scan it fast. + </td> + <td style="border: none; padding: 13px 0 13px 13px; text-align: left;"> + Avoid light-colored QR codes on dark backgrounds or low-contrast brand tints that fail scanner detection. + </td> + </tr> + </tbody> +</table> + +## Properties + +The {Platform} QR Code exposes properties for the encoded value, code density, sizing, logo, and shape customization. + +| Name | Type | Default | Description | +| -- | -- | -- | -- | +| <ApiLink pkg="core" type="QrCode" member="value" label="value" /> | `string` | — | The string encoded in the QR code. | +| <ApiLink pkg="core" type="QrCode" member="version" label="version" /> | `number` | — | The QR version (1–40). When not set, the smallest version that fits `value` is used. | +| <ApiLink pkg="core" type="QrCode" member="errorLevel" label="errorLevel" /> | `'L' \| 'M' \| 'Q' \| 'H'` | `'M'` | The error correction level. Also caps the logo size. | +| <ApiLink pkg="core" type="QrCode" member="size" label="size" /> | `number` | `128` | The rendered width and height in pixels. | +| <ApiLink pkg="core" type="QrCode" member="margin" label="margin" /> | `number` | `4` | The quiet-zone margin, in QR modules. | +| <ApiLink pkg="core" type="QrCode" member="logoSrc" label="logoSrc" /> | `string` | — | The source URL of an optional center logo image. | +| <ApiLink pkg="core" type="QrCode" member="logoSize" label="logoSize" /> | `number` | `0.4` | The logo size as a ratio (0–1) of the largest safe logo area. | +| <ApiLink pkg="core" type="QrCode" member="logoMargin" label="logoMargin" /> | `number` | — | The margin around the logo, in pixels. | +| <ApiLink pkg="core" type="QrCode" member="dotStyle" label="dotStyle" /> | `'square' \| 'circle' \| 'rounded'` | `'square'` | The shape of the data modules and the inner finder-pattern dots. | +| <ApiLink pkg="core" type="QrCode" member="squareStyle" label="squareStyle" /> | `'square' \| 'circle' \| 'rounded'` | `'square'` | The shape of the outer finder-pattern squares. | + +<PlatformBlock for="WebComponents, Angular"> + +## Methods + +| Name | Returns | Description | +| -- | -- | -- | +| `toBlob()` | `Promise<Blob>` | Serializes the QR code to an `image/svg+xml` blob with theme colors resolved and the logo inlined. Rejects when `value` is not set. | +| `toImage(options?)` | `Promise<File>` | Exports the QR code as an image file. `options` accepts `format` (`'png'` default, `'jpeg'`, `'webp'`, or `'svg'`), `scale` (default `1`), `fileName` (default `'qr-code'`), and `download` (default `false`). Rejects when `value` is not set or the options are invalid. | + +</PlatformBlock> + +## Styling + +<PlatformBlock for="Angular"> + +<Sample src="/data-display/qr-code-styling" height={300} noBackground={false} position="center" noBorder={false} spacing="md" alt="Angular QR Code styling example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/qr-code/styling" height={300} noBackground={false} position="center" noBorder={false} spacing="md" alt="{Platform} QR Code styling example" /> + +</PlatformBlock> + +The {Platform} QR Code appearance is controlled through CSS variables, CSS parts and the theming system. + +### Styling Variables + +| Variable | What it changes | +| -- | -- | +| `--ig-qr-code-background` | The background color of the QR code. Defaults to `white`. | +| `--ig-qr-code-dark-color` | The color of the data modules, and the corner square/dot colors unless overridden. Defaults to `black`. | +| `--ig-qr-code-corner-square-color` | The color of the outer finder-pattern corner squares. Falls back to `--ig-qr-code-dark-color`. | +| `--ig-qr-code-corner-dot-color` | The color of the inner finder-pattern corner dots. Falls back to `--ig-qr-code-dark-color`. | + +### Style Parts + +| Part | What it styles | +| -- | -- | +| `background` | The background rectangle of the QR code. | +| `dots` | The data modules (dots) of the QR code. | +| `corner-square` | The outer finder-pattern corner squares. | +| `corner-dot` | The inner finder-pattern corner dots. | + +### Sass Theming + +Create a theme with `qr-code-theme()` and pass it to the `tokens` mixin. + +```scss +@use "igniteui-theming/sass/themes" as *; + +$custom-qr-code-theme: qr-code-theme( + $background: #ffffff, + $dark-color: #1a1a2e, + $corner-square-color: #c0392b, + $corner-dot-color: #1a1a2e +); + +:root { + @include tokens($custom-qr-code-theme); +} +``` + +### CSS Variables + +Set the component CSS variables directly when you need local styling without a Sass build step. + +```css +igc-qr-code { + --ig-qr-code-background: var(--ig-gray-50); + --ig-qr-code-dark-color: var(--ig-primary-800); + --ig-qr-code-corner-square-color: var(--ig-secondary-800); +} +``` + +### Styling with Tailwind + +Combine Tailwind utility classes with the QR Code CSS variables. [Set up Tailwind](../themes/tailwind.mdx) with the Ignite UI theme first: + +```css +@import "tailwindcss/theme.css"; +@import "tailwindcss/utilities.css"; +``` + +Apply the `light-qr-code` utility to give the QR Code its theme variables, then override individual variables with arbitrary-property classes. The `!` prefix marks the utility as important so it takes precedence over the component's default styles. + +<PlatformBlock for="WebComponents, Angular"> + +```html +<igc-qr-code + value="https://www.infragistics.com" + class="!light-qr-code [--ig-qr-code-dark-color:#1a1a1a] [--ig-qr-code-background:#f7df1e]"> +</igc-qr-code> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrQrCode + value="https://www.infragistics.com" + className="!light-qr-code [--ig-qr-code-dark-color:#1a1a1a] [--ig-qr-code-background:#f7df1e]"> +</IgrQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbQrCode + Value="https://www.infragistics.com" + Class="!light-qr-code [--ig-qr-code-dark-color:#1a1a1a] [--ig-qr-code-background:#f7df1e]"> +</IgbQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +<Sample src="/data-display/qr-code-tailwind-styling" height={330} position="center" noBackground={false} noBorder={false} spacing="md" alt="Angular QR Code Tailwind styling example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/qr-code/tailwind-styling" height={330} position="center" noBackground={false} noBorder={false} spacing="md" alt="{Platform} QR Code Tailwind styling example" /> + +</PlatformBlock> + +## Accessibility + +The {Platform} QR Code is a static graphic that screen readers announce through the `<title>` of its SVG. + +### Keyboard Interaction + +The QR Code is not focusable and does not respond to keyboard input. + +### Screen Readers / ARIA + +The rendered `<svg>` has `role="img"` and a `<title>` that screen readers announce. The title defaults to `QR code: <value>`; set `aria-label` to announce a more meaningful phrase instead. + +<PlatformBlock for="WebComponents, Angular"> + +```html +<igc-qr-code + value="https://www.infragistics.com/products" + aria-label="Scan to visit our product page"> +</igc-qr-code> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrQrCode + value="https://www.infragistics.com/products" + ariaLabel="Scan to visit our product page"> +</IgrQrCode> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbQrCode + Value="https://www.infragistics.com/products" + AriaLabel="Scan to visit our product page"> +</IgbQrCode> +``` + +</PlatformBlock> + +### Accessibility Compliance + +Infragistics documents {ProductName} accessibility support for Section 508 and WCAG 2.1 guideline areas in the [Accessibility Compliance](../interactivity/accessibility-compliance.mdx) topic. + +| Criterion | How the component complies | +| -- | -- | +| [1.1.1 Non-text Content](https://www.w3.org/WAI/WCAG21/Understanding/non-text-content) | The SVG `<title>` provides a text alternative, taken from `aria-label` or derived from `value`. | +| [1.4.11 Non-text Contrast](https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast) | The default black modules on a white background exceed the 3:1 contrast ratio for graphical objects. | +| [4.1.2 Name, Role, Value](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value) | The SVG exposes `role="img"` with the `<title>` as its accessible name. | + +Your responsibilities: + +- Pair the QR Code with a short visible call to action so sighted users know what will happen after scanning. +- Provide an `aria-label` when the encoded `value` is opaque (e.g. a token or short identifier) so the announced text is meaningful. +- Keep sufficient contrast between the module color and the background when overriding CSS variables so scanners can read the code reliably. + +## Troubleshooting + +The {Platform} QR Code troubleshooting guidance follows a problem → cause → fix format for common integration and rendering issues. + +### Why is my QR code not scanning? + +Contrast between the modules and the background is too low, the code is too small on screen, or the quiet-zone margin is too small. Restore the default `black` on `white` colors, increase `size`, and use a `margin` of at least `4` modules for reliable scanning. + +### Why is my logo smaller than the logoSize I set? + +The logo is capped to the safe area of the current `errorLevel`. Set `errorLevel` to `H` to allow the largest logo. + +### Why is my logo not showing up? + +`logoSrc` uses a rejected source (an unsafe scheme or a non-image `data:` URI), or the image failed to load. Use a valid image URL or a `data:image/*` URI; assigning a valid source afterwards renders the logo. + +### Why did my QR code not switch to a dark theme automatically? + +QR Code colors do not invert with the global light/dark theme, because light-on-dark codes are not reliably scannable. To change them for the dark variant of your UI, set `--ig-qr-code-background` and `--ig-qr-code-dark-color` explicitly. + +## Known Limitations + +The {Platform} QR Code has the following limitations. + +- The QR Code has no slots or events. +- QR Code visual structure follows a fixed, standardized layout and is not mirrored in Right-to-Left contexts. + +<PlatformBlock for="WebComponents, Angular"> + +- Exports omit a logo loaded from a cross-origin URL that does not send CORS headers. + +</PlatformBlock> + +## API References + +Use these API references for the complete QR Code API surface. + +<PlatformBlock for="WebComponents, Angular"> + +[`IgcQrCodeComponent`]({environment:infragisticsBaseUrl}/api/webcomponents/igniteui-webcomponents/latest/classes/IgcQrCodeComponent) + +</PlatformBlock> + +<PlatformBlock for="React, Blazor"> + +<ApiLink pkg="core" type="QrCode" /> + +</PlatformBlock> + +## Dependencies + +The {Platform} QR Code requires a theme stylesheet, which you add in **Getting Started**. It has no other runtime dependencies. + +## Additional Resources + +Use these resources for support and related Ignite UI documentation. + +- [{ProductName} **Forums**]({ForumsLink}) +- [{ProductName} **GitHub**]({GithubLink}) + +## Related Components + +The QR Code is a standalone display primitive. When you need related visual content, consider the following components: + +- [Icon](../layouts/icon.mdx) — For static symbolic imagery that does not need to be scannable. +- [Avatar](../layouts/avatar.mdx) — For identity imagery representing people or entities. + +## FAQ + +<Faq> + <FaqItem question="What data can I encode in a QR Code?" indicatorPosition="end"> + The `value` property accepts any string. Common uses include URLs, plain text, payment references, one-time setup tokens, Wi-Fi credentials, and vCard payloads. The component automatically selects the most compact encoding mode (numeric, alphanumeric, or byte) that fits the input. + </FaqItem> + + <FaqItem question="Do I need an internet connection or an external library to render a QR Code?" indicatorPosition="end"> + No. The QR Code component generates the SVG entirely on the client from the string `value`, with no dependency on external QR-generation libraries. The only network request is for a center logo image loaded from a URL. + </FaqItem> + + <FaqItem question="How large can the center logo be without breaking the code?" indicatorPosition="end"> + The `logoSize` ratio (default `0.4`) is a fraction of the largest safe logo area, which is 9% of the code at the `H` error level. The QR Code caps the logo to the safe area of the current `errorLevel`, so the code stays scannable. Set `errorLevel` to `H` to allow the largest logo. + </FaqItem> + + <FaqItem question="Which package provides the QR Code?" indicatorPosition="end"> + <PlatformBlock for="WebComponents, Angular">The QR Code ships in the `igniteui-webcomponents` package, version 7.3.0 or later.</PlatformBlock> + <PlatformBlock for="Angular">Angular applications install it directly because `igniteui-angular` does not include the QR Code.</PlatformBlock> + <PlatformBlock for="React, Blazor">The QR Code ships in the `{PackageCommon}` package.</PlatformBlock> + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/en/components/inputs/switch.mdx b/docs/xplat/src/content/en/components/inputs/switch.mdx index 1e146ea14f..a445ec5a37 100644 --- a/docs/xplat/src/content/en/components/inputs/switch.mdx +++ b/docs/xplat/src/content/en/components/inputs/switch.mdx @@ -1,9 +1,11 @@ --- -title: "{Platform} Switch Component – {ProductName}" +title: "Switch" description: "{ProductName} Switch component enables developers to use binary on/off or true/false data input functions within their applications." keywords: "{ProductName}, UI controls, {Platform} widgets, web widgets, UI widgets, {Platform}, Native {Platform} Components Suite, Native {Platform} Controls, Native {Platform} Components Library, {Platform} Switch components, {Platform} Switch controls" mentionedTypes: ["Switch"] +relatedComponents: [Checkbox, ToggleButton] license: MIT +last_updated: "2026-08-31" llms: description: "The {ProductName} Switch component is a binary choice selection component that behaves similarly to the switch component in iOS." --- @@ -11,33 +13,97 @@ import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro' import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; +import Anatomy from 'igniteui-astro-components/components/mdx/Anatomy.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; +import { Image } from 'astro:assets'; +import switchAnatomy from '@xplat-images/anatomy-content-light/switch-lt-a.png'; +import switchDo from '@xplat-images/switch/switch-do.png'; +import switchDoNot from '@xplat-images/switch/switch-do-not.png'; - -# {Platform} Switch +# Switch Component The {ProductName} Switch component is a binary choice selection component that behaves similarly to the switch component in iOS. -## {Platform} Switch Example +## Live Demo + +<PlatformBlock for="Angular"> -<Sample src="/inputs/switches/overview" height={100} alt="{Platform} Switch Example" /> +<Sample src="/data-entries/switch-overview" showThemePicker height={500} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch Example" /> +</PlatformBlock> +<PlatformBlock for="React,WebComponents,Blazor"> -## Usage +<Sample src="/inputs/switches/overview" showThemePicker height={500} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch Example" /> + +</PlatformBlock> + +## Anatomy + +The {Platform} Switch contains a control for changing a binary state and an optional label. + +<Anatomy + class="switch-anatomy" + name="Switch" + description="The Switch component contains a control for changing a binary state and an optional label." + src={switchAnatomy.src} + alt="Switch anatomy" +/> + +<style>{` + .switch-anatomy { + --igd-anatomy-padding: 64px 32px; + } + + .switch-anatomy .igd-anatomy__image { + max-width: 142.5px; + } +`}</style> + +<span class="ig-typography__body-2" style="display: block; margin-bottom: 24px;"><strong>1. Track:</strong> indicates the switch path between on and off states.<br /> +<strong>2. Thumb:</strong> changes the current state.<br /> +<strong>3. Label (optional):</strong> describes what the switch controls.</span> + +The following diagram shows the logical structure of the {Platform} Switch. The control manages the binary state, while the optional label describes the setting controlled by the switch. + +```text +Switch +├── Control +└── Label (optional) +``` + +## Getting Started + +To use the {Platform} Switch, follow the <PlatformBlock for="Angular">[{ProductName} Getting Started](../general/getting-started.mdx)</PlatformBlock><PlatformBlock for="React,WebComponents,Blazor">[{ProductName} Getting Started](../general-getting-started.mdx)</PlatformBlock> topic for the basic project setup, then register the component for your target platform. At its core, the <ApiLink pkg="core" type="Switch" /> component allows for toggling between on/off states. The default styling is done according to the selection controls specification in the Material Design guidelines. +<PlatformBlock for="Angular"> -<PlatformBlock for="WebComponents"> +For Angular using the **igniteui-angular** package, install the package: + +```cmd +npm install igniteui-angular +``` + +Then import the `IgxSwitchComponent`: +```ts +import { IgxSwitchComponent } from 'igniteui-angular/switch'; +``` + +</PlatformBlock> -First, you need to install the {ProductName} by running the following command: +<PlatformBlock for="WebComponents"> + +For Web Components using the **{PackageWebComponents}** package, install the package: ```cmd npm install {PackageWebComponents} ``` -You will then need to import the <ApiLink pkg="core" type="Switch" />and its necessary CSS, like so: +Then import the <ApiLink pkg="core" type="Switch" />, its theme CSS, and register the component: ```ts import { defineComponents, IgcSwitchComponent } from "igniteui-webcomponents"; @@ -46,23 +112,17 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; defineComponents(IgcSwitchComponent); ``` -For a complete introduction to the {ProductName}, read the [**Getting Started**](../general-getting-started.mdx) topic. - - </PlatformBlock> - - <PlatformBlock for="React"> - -First, you need to the install the corresponding {ProductName} npm package by running the following command: +For React using the **igniteui-react** package, install the package: ```cmd npm install igniteui-react ``` -You will then need to import the <ApiLink pkg="core" type="Switch" /> and its necessary CSS, like so: +Then import the Switch wrapper and its theme CSS: ```tsx import { IgrSwitch } from 'igniteui-react'; @@ -71,14 +131,9 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; </PlatformBlock> - - <PlatformBlock for="Blazor"> - - -Before using the <ApiLink pkg="core" type="Switch" />, you need to register it as follows: - +For Blazor using the **IgniteUI.Blazor** package, register the Switch module as follows: ```csharp // in Program.cs file @@ -86,18 +141,24 @@ Before using the <ApiLink pkg="core" type="Switch" />, you need to register it a builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); ``` -You will also need to link an additional CSS file to apply the styling to the <ApiLink pkg="core" type="Switch" /> component. The following needs to be placed in the **wwwroot/index.html** file in a **Blazor Web Assembly** project or the **Pages/_Host.cshtml** file in a **Blazor Server** project: +Then link the additional CSS file in the **wwwroot/index.html** file for a **Blazor WebAssembly** project or in the **Pages/_Host.cshtml** file for a **Blazor Server** project: ```razor <link href="_content/IgniteUI.Blazor/themes/light/bootstrap.css" rel="stylesheet" /> ``` - </PlatformBlock> - The simplest way to start using the <ApiLink pkg="core" type="Switch" /> is as follows: +<PlatformBlock for="Angular"> + +```html +<igx-switch [checked]="true">Simple switch</igx-switch> +``` + +</PlatformBlock> + <PlatformBlock for="WebComponents"> ```html @@ -122,20 +183,32 @@ The simplest way to start using the <ApiLink pkg="core" type="Switch" /> is as f </PlatformBlock> +<PlatformBlock for="Blazor"> + <DocsAside type="warning" title="Warning"> -The <ApiLink pkg="core" type="Switch" /> component doesn't work with the standard `<form>` element. Use `Form` instead. +The <ApiLink pkg="core" type="Switch" /> component doesn't work with a standard HTML `<form>` element in Blazor. Use the Blazor `EditForm` component instead. </DocsAside> -## Examples +</PlatformBlock> + +## Usage + +Use the {Platform} Switch as a binary choice control for settings that take effect immediately when the user changes their state. + +The following example shows the basic Switch configuration. To provide a meaningful label for the switch, simply place some text between the opening and closing tags: + +<PlatformBlock for="Angular"> -### Label +```html +<igx-switch>Accept terms</igx-switch> +``` -To provide a meaningful label for the switch, simply place some text between the opening and closing tags: +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<IgrSwitch><span>Label</span></IgrSwitch> +<IgrSwitch>Accept terms</IgrSwitch> ``` </PlatformBlock> @@ -143,7 +216,7 @@ To provide a meaningful label for the switch, simply place some text between the <PlatformBlock for="WebComponents"> ```html -<igc-switch>Label</igc-switch> +<igc-switch>Accept terms</igc-switch> ``` </PlatformBlock> @@ -151,17 +224,24 @@ To provide a meaningful label for the switch, simply place some text between the <PlatformBlock for="Blazor"> ```razor -<IgbSwitch>Label</IgbSwitch> +<IgbSwitch>Accept terms</IgbSwitch> ``` </PlatformBlock> -You can specify if the label should be positioned before or after the switch toggle by setting the <ApiLink pkg="core" type="Switch" member="labelPosition" label="LabelPosition" /> attribute of the switch. Allowed values are `before` and `after`(default): +You can use the <ApiLink pkg="core" type="Switch" member="required" label="required" /> property to mark the switch as required. + +<PlatformBlock for="Angular"> +```html +<igx-switch [required]="true">Label</igx-switch> +``` + +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<IgrSwitch aria-labelledby="switchLabel" labelPosition="before" ><span id="switch-label">Label</span></IgrSwitch> +<IgrSwitch required={true}></IgrSwitch> ``` </PlatformBlock> @@ -169,7 +249,7 @@ You can specify if the label should be positioned before or after the switch tog <PlatformBlock for="WebComponents"> ```html -<igc-switch label-position="before">Label</igc-switch> +<igc-switch required></igc-switch> ``` </PlatformBlock> @@ -177,20 +257,24 @@ You can specify if the label should be positioned before or after the switch tog <PlatformBlock for="Blazor"> ```razor -<IgbSwitch LabelPosition="@ToggleLabelPosition.Before">Label</IgbSwitch> +<IgbSwitch Required="true" /> ``` </PlatformBlock> -The switch can also be labelled by elements external to the switch. In this case, the user is given full control to position and style the label in accordance with their needs. +You can use the <ApiLink pkg="core" type="Switch" member="invalid" label="invalid" /> property to mark the switch as invalid. + +<PlatformBlock for="Angular"> +```html +<igx-switch [invalid]="true">Label</igx-switch> +``` + +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<> - <span id="switch-label">Label</span> - <IgrSwitch aria-labelledby="switch-label"></IgrSwitch> -</> +<IgrSwitch invalid={true}></IgrSwitch> ``` </PlatformBlock> @@ -198,8 +282,7 @@ The switch can also be labelled by elements external to the switch. In this case <PlatformBlock for="WebComponents"> ```html -<span id="switch-label">Label</span> -<igc-switch aria-labelledby="switch-label"></igc-switch> +<igc-switch invalid></igc-switch> ``` </PlatformBlock> @@ -207,25 +290,43 @@ The switch can also be labelled by elements external to the switch. In this case <PlatformBlock for="Blazor"> ```razor -<span id="switch-label">Label</span> -<IgbSwitch AriaLabelledBy="switch-label" /> +<IgbSwitch Invalid="true" /> ``` </PlatformBlock> -<Sample src="/inputs/switches/label" height={100} alt="{Platform} Avatar Example" /> +### Interaction States + +The Switch can be inserted in an `Enabled` or `Disabled` state. In `Enabled` state, the switch also supports `Hover`, `Focused` and `Focused & Hover` states. + +<PlatformBlock for="Angular"> + +<Sample src="/data-entries/switch-enabled" showThemePicker height={316} position="start center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch interaction states example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/switches/enabled" showThemePicker height={316} position="start center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch interaction states example" /> + +</PlatformBlock> +### Disabled States +You may also set the state of the switch to `Disabled` to disallow user interaction with it. You can use the <ApiLink pkg="core" type="Switch" member="disabled" label="disabled" /> attribute to set this state. +<PlatformBlock for="Angular"> -### Checked +```html +<igx-switch [disabled]="true">Label</igx-switch> +``` -You can use the <ApiLink pkg="core" type="Switch" member="checked" label="checked" /> attribute to toggle on the switch. +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<IgrSwitch checked={true}></IgrSwitch> +<IgrSwitch disabled={true}></IgrSwitch> ``` </PlatformBlock> @@ -233,7 +334,7 @@ You can use the <ApiLink pkg="core" type="Switch" member="checked" label="checke <PlatformBlock for="WebComponents"> ```html -<igc-switch checked></igc-switch> +<igc-switch disabled></igc-switch> ``` </PlatformBlock> @@ -241,24 +342,43 @@ You can use the <ApiLink pkg="core" type="Switch" member="checked" label="checke <PlatformBlock for="Blazor"> ```razor -<IgbSwitch Checked="true" /> +<IgbSwitch Disabled="true" /> ``` </PlatformBlock> -<Sample src="/inputs/switches/checking" height={100} alt="{Platform} Switch Example" /> +<PlatformBlock for="Angular"> + +<Sample src="/data-entries/switch-disabled" showThemePicker height={212} position="start" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch Disabled Example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/switches/disabled" showThemePicker height={212} position="start" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch Disabled Example" /> + +</PlatformBlock> + +### On/Off States +The Switch can be set to an `On` or `Off` state to indicate whether a setting is enabled or disabled. +<PlatformBlock for="Angular"> +```html +<igx-switch [checked]="true">On</igx-switch> +<igx-switch [checked]="false">Off</igx-switch> +``` -### Required +<Sample src="/data-entries/switch-selected" showThemePicker height={250} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch on and off states example" /> -You can use the <ApiLink pkg="core" type="Switch" member="required" label="required" /> attribute to mark the switch as required. +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<IgrSwitch required={true}></IgrSwitch> +<IgrSwitch checked={true}>On</IgrSwitch> +<IgrSwitch checked={false}>Off</IgrSwitch> ``` </PlatformBlock> @@ -266,7 +386,8 @@ You can use the <ApiLink pkg="core" type="Switch" member="required" label="requi <PlatformBlock for="WebComponents"> ```html -<igc-switch required></igc-switch> +<igc-switch checked>On</igc-switch> +<igc-switch>Off</igc-switch> ``` </PlatformBlock> @@ -274,19 +395,43 @@ You can use the <ApiLink pkg="core" type="Switch" member="required" label="requi <PlatformBlock for="Blazor"> ```razor -<IgbSwitch Required="true" /> +<IgbSwitch Checked="true">On</IgbSwitch> +<IgbSwitch Checked="false">Off</IgbSwitch> ``` </PlatformBlock> -### Invalid +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/switches/selected" showThemePicker height={250} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch on and off states example" /> + +</PlatformBlock> + +### Layout + +You can specify if the label should be positioned before or after the switch toggle by setting the <ApiLink pkg="core" type="Switch" member="labelPosition" label="LabelPosition" /> property of the switch. Allowed values are `before` and `after` (default): + +<PlatformBlock for="Angular"> +```html +<igx-switch labelPosition="before">Label</igx-switch> +``` + +<Sample src="/data-entries/switch-layout" showThemePicker height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch layout example" /> + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrSwitch aria-labelledby="switch-label" labelPosition="before"><span id="switch-label">Label</span></IgrSwitch> +``` -You can use the <ApiLink pkg="core" type="Switch" member="invalid" label="invalid" /> attribute to mark the switch as invalid. +</PlatformBlock> <PlatformBlock for="WebComponents"> ```html -<igc-switch invalid></igc-switch> +<igc-switch label-position="before">Label</igc-switch> ``` </PlatformBlock> @@ -294,19 +439,26 @@ You can use the <ApiLink pkg="core" type="Switch" member="invalid" label="invali <PlatformBlock for="Blazor"> ```razor -<IgbSwitch Invalid="true" /> +<IgbSwitch LabelPosition="@ToggleLabelPosition.Before">Label</IgbSwitch> ``` </PlatformBlock> -### Disabled +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/switches/layout" showThemePicker height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch layout example" /> + +</PlatformBlock> -You can use the <ApiLink pkg="core" type="Switch" member="disabled" label="disabled" /> attribute to disable the switch. +The switch can also be labelled by elements external to the switch. In this case, the user is given full control to position and style the label in accordance with their needs. <PlatformBlock for="React"> ```tsx -<IgrSwitch disabled="true"></IgrSwitch> +<> + <span id="switch-label">Label</span> + <IgrSwitch aria-labelledby="switch-label"></IgrSwitch> +</> ``` </PlatformBlock> @@ -314,7 +466,8 @@ You can use the <ApiLink pkg="core" type="Switch" member="disabled" label="disab <PlatformBlock for="WebComponents"> ```html -<igc-switch disabled></igc-switch> +<span id="switch-label">Label</span> +<igc-switch aria-labelledby="switch-label"></igc-switch> ``` </PlatformBlock> @@ -322,28 +475,57 @@ You can use the <ApiLink pkg="core" type="Switch" member="disabled" label="disab <PlatformBlock for="Blazor"> ```razor -<IgbSwitch Disabled="true" /> +<span id="switch-label">Label</span> +<IgbSwitch AriaLabelledBy="switch-label" /> ``` </PlatformBlock> -<Sample src="/inputs/switches/disabled" height={100} alt="{Platform} Switch Example" /> - +### Do/Don't +**When to use:** Use Switch for an immediate on/off setting that takes effect when the user changes it. +<PlatformBlock for="Angular"> -### Forms +**When not to use:** Use [Checkbox](../checkbox.mdx) when users select one or more options for a later form submission, or [Button](./button.mdx) when the control represents an action or a toggleable command. -You can use the <ApiLink pkg="core" type="Switch" member="name" label="name" /> and <ApiLink pkg="core" type="Switch" member="value" label="value" /> attributes when using the switch with `Form`. +</PlatformBlock> -<PlatformBlock for="React"> +<PlatformBlock for="React,WebComponents,Blazor"> -```tsx -<IgrSwitch name="wifi" value="enabled"></IgrSwitch> -``` +**When not to use:** Use [Checkbox](./checkbox.mdx) when users select one or more options for a later form submission, or [Button](./button.mdx) when the control represents an action or a toggleable command. </PlatformBlock> +<div class="table-responsive"> + <table class="table" style="width: 100%; table-layout: fixed; border-collapse: collapse; border: 1px solid #d3d3d3; margin-bottom: 24px;"> + <thead> + <tr> + <th style="width: 50%; background-color: #d3d3d3; text-align: left; padding: 16px 20px; font-size: 18px; font-weight: 500;">Do</th> + <th style="width: 50%; background-color: #d3d3d3; text-align: left; padding: 16px 20px; font-size: 18px; font-weight: 500;">Don't</th> + </tr> + </thead> + <tbody> + <tr> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={switchDo} alt="Switch used for an immediate on/off setting" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={switchDoNot} alt="Switch used for selecting options or representing an action" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + </tr> + </tbody> + </table> +</div> + +## Properties + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| <ApiLink pkg="core" type="Switch" member="checked" label="checked" /> | `boolean` | `false` | Gets or sets whether the switch is on. | +| <ApiLink pkg="core" type="Switch" member="disabled" label="disabled" /> | `boolean` | `false` | Gets or sets whether the switch is disabled. | +| <ApiLink pkg="core" type="Switch" member="invalid" label="invalid" /> | `boolean` | `false` | Gets or sets whether the switch is invalid. | +| <ApiLink pkg="core" type="Switch" member="labelPosition" label="labelPosition" /> | `ToggleLabelPosition` | `after` | Sets the position of the label relative to the control. | +| <ApiLink pkg="core" type="Switch" member="name" label="name" /> | `string` | `-` | Sets the name used when the switch is submitted with a form. | +| <ApiLink pkg="core" type="Switch" member="required" label="required" /> | `boolean` | `false` | Gets or sets whether the switch is required. | +| <ApiLink pkg="core" type="Switch" member="value" label="value" /> | `string` | `-` | Sets the value used when the switch is submitted with a form. | + <PlatformBlock for="WebComponents"> ```html @@ -362,35 +544,267 @@ You can use the <ApiLink pkg="core" type="Switch" member="name" label="name" /> ## Styling -The <ApiLink pkg="core" type="Switch" /> component exposes several CSS parts to give you full control over its styling: +The {Platform} Switch uses CSS parts and CSS variables to style its track, thumb, and label. + +<PlatformBlock for="Angular"> + +### Sass Theming + +To get started with styling the switch, import the `index` file, where all the theme functions and the `tokens()` mixin are exported: + +```scss +@use "igniteui-angular/theming" as *; +``` + +Then create a new theme that extends <ApiLink kind="sass" module="themes" type="function-switch-theme" label="switch-theme" code={true} />. Providing `$thumb-off-color` and `$thumb-on-color` is enough to get a fully styled switch, because the theme generates the remaining colors from them: + +```scss +$custom-switch-theme: switch-theme( + $thumb-off-color: #7cadd5, + $thumb-on-color: #ecaa53, +); +``` + +Finally, include the custom theme in your application: + +```scss +:host { + @include tokens($custom-switch-theme); +} +``` + +<Sample src="/data-entries/switch-styling" height={500} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch styling example" /> + +### Styling with Tailwind + +You can style the switch using the Ignite UI Tailwind utility classes. Make sure to [set up Tailwind](/themes/misc/tailwind-classes) first, then import the utility file in your global stylesheet: + +```scss +@import "tailwindcss"; +@use 'igniteui-theming/tailwind/utilities/material.css'; +``` + +Use `light-switch` or `dark-switch` for the corresponding theme and override the generated CSS variables with arbitrary properties. You can find the full list of properties in the <ApiLink kind="sass" module="themes" type="function-switch-theme" label="IgxSwitch Theme" />: + +```html +<igx-switch + class="!light-switch ![--thumb-on-color:#FF4E00]" + [checked]="true"> + Label +</igx-switch> +``` + +The exclamation mark (`!`) makes the utility class important so it takes precedence over the component theme. + +<Sample src="/data-entries/switch-tailwind-styling" height={450} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch Tailwind styling example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +### Sass Theming + +Use the {ProductName} theme system to style the Switch consistently with the rest of your application. + +Import the theming functions before creating a custom Switch theme: + +```scss +@use "igniteui-theming" as *; +``` + +Create a theme with `switch-theme` and include it in the global stylesheet. The track and thumb parameters are used as the base for the related interaction-state colors: + +```scss +$custom-switch: switch-theme( + $track-on-color: #57a5cd, +); + +igc-switch { + @include switch($custom-switch); +} +``` + +The same theme applies to Web Components directly and to the underlying `igc-switch` element rendered by the React and Blazor wrappers. + +### CSS Variables + +Use the following CSS variables to customize the Switch colors and interaction states. Set them on the Switch element to apply the styles to its track, thumb, and label: + +| Primary property | Dependent property | Description | +| --- | --- | --- | +| `--track-on-color` | `--track-on-hover-color` | Track background when the switch is checked. | +| | `--track-off-color` | Track background when the switch is unchecked. | +| `--thumb-on-color` | `--thumb-off-color` | Thumb color for the checked and unchecked states. | +| `--label-color` | `--label-disabled-color` | Label color for the default and disabled states. | + +### Style Parts + +Use the following CSS parts to target the Switch and its inner elements: + +| Part | Component | What it styles | +| --- | --- | --- | +| `base` | <ApiLink pkg="core" type="Switch" /> | The base wrapper of the switch. | +| `control` | <ApiLink pkg="core" type="Switch" /> | The switch input element. | +| `thumb` | <ApiLink pkg="core" type="Switch" /> | The position indicator of the switch. | +| `label` | <ApiLink pkg="core" type="Switch" /> | The switch label. | -|Name|Description| -|--|--| -| `base` | The base wrapper of the switch. | -| `control` | The switch input element. | -| `thumb` | The position indicator of the switch. | -| `label` | The switch label. | +### Custom Styling + +The following example changes the track and thumb colors for the checked and unchecked states: + +| Selector | Declaration | Effect | +| --- | --- | --- | +| `igc-switch` | `--track-on-color`, `--track-off-color` | Changes the track background for the checked and unchecked states. | +| `igc-switch` | `--thumb-on-color`, `--thumb-off-color` | Changes the thumb color for the checked and unchecked states. | ```css - igc-switch { - --thumb-on-color: white; - --thumb-off-color: var(--ig-success-500); - --track-on-color: var(--ig-success-500); /* Background color when checked */ - --track-off-color: white; /* Background color when unchecked */ - --track-on-hover-color: var(--ig-success-500); /* Background hover color when checked */ - } +igc-switch { + --thumb-on-color: white; + --thumb-off-color: var(--ig-success-500); + --track-on-color: var(--ig-success-500); /* Background color when checked */ + --track-off-color: white; /* Background color when unchecked */ + --track-on-hover-color: var(--ig-success-500); /* Background hover color when checked */ +} +``` + +<Sample src="/inputs/switches/styling" height={500} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch Styling Example" /> + +### Styling with Tailwind + +You can style the {Platform} Switch with the custom Tailwind utility classes from `igniteui-theming`. Make sure to [set up Tailwind](/themes/tailwind) first, then import the Ignite UI utilities in your global stylesheet: + +```css +@import "tailwindcss"; +@import "igniteui-theming/tailwind/utilities/material.css"; +``` + +<PlatformBlock for="React"> + +```jsx +<IgrSwitch className="!light-switch ![--track-on-color:#7B9E89]"></IgrSwitch> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-switch class="!light-switch ![--track-on-color:#7B9E89]"></igc-switch> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbSwitch Class="!light-switch ![--track-on-color:#7B9E89]" /> ``` -<Sample src="/inputs/switches/styling" height={100} alt="{Platform} Switch Styling" /> +</PlatformBlock> + +The exclamation mark (`!`) gives the Tailwind utility precedence over the Switch's default theme styles. + +<Sample src="/inputs/switches/tailwind-styling" height={450} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch Tailwind styling example" /> + +</PlatformBlock> +## Accessibility +The {Platform} Switch exposes a binary state and supports an accessible name through its label or ARIA attributes. + +### Keyboard Interaction + +| Key | Action | +| --- | --- | +| Tab / Shift+Tab | Moves focus to or from the switch. | +| Space | Toggles the focused switch. | + +### Screen Readers / ARIA + +The Switch renders an interactive control with a binary checked state. Provide visible label content or an accessible name with `aria-label` or `aria-labelledby`, and keep the label specific to the setting controlled by the switch. + +<PlatformBlock for="WebComponents, React, Blazor"> + +- The control exposes its checked state and disabled state to assistive technology. +- The `igcChange` event is emitted when the checked state changes. + +</PlatformBlock> + +### Accessibility Compliance + +Infragistics documents {ProductName} accessibility support for Section 508 and WCAG 2.1 guideline areas in the [Accessibility Compliance](../interactivity/accessibility-compliance.mdx) topic. + +| Criterion | How the component complies | +| --- | --- | +| [2.1.1 Keyboard](https://www.w3.org/WAI/WCAG21/Understanding/keyboard) | The switch can be reached with the keyboard and toggled with Space. | +| [4.1.2 Name, Role, Value](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value) | The switch exposes an accessible name and its binary checked state through the rendered control. | + +## Troubleshooting + +Use this section to check boundaries and common decisions before treating Switch as a form field, interactive command, or setting control. + +### Why does the Switch not submit with my form? + +The Switch is form-associated but requires a `name` and `value` to contribute a value when the form is submitted. Set both properties and use the form integration supported by your target platform. + +### Why is the Switch not announced correctly by a screen reader? + +The Switch needs an accessible name. Add visible label content or reference an external label with `aria-labelledby`; use `aria-label` when visible text is not available. + +### Known Limitations + +The {Platform} Switch has the following platform-independent limitations: + +- A Switch represents one binary setting; use a different control when users need multiple choices or a deferred form selection. +- A Switch does not provide an accessible name automatically when it has no label or ARIA naming attribute. ## API References +See the complete {Platform} Switch API reference: + +<ApiLink pkg="core" type="Switch" /> + +<PlatformBlock for="Angular"> +<ApiLink kind="sass" module="themes" type="function-switch-theme" label="IgxSwitchComponent Theme" /> +</PlatformBlock> + +## Dependencies -<ApiLink pkg="core" type="Switch" /><br /> +The {Platform} Switch requires a theme stylesheet to apply its visual styling. See the framework-specific setup in <PlatformBlock for="Angular">[**Getting Started**](../general/getting-started.mdx)</PlatformBlock><PlatformBlock for="React,WebComponents,Blazor">[**Getting Started**](../general-getting-started.mdx)</PlatformBlock>. ## Additional Resources +Use the following {Platform} resources for API details, examples, and project support: + +- [Lists - Design System Pattern](https://www.infragistics.com/products/indigo-design/help/patterns/lists) - [{ProductName} **Forums**]({ForumsLink}) - [{ProductName} **GitHub**]({GithubLink}) + +## Related Components + +<PlatformBlock for="Angular"> +- [Checkbox](../checkbox.mdx) - Use Checkbox when users select one or more options, especially as part of a form. +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> +- [Checkbox](./checkbox.mdx) - Use Checkbox when users select one or more options, especially as part of a form. +</PlatformBlock> + +- [Button](./button.mdx) - Use Button when the control represents a command or action rather than a setting. + +## FAQ + +<Faq> + <FaqItem question="How do I set the Switch to its initial on or off state?"> + Set the <ApiLink pkg="core" type="Switch" member="checked" label="checked" /> property to `true` for the on state or `false` for the off state. The property uses a Boolean value in React, Web Components, and Blazor syntax. + </FaqItem> + <FaqItem question="How do I position the Switch label?"> + Place the label text inside the Switch and set the <ApiLink pkg="core" type="Switch" member="labelPosition" label="labelPosition" /> property to `before` or `after`. The default label position is `after`. + </FaqItem> + <FaqItem question="How do I submit a Switch value with a form?"> + Set both the <ApiLink pkg="core" type="Switch" member="name" label="name" /> and <ApiLink pkg="core" type="Switch" member="value" label="value" /> properties. In Blazor, use the `EditForm` component instead of a standard HTML `form`. + </FaqItem> + <FaqItem question="How do I make a Switch required or invalid?"> + Set the <ApiLink pkg="core" type="Switch" member="required" label="required" /> property when the setting must be selected, and set <ApiLink pkg="core" type="Switch" member="invalid" label="invalid" /> when the control is in an invalid state. Use <ApiLink pkg="core" type="Switch" member="disabled" label="disabled" /> when users must not be able to change the setting. + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/en/components/interactivity/accessibility-compliance.mdx b/docs/xplat/src/content/en/components/interactivity/accessibility-compliance.mdx index 90b08074cf..dddc3e6a9d 100644 --- a/docs/xplat/src/content/en/components/interactivity/accessibility-compliance.mdx +++ b/docs/xplat/src/content/en/components/interactivity/accessibility-compliance.mdx @@ -1,199 +1,252 @@ --- -title: Ignite UI for {Platform} Accessibility Compliance | Ignite UI for {Platform} | Infragistics -description: Ignite UI for {Platform} Accessibility Support and Compliance - Section 508 Compliance, WCAG and ARIA . -keywords: accessibility, {Platform}, ignite ui for {Platform}, infragistics +title: "{Platform} Accessibility Compliance | {ProductName} | Infragistics" +description: "Accessibility support in {ProductName} - the standards we target, per-component keyboard and screen reader status, and how to report an accessibility issue." +keywords: "{ProductName}, Infragistics, Accessibility, WCAG, Section 508, EN 301 549, ARIA, Keyboard" license: MIT +last_updated: "2026-08-27" mentionedTypes: [] llms: - description: "As the leading global provider of UI and UX tools for developers, our {Platform} team at Infragistics is committed to providing components and tools that make it easier for you to create the best possible user experience." + description: "Accessibility support in {ProductName}: the conformance standards targeted, the per-component keyboard and screen-reader documentation index, required configuration, and the channel for reporting accessibility issues." --- + import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; +import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; -<style>{` -.greenCheck { - content:url("${import.meta.env.BASE_URL.replace(/\/$/, '')}/images/general/greenCheck.png"); -} +# Accessibility Compliance -.redCheck { - content:url("${import.meta.env.BASE_URL.replace(/\/$/, '')}/images/general/redX.png"); -} -`}</style> +This page records the accessibility standards {ProductName} targets, what each component's own documentation covers today, and how to report an accessibility problem. -# Accessibility Compliance +Accessibility support is delivered by two layers — the components themselves and the theming engine that styles them. Use this page to find the status of a specific component; use [Theming Accessibility](../themes/accessibility.mdx) for contrast, text scaling, and chart color behavior. + +<DocsAside type="note"> +**Scope of this page.** The information below reflects the **Default theme** and the current documented behavior of each component. It is a support summary, not a formal conformance statement. Custom themes, typography changes, and animation or color overrides can change the result. +</DocsAside> -As the leading global provider of UI and UX tools for developers, our {Platform} team at Infragistics is committed to providing components and tools that make it easier for you to create the best possible user experience. Our goal is to enable you to focus on crafting the best applications and the best user experience for all users. - -Here you can find specific information regarding the accessibility support and compliance for our {Platform} grids, charts, and UI components and controls within Ignite UI for {Platform}. - -## Section 508 Compliance - -[Section 508](http://www.section508.gov/) of the Rehabilitation Act was amended in 1998 by Congress to require all Federal agencies to make their electronic and information technology accessible to people with disabilities. Since then, Section 508 compliance has not only been a requirement in government agencies, but it's also important when providing software solutions and designing Web pages. - -Section 1194.22 of the Section 508 law specifically targets Web-based intranet and internet information and systems, and contains a set of 16 rules to follow. In order to enable you to keep your Web applications and Web sites compatible with these rules with minimal effort on your part, Infragistics has taken steps to ensure that the Ignite UI for {Platform} controls and components are compliant with the relevant accessibility rules. - -The matrix below provides a high-level outline of the accessibility support provided by our visual controls (and related components). To learn more about an individual control/component's accessibility compliance, click the name of the control/component. - -### Ignite UI for {Platform} Compliance with Section 508 - -|**Component/Principle**|<a title="A text equivalent for every non-text element shall be provided (e.g., via 'alt', 'longdesc', or in element content)."> (a)</a><br/>|<a title="Equivalent alternatives for any multimedia presentation shall be synchronized with the presentation">(b)</a><br/>|<a title="Web pages shall be designed so that all information conveyed with color is also available without color, for example from context or markup">(c)</a><br/>|<a title="Documents shall be organized so they are readable without requiring an associated style sheet">(d)</a><br/>|<a title="Redundant text links shall be provided for each active region of a server-side image map">(e)</a><br/>|<a title="Client-side image maps shall be provided instead of server-side image maps except where the regions cannot be defined with an available geometric shape">(f)</a><br/>|<a title="Row and column headers shall be identified for data tables">(g)</a><br/>|<a title="Markup shall be used to associate data cells and header cells for data tables that have two or more logical levels of row or column headers">(h)</a><br/>|<a title="Frames shall be titled with text that facilitates frame identification and navigation">(i)</a><br/>|<a title="Pages shall be designed to avoid causing the screen to flicker with a frequency greater than 2 Hz and lower than 55 Hz">(j)</a><br/>|<a title="A text-only page, with equivalent information or functionality, shall be provided to make a web site comply with the provisions of this part, when compliance cannot be accomplished in any other way">(k)</a><br/>|<a title="When pages utilize scripting languages to display content, or to create interface elements, the information provided by the script shall be identified with functional text that can be read by assistive technology.">(l)</a><br/>|<a title="When a web page requires that an applet, plug-in or other application be present on the client system to interpret page content, the page must provide a link to a plug-in or applet that complies with §1194.21 (a)">(m)</a><br/>|<a title="When electronic forms are designed to be completed online, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues.">(n)</a><br/>|<a title="A method shall be provided that permits users to skip repetitive navigation links.">(o)</a><br/>|<a title="When a timed response is required, the user shall be alerted and given sufficient time to indicate more time is required">(p)</a><br/>| -|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--| -|**Grids**||||||||||||||||| -| - Grid|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -| - HierarchicalGrid|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -| - TreeGrid|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -|**Other**||||||||||<span class="greenCheck" />*||||||| -| - Avatar|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Badge|<span class="greenCheck" />||<span class="greenCheck" />|||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Bottom navigation|||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Button|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Button group|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Calendar|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Card|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Carousel|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -| - Checkbox|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Chip|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Circular progress|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Combo|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />||| -| - Date time input|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Date picker|||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Divider|<span class="greenCheck" />||<span class="greenCheck" />|||||||||<span class="greenCheck" />||||| -| - Dialog|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Drop down|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />||| -| - Expansion panel|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Icon|||<span class="greenCheck" />|||||||||<span class="redCheck" />||||| -| - Input|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Input group|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Linear progress|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - List|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Navbar|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Navigation drawer|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Radio group|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Radio|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Select|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />||| -| - Slider|||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Snackbar|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -| - Switch|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Tabs|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Time picker|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Toast|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| - - -**LEGEND** - -|||| +## Standards We Target + +| Standard | Region | What it requires | |---|---|---| -|<span class="greenCheck" />|The control/component is completely accessible in this particular area.|| -|<span class="greenCheck" />*|The control/component is accessible in this particular area after implementing certain configurations| Example: Use **NoopAnimationsModule**utility module to allow disabling of animations| -|<span class="redCheck" />|The control/component is not entirely accessible unless you perform some sort of action.|| -|'white space'|this particular rule does not apply to the control|| +| <a href="https://www.w3.org/WAI/WCAG21/quickref/" target="_blank" rel="noopener noreferrer">WCAG 2.1 Level AA</a> | International | The success criteria listed below. The baseline referenced by the other two. | +| <a href="https://www.section508.gov/" target="_blank" rel="noopener noreferrer">Section 508 (Revised)</a> | United States | Federal procurement. Since the Revised Section 508 Standards (published 2017, compliance date January 2018) it incorporates WCAG 2.0 Level AA by reference, so it is satisfied by the same work. | +| <a href="https://www.etsi.org/deliver/etsi_en/301500_301599/301549/" target="_blank" rel="noopener noreferrer">EN 301 549</a> | Europe | The European standard referenced for ICT accessibility, built on WCAG. The European Accessibility Act, which builds on it, applies from 28 June 2025. | -<DocsAside type="warning"> -The table above is relevant only to the **Default theme** of Ignite UI for {Platform} theming library. The checklist compliance might be different when it comes to custom themes, typography and any visual changes related to animations and colors. +<DocsAside type="note"> +Section 508 previously defined its own 16 rules under §1194.22. Those were superseded by the Revised Standards, which adopt WCAG directly. Targeting WCAG 2.1 Level AA therefore addresses all three frameworks above. </DocsAside> -### Compliance Information - -- **a** - A text equivalent for every non-text element shall be provided (e.g., via "alt", "longdesc", or in element content). -- **b** - Equivalent alternatives for any multimedia presentation shall be synchronized with the presentation. -- **c** - Web pages shall be designed so that all information conveyed with color is also available without color, for example from context or markup. -- **d** - Documents shall be organized so they are readable without requiring an associated style sheet. -- **e** - Redundant text links shall be provided for each active region of a server-side image map. -- **f** - Client-side image maps shall be provided instead of server-side image maps except where the regions cannot be defined with an available geometric shape. -- **g** - Row and column headers shall be identified for data tables. -- **h** - Markup shall be used to associate data cells and header cells for data tables that have two or more logical levels of row or column headers. -- **i** - Frames shall be titled with text that facilitates frame identification and navigation. -- **j** - Pages shall be designed to avoid causing the screen to flicker with a frequency greater than 2 Hz and lower than 55 Hz. -- **k** - A text-only page, with equivalent information or functionality, shall be provided to make a web site comply with the provisions of this part, when compliance cannot be accomplished in any other way. The content of the text-only page shall be updated whenever the primary page changes. -- **l** - When pages utilize scripting languages to display content, or to create interface elements, the information provided by the script shall be identified with functional text that can be read by assistive technology. -- **m** - When a web page requires that an applet, plug-in or other application be present on the client system to interpret page content, the page must provide a link to a plug-in or applet that complies with §1194.21(a) through l. -- **n** - When electronic forms are designed to be completed on-line, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. -- **o** - A method shall be provided that permits users to skip repetitive navigation links. -- **p** - When a timed response is required, the user shall be alerted and given sufficient time to indicate more time is required. - - -## WCAG compliance -[WCAG](https://www.w3.org/WAI/WCAG21/quickref/?showtechniques=111) is simply a set of formal guidelines on how to develop accessible web content. These standards represent a higher level of accessibility than 508 standards, although they are identical or very similar. WCAG focuses primarily on HTML accessibility. - -|**Component/Guideline**|<a title="Text Alternatives - Provide text alternatives for any non-text content so that it can be changed into other forms people need, such as large print, braille, speech, symbols or simpler language.">1.1</a><br/>|<a title="Time-based Media - Provide alternatives for time-based media.">1.2</a><br/>|<a title="Adaptable - Create content that can be presented in different ways (for example simpler layout) without losing information or structure">1.3 </a><br/>|<a title="Distinguishable - Make it easier for users to see and hear content including separating foreground from background.">1.4</a><br/>|<a title="Keyboard Accessible - Make all functionality available from a keyboard">2.1</a><br/>|<a title="Enough Time - Provide users enough time to read and use content.">2.2</a><br/>|<a title="Seizures and Physical Reactions - Do not design content in a way that is known to cause seizures or physical reactions.">2.3</a><br/>|<a title="Navigable - Provide ways to help users navigate, find content, and determine where they are">2.4</a><br/>|<a title="Input Modalities - Make it easier for users to operate functionality through various inputs beyond keyboard.<br/>">2.5</a><br/>|<a title="Readable - Make text content readable and understandable">3.1</a><br/>|<a title="Predictable - Make Web pages appear and operate in predictable ways">3.2</a><br/>|<a title="Input Assistance - Help users avoid and correct mistakes">3.3</a><br/>|<a title="Compatible - Maximize compatibility with current and future user agents, including assistive technologies">4.1 </a><br/>| -|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--| -|**Grids**|||||||||||||| -| - Grid|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />| -| - HierarchicalGrid|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />| -| - TreeGrid|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />| -|**Other**|||||||<span class="greenCheck" />*||||||| -| - Avatar|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Badge|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Banner|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Bottom navigation||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Button||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Button group||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Calendar|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />| -| - Card|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Carousel|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Checkbox|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*||| -| - Chip||||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Circular progress|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*|||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Combo|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />| -| - Date time editor||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|| -| - Date picker||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|| -| - Divider|<span class="greenCheck" />||||||||||<span class="greenCheck" />*||| -| - Dialog|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Drop down|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Expansion panel|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Icon||||<span class="greenCheck" />||<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Input|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|| -| - Input group|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|| -| - Label|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Linear progress|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*|||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - List|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Month picker||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />| -| - Navbar|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Navigation drawer|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Radio group|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Radio|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Select|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Slider||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Snackbar|||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Switch|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Tabs|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Time picker||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />| -| - Toast|||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Tooltip|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| - - -**Legend** - -|||| +### Success criteria that apply to UI components + +WCAG conformance is claimed against individual **success criteria**, not against the broader guidelines. These are the criteria that a UI component library can affect: + +| Criterion | Level | What it means for a component | +|---|:--:|---| +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html" target="_blank" rel="noopener noreferrer">1.1.1 Non-text Content</a> | A | Icons and images carry a text alternative. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html" target="_blank" rel="noopener noreferrer">1.3.1 Info and Relationships</a> | A | Structure conveyed visually is also conveyed in markup. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/meaningful-sequence.html" target="_blank" rel="noopener noreferrer">1.3.2 Meaningful Sequence</a> | A | Reading order matches visual order. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html" target="_blank" rel="noopener noreferrer">1.4.3 Contrast (Minimum)</a> | AA | Text meets 4.5:1 against its background. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/resize-text.html" target="_blank" rel="noopener noreferrer">1.4.4 Resize Text</a> | AA | Text scales to 200% without loss of content. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html" target="_blank" rel="noopener noreferrer">1.4.11 Non-text Contrast</a> | AA | Control boundaries and states meet 3:1. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html" target="_blank" rel="noopener noreferrer">1.4.13 Content on Hover or Focus</a> | AA | Tooltips and popovers are dismissible and persistent. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/keyboard.html" target="_blank" rel="noopener noreferrer">2.1.1 Keyboard</a> | A | All functionality is reachable by keyboard. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/no-keyboard-trap.html" target="_blank" rel="noopener noreferrer">2.1.2 No Keyboard Trap</a> | A | Focus can always move back out. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html" target="_blank" rel="noopener noreferrer">2.4.3 Focus Order</a> | A | Tab order follows a meaningful sequence. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html" target="_blank" rel="noopener noreferrer">2.4.7 Focus Visible</a> | AA | The focused control is visibly indicated. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/label-in-name.html" target="_blank" rel="noopener noreferrer">2.5.3 Label in Name</a> | A | The accessible name contains the visible label. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/on-focus.html" target="_blank" rel="noopener noreferrer">3.2.1 On Focus</a> | A | Focus alone does not trigger a change of context. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/on-input.html" target="_blank" rel="noopener noreferrer">3.2.2 On Input</a> | A | Changing a value alone does not trigger a change of context. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/labels-or-instructions.html" target="_blank" rel="noopener noreferrer">3.3.2 Labels or Instructions</a> | A | Inputs carry labels or instructions. | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html" target="_blank" rel="noopener noreferrer">4.1.2 Name, Role, Value</a> | A | Every control exposes a name, a role, and its current state. | + +## How Accessibility Is Delivered + +| Layer | Responsible for | Where it is documented | |---|---|---| -|<span class="greenCheck" />|The control/component is completely accessible in this particular area.|| -|<span class="greenCheck" />*|The control/component is accessible in this particular area after implementing certain configurations|Example 1: Guideline 2.2. For certain components additional actions and time parameters should be set; Example 2: Guideline 2.3. Use **NoopAnimationsModule**utility module to allow disabling of animations;| -|<span class="redCheck" />|The control/component is not entirely accessible unless you perform some sort of action.|| -|'white space'|this particular rule does not apply to the control|| +| **Component library** (`igniteui-angular` on Angular) | Keyboard operability, focus movement, ARIA roles and states, screen-reader announcements. | The index below, and each component topic. | +| **Theming engine** (`igniteui-theming`) | Color contrast, text sizing, chart color palettes, styling utilities for custom controls. | [Theming Accessibility](../themes/accessibility.mdx) | + +## Component Support + +This index records what each component's documentation covers today. **Not documented yet** means the component's own documentation does not describe this behavior — it is a statement about the documentation, not about the component. + +| Status | Meaning | +|---|---| +| **Documented** | The behavior is described in the component's own documentation, linked in the row. | +| **Requires configuration** | Available once the setting named in [Configuration Required](#configuration-required) is applied. | +| **Not documented yet** | The component's documentation does not yet describe this behavior. | + +<PlatformBlock for="Angular"> + +| Component | Keyboard interaction | Screen reader / ARIA | Reference | +|---|---|---|---| +| [Grid](../grid/grid.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../grid/keyboard-navigation.mdx) | +| [Hierarchical Grid](../hierarchicalgrid/hierarchical-grid.mdx) | Documented | Not documented yet | [Keyboard navigation](../hierarchicalgrid/keyboard-navigation.mdx) | +| [Tree Grid](../treegrid/tree-grid.mdx) | Documented | Not documented yet | [Keyboard navigation](../treegrid/keyboard-navigation.mdx) | +| [Avatar](../layouts/avatar.mdx#accessibility) | Documented | Documented | [Accessibility](../layouts/avatar.mdx#accessibility) | +| [Badge](../inputs/badge.mdx#accessibility) | Documented | Documented | [Accessibility](../inputs/badge.mdx#accessibility) | +| [Banner](../banner.mdx) | Not documented yet | Not documented yet | — | +| [Bottom Navigation](../tabs.mdx) | Not documented yet | Not documented yet | — | +| [Button](../inputs/button.mdx) | Not documented yet | Not documented yet | — | +| [Button Group](../inputs/button-group.mdx) | Not documented yet | Not documented yet | — | +| [Calendar](../calendar.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../calendar.mdx#keyboard-navigation) | +| [Card](../card.mdx) | Not documented yet | Not documented yet | — | +| [Carousel](../carousel.mdx#accessibility) | Documented | Documented | [Accessibility](../carousel.mdx#accessibility) | +| [Checkbox](../checkbox.mdx) | Not documented yet | Not documented yet | — | +| [Chip](../chip.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../chip.mdx#keyboard-navigation) | +| [Circular Progress](../circular-progress.mdx) | Not documented yet | Not documented yet | — | +| [Combo](../combo.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../combo.mdx#keyboard-navigation) | +| [Date Time Editor](../date-time-editor.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../date-time-editor.mdx#keyboard-navigation) | +| [Date Picker](../date-picker.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../date-picker.mdx#keyboard-navigation) | +| [Dialog](../dialog.mdx) | Not documented yet | Not documented yet | — | +| [Divider](../divider.mdx) | Not documented yet | Not documented yet | — | +| [Drop Down](../drop-down.mdx) | Not documented yet | Not documented yet | — | +| [Expansion Panel](../expansion-panel.mdx) | Not documented yet | Not documented yet | — | +| [Icon](../icon.mdx) | Not documented yet | Not documented yet | — | +| [Input Group](../input-group.mdx) | Not documented yet | Not documented yet | — | +| [Label](../label-input.mdx) | Not documented yet | Not documented yet | — | +| [Linear Progress](../linear-progress.mdx) | Not documented yet | Not documented yet | — | +| [List](../list.mdx) | Not documented yet | Not documented yet | — | +| [Month Picker](../month-picker.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../month-picker.mdx#keyboard-navigation) | +| [Navbar](../navbar.mdx) | Not documented yet | Not documented yet | — | +| [Navigation Drawer](../navdrawer.mdx) | Not documented yet | Not documented yet | — | +| [Radio](../radio-button.mdx) | Not documented yet | Not documented yet | — | +| [Select](../select.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../select.mdx#keyboard-navigation) | +| [Slider](../slider/slider.mdx) | Not documented yet | Not documented yet | — | +| [Snackbar](../snackbar.mdx) | Not documented yet | Not documented yet | — | +| [Switch](../inputs/switch.mdx) | Not documented yet | Not documented yet | — | +| [Tabs](../tabs.mdx) | Not documented yet | Not documented yet | — | +| [Time Picker](../time-picker.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../time-picker.mdx#keyboard-navigation) | +| [Toast](../toast.mdx) | Not documented yet | Not documented yet | — | +| [Tooltip](../tooltip.mdx#accessibility) | Documented | Not documented yet | [Accessibility](../tooltip.mdx#accessibility) | + +</PlatformBlock> + +<PlatformBlock for="React, WebComponents, Blazor"> + +| Component | Keyboard interaction | Screen reader / ARIA | Reference | +|---|---|---|---| +| [Grid](../grids/data-grid.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../grids/data-grid.mdx#keyboard-navigation) | +| [Hierarchical Grid](../grids/hierarchical-grid/overview.mdx) | Documented | Not documented yet | [Keyboard navigation](../grids/data-grid.mdx#keyboard-navigation) | +| [Tree Grid](../grids/tree-grid/overview.mdx) | Documented | Not documented yet | [Keyboard navigation](../grids/data-grid.mdx#keyboard-navigation) | +| [Tree](../grids/tree.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../grids/tree.mdx#keyboard-navigation) | +| [List](../grids/list.mdx) | Not documented yet | Not documented yet | — | +| [Avatar](../layouts/avatar.mdx#accessibility) | Documented | Documented | [Accessibility](../layouts/avatar.mdx#accessibility) | +| [Badge](../inputs/badge.mdx#accessibility) | Documented | Documented | [Accessibility](../inputs/badge.mdx#accessibility) | +| [Banner](../notifications/banner.mdx) | Not documented yet | Not documented yet | — | +| [Button](../inputs/button.mdx) | Not documented yet | Not documented yet | — | +| [Button Group](../inputs/button-group.mdx) | Not documented yet | Not documented yet | — | +| [Calendar](../scheduling/calendar.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../scheduling/calendar.mdx#keyboard-navigation) | +| [Card](../layouts/card.mdx) | Not documented yet | Not documented yet | — | +| [Carousel](../layouts/carousel.mdx#accessibility) | Documented | Documented | [Accessibility](../layouts/carousel.mdx#accessibility) | +| [Checkbox](../inputs/checkbox.mdx) | Not documented yet | Not documented yet | — | +| [Chip](../inputs/chip.mdx) | Not documented yet | Not documented yet | — | +| [Circular Progress](../inputs/circular-progress.mdx) | Not documented yet | Not documented yet | — | +| [Combo](../inputs/combo/overview.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../inputs/combo/overview.mdx#keyboard-navigation) | +| [Date Time Input](../inputs/date-time-input.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../inputs/date-time-input.mdx#keyboard-navigation) | +| [Date Picker](../scheduling/date-picker.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../scheduling/date-picker.mdx#keyboard-navigation) | +| [Dialog](../notifications/dialog.mdx) | Not documented yet | Not documented yet | — | +| [Divider](../layouts/divider.mdx) | Not documented yet | Not documented yet | — | +| [Dock Manager](../layouts/dock-manager.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../layouts/dock-manager.mdx#keyboard-navigation) | +| [Dropdown](../inputs/dropdown.mdx) | Not documented yet | Not documented yet | — | +| [Expansion Panel](../layouts/expansion-panel.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../layouts/expansion-panel.mdx#keyboard-navigation) | +<PlatformBlock for="WebComponents">| [File Input](../inputs/file-input.mdx#accessibility--aria-support) | Documented | Documented | [Accessibility](../inputs/file-input.mdx#accessibility--aria-support) | +</PlatformBlock>| [Icon](../layouts/icon.mdx) | Not documented yet | Not documented yet | — | +| [Icon Button](../inputs/icon-button.mdx) | Not documented yet | Not documented yet | — | +| [Input](../inputs/input.mdx) | Not documented yet | Not documented yet | — | +| [Linear Progress](../inputs/linear-progress.mdx) | Not documented yet | Not documented yet | — | +| [Navbar](../menus/navbar.mdx) | Not documented yet | Not documented yet | — | +| [Navigation Drawer](../menus/navigation-drawer.mdx) | Not documented yet | Not documented yet | — | +| [Radio](../inputs/radio.mdx) | Not documented yet | Not documented yet | — | +| [Rating](../inputs/rating.mdx) | Not documented yet | Not documented yet | — | +| [Select](../inputs/select.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../inputs/select.mdx#keyboard-navigation) | +| [Slider](../inputs/slider.mdx) | Not documented yet | Not documented yet | — | +| [Snackbar](../notifications/snackbar.mdx) | Not documented yet | Not documented yet | — | +| [Stepper](../layouts/stepper.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../layouts/stepper.mdx#keyboard-navigation) | +| [Switch](../inputs/switch.mdx) | Not documented yet | Not documented yet | — | +| [Tabs](../layouts/tabs.mdx#keyboard-navigation) | Documented | Not documented yet | [Keyboard navigation](../layouts/tabs.mdx#keyboard-navigation) | +| [Text Area](../inputs/text-area.mdx) | Not documented yet | Not documented yet | — | +| [Toast](../notifications/toast.mdx) | Not documented yet | Not documented yet | — | +| [Tooltip](../inputs/tooltip.mdx#accessibility--aria-support) | Documented | Documented | [Accessibility](../inputs/tooltip.mdx#accessibility--aria-support) | + +</PlatformBlock> <DocsAside type="warning"> -The table above is relevant only to the **Default theme** of Ignite UI for {Platform} theming library. The checklist compliance might be different when it comes to custom themes, typography and any visual changes related to animations and colors. +Rows marked **Not documented yet** are a gap in this documentation, not a known defect. If you need a conformance answer for a specific component before the next review cycle, [open an issue](#reporting-an-accessibility-issue) and ask. </DocsAside> -### Compliance Information - -- **Principle 1 - Perceivable** - Information and user interface components must be presentable to users in ways they can perceive - - Guideline 1.1 – **Text Alternatives** - Provide text alternatives for any non-text content so that it can be changed into other forms people need, such as large print, braille, speech, symbols or simpler language. - - Guideline 1.2 – **Time-based Media** - Provide alternatives for time-based media. - - Guideline 1.3 – **Adaptable** - Create content that can be presented in different ways (for example simpler layout) without losing information or structure. - - Guideline 1.4 – **Distinguishable** - Make it easier for users to see and hear content including separating foreground from background. -- **Principle 2 – Operable** - User interface components and navigation must be operable. - - Guideline 2.1 – **Keyboard Accessible** - Make all functionality available from a keyboard. - - Guideline 2.2 – **Enough Time** - Provide users enough time to read and use content. - - Guideline 2.3 – **Seizures and Physical Reactions** - Do not design content in a way that is known to cause seizures or physical reactions. - - Guideline 2.4 – **Navigable** - Provide ways to help users navigate, find content, and determine where they are. - - Guideline 2.5 – **Input Modalities** - Make it easier for users to operate functionality through various inputs beyond keyboard. -- **Principle 3 – Understandable** - Information and the operation of the user interface must be understandable. - - Guideline 3.1 – **Readable** - Make text content readable and understandable. - - Guideline 3.2 – **Predictable** - Make Web pages appear and operate in predictable ways. - - Guideline 3.3 – **Input Assistance** - Help users avoid and correct mistakes. -- **Principle 4 – Robust** - Content must be robust enough that it can be interpreted by a wide variety of user agents, including assistive technologies. - - Guideline 4.1 – **Compatible** - Maximize compatibility with current and future user agents, including assistive technologies - - -## WAI-ARIA Support -In 2014 the W3C finalized their [WAI-ARIA specification](http://www.w3.org/TR/wai-aria/) which defined how to design Web content and Web applications to be more accessible to users with disabilities. +## Configuration Required + +Some accessibility outcomes depend on how you configure the application rather than on the component alone. + +<PlatformBlock for="Angular"> + +| Concern | Criterion | What to configure | +|---|---|---| +| Animation and motion | <a href="https://www.w3.org/WAI/WCAG21/Understanding/three-flashes-or-below-threshold.html" target="_blank" rel="noopener noreferrer">2.3.1 Three Flashes or Below</a> | Provide `NoopAnimationsModule` from `@angular/platform-browser/animations` instead of `BrowserAnimationsModule` to disable Angular animations application-wide. | + +</PlatformBlock> + +<PlatformBlock for="React, WebComponents, Blazor"> + +| Concern | Criterion | What to configure | +|---|---|---| +| Animation and motion | <a href="https://www.w3.org/WAI/WCAG21/Understanding/three-flashes-or-below-threshold.html" target="_blank" rel="noopener noreferrer">2.3.1 Three Flashes or Below</a> | No configuration required. The animation player reads the operating system's `prefers-reduced-motion: reduce` setting and plays animations with a duration of `0` when it is set. | + +</PlatformBlock> + +The remaining items apply to every platform. + +| Concern | Criterion | What to configure | +|---|---|---| +| Time limits on transient messages | <a href="https://www.w3.org/WAI/WCAG21/Understanding/timing-adjustable.html" target="_blank" rel="noopener noreferrer">2.2.1 Timing Adjustable</a> | Components that auto-dismiss — such as Snackbar and Toast — expose a display-duration setting. Extend it, or disable auto-dismiss, so a user has time to read the message. | +| Color contrast after theming | <a href="https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html" target="_blank" rel="noopener noreferrer">1.4.3 Contrast (Minimum)</a> | Set foreground colors with `contrast-color()` or `adaptive-contrast()` rather than fixed values. See [Theming Accessibility](../themes/accessibility.mdx). | +| Accessible names on icon-only controls | <a href="https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html" target="_blank" rel="noopener noreferrer">4.1.2 Name, Role, Value</a> | Supply an accessible name in your own markup. A control showing only an icon has no name until you give it one. | + +## Formal Conformance Documentation + +This page is a documentation index, not a conformance claim. It records what our own documentation covers; it does not certify any component against a standard. + +For procurement, contract, or audit purposes — where a traceable, per-criterion conformance statement is required — request the current accessibility conformance report (VPAT) through your account manager or Infragistics support. Cite the product, version, and the standard the report must address (WCAG 2.1 Level AA, Section 508, or EN 301 549). + +<DocsAside type="note"> +Earlier revisions of this page carried per-component conformance matrices. Those tables asserted a level of conformance that was not backed by a traceable, per-criterion assessment, and have been removed rather than restated. The conformance report is the authoritative source for that information. +</DocsAside> + +## Reporting an Accessibility Issue + +If you find an accessibility problem in a component, report it on the <a href="{GithubLink}/issues" target="_blank" rel="noopener noreferrer">{ProductName} issue tracker</a>. + +Include the component, the assistive technology and browser you used, the expected behavior, and the WCAG success criterion you believe is affected. Accessibility reports are triaged against the criteria listed above. + +## Additional Resources + +- [Theming Accessibility](../themes/accessibility.mdx) — contrast, text scaling, and chart palettes. +- <a href="https://www.w3.org/WAI/WCAG21/quickref/" target="_blank" rel="noopener noreferrer">WCAG 2.1 Quick Reference</a> — all success criteria with techniques. +- <a href="https://www.w3.org/WAI/ARIA/apg/patterns/" target="_blank" rel="noopener noreferrer">WAI-ARIA Authoring Practices</a> — expected keyboard and ARIA behavior per interaction pattern. +- <a href="https://www.section508.gov/" target="_blank" rel="noopener noreferrer">Section 508</a> — United States federal procurement requirements. +- [Formal Conformance Documentation](#formal-conformance-documentation) — how to request a conformance report (VPAT) for procurement. + +## FAQ + +<Faq> + <FaqItem question="Is {ProductName} WCAG compliant?" indicatorPosition="end"> + Conformance is a property of a finished application, not of a component library on its own. {ProductName} targets WCAG 2.1 Level AA and documents per-component behavior in the index above, but the markup, content, and configuration you add determine the result. Use the index above to check the components you rely on, and report anything that does not behave as documented. + </FaqItem> + + <FaqItem question="Why do some components say "Not documented yet"?" indicatorPosition="end"> + That status means the component's own documentation does not yet describe the behavior. It is not a statement that the component fails a criterion - it records what the documentation covers, so you can tell the difference between a behavior that is documented and one that is not. + </FaqItem> + + <FaqItem question="Does Section 508 still have its own separate rules?" indicatorPosition="end"> + No. The Revised Section 508 Standards (published 2017, compliance date January 2018) replaced the earlier §1194.22 rules and adopt WCAG Level AA by reference, so meeting WCAG also addresses Section 508. + </FaqItem> + + <FaqItem question="Does the compliance information apply to custom themes?" indicatorPosition="end"> + Partly. Keyboard and ARIA behavior is unaffected by theming. Color contrast is not — overriding colors can move text below the required ratio. Verify custom palettes as described in Theming Accessibility. + </FaqItem> + + <FaqItem question="Where do I find the keyboard shortcuts for a component?" indicatorPosition="end"> + On the component's own topic, linked from the Reference column above. The grid family shares a dedicated keyboard navigation topic. + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/en/components/interactivity/chat.mdx b/docs/xplat/src/content/en/components/interactivity/chat.mdx index 6cdcd58dfb..ce124fbc73 100644 --- a/docs/xplat/src/content/en/components/interactivity/chat.mdx +++ b/docs/xplat/src/content/en/components/interactivity/chat.mdx @@ -234,12 +234,12 @@ const ChatExample = () => { } ``` -You can then sync messages coming from the client, by hooking to the `messageCreated` event and adding the created messages to the collection: +The `Messages` collection is updated automatically when the user sends a message. You can handle the `MessageCreated` event to persist the message or perform other side effects; do not append the event detail to `Messages` again: ```cs public void OnMessageCreated(IgbChatMessageEventArgs e) { - Messages = Messages.Append(e.Detail).ToArray(); + Console.WriteLine($"Message created: {e.Detail.Text}"); } ``` @@ -250,15 +250,57 @@ This approach makes it easy to plug the Chat into your own data source, such as ### Properties The <ApiLink type="Chat" /> component exposes several key properties that let you control its state and configuration: -| Name | Description | -| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `messages` | Array of messages (<ApiLink type="ChatMessage" />[]) displayed in the chat. You can bind to this to control which messages are shown. | -| `draftMessage` | The current unsent message, represented as an object containing `text` and optional `attachments`. This is useful for saving or restoring message drafts. | -| `options` | Chat configuration (<ApiLink type="ChatOptions" />) such as current user ID, input placeholders, accepted file types, quick reply suggestions, typing delay, and custom renderers. | -| `resourceStrings` | Localized resource strings for labels, headers, and system text. Use this property to adapt the component for different languages. | +| Name | Description | +| --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <PlatformBlock for="Blazor">`Messages`</PlatformBlock><PlatformBlock for="WebComponents,React">`messages`</PlatformBlock> | Bidirectional array of messages (<ApiLink type="ChatMessage" />[]) displayed in the chat. The Chat updates the supplied collection when the user sends a message. | +| <PlatformBlock for="Blazor">`DraftMessage`</PlatformBlock><PlatformBlock for="WebComponents,React">`draftMessage`</PlatformBlock> | The current unsent message, represented as an object containing `text` and optional `attachments`. This is useful for saving or restoring message drafts. | +| <PlatformBlock for="Blazor">`Options`</PlatformBlock><PlatformBlock for="WebComponents,React">`options`</PlatformBlock> | Chat configuration (<ApiLink type="ChatOptions" />) such as current user ID, input placeholders, accepted file types, quick reply suggestions, typing delay, and custom renderers. | +| <PlatformBlock for="Blazor">`ResourceStrings`</PlatformBlock><PlatformBlock for="WebComponents,React">`resourceStrings`</PlatformBlock> | Localized resource strings for labels, headers, and system text. Use this property to adapt the component for different languages. | These properties make it straightforward to synchronize the Chat’s UI with your application’s state and backend. +#### Bidirectional Messages Collection + +The <PlatformBlock for="WebComponents,React">`messages`</PlatformBlock><PlatformBlock for="Blazor">`Messages`</PlatformBlock> collection is bidirectional: the application provides the messages to display, and the Chat updates the original collection as the conversation continues. After the user sends a message, code holding a reference to the collection can access the newly created message. + +The <PlatformBlock for="WebComponents">`igcMessageCreated`</PlatformBlock><PlatformBlock for="React">`onMessageCreated`</PlatformBlock><PlatformBlock for="Blazor">`MessageCreated`</PlatformBlock> event is a notification for persistence or other side effects. Do not append the created message to the collection again. + +If the original collection must remain unchanged, pass the Chat a shallow copy. Existing message objects are still shared; create a new instance of each message when building the copied collection if those objects must also remain independent. + +<PlatformBlock for="WebComponents"> + + +```ts +const chatMessages = [...originalMessages]; +chat.messages = chatMessages; +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + + +```tsx +const chatMessages = [...originalMessages]; + +return <IgrChat messages={chatMessages} options={options} />; +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + + +```cs +IgbChatMessage[] chatMessages = originalMessages.ToArray(); +``` + +```razor +<IgbChat Messages="chatMessages" Options="Options"></IgbChat> +``` + +</PlatformBlock> + <PlatformBlock for="WebComponents, React"> ### Attachments diff --git a/docs/xplat/src/content/en/components/layouts/accordion.mdx b/docs/xplat/src/content/en/components/layouts/accordion.mdx index 48428e420d..853c3b0bd2 100644 --- a/docs/xplat/src/content/en/components/layouts/accordion.mdx +++ b/docs/xplat/src/content/en/components/layouts/accordion.mdx @@ -1,92 +1,167 @@ --- -title: "{Platform} Accordion | Accordion | Infragistics" -description: Accordion is used to build vertical expandable panels in accordion menu. -keywords: "{Platform} Accordion, {ProductName}, Infragistics" +title: "{Platform} Accordion Component | Layouts | Infragistics" +description: "{Platform} Accordion is a layout component for organizing expandable and collapsible content panels in a vertical container." +keywords: "{Platform} Accordion, accordion component, expandable panels, {ProductName}, Infragistics" license: MIT -mentionedTypes: ["Accordion", "Infragistics.Controls.Layouts.Implementation.ExpansionPanel"] +last_updated: "2026-07-30" +mentionedTypes: ["Accordion", "ExpansionPanel"] namespace: Infragistics.Controls +relatedComponents: ["ExpansionPanel"] llms: - description: "The {ProductName} Accordion is a GUI component for building vertical expandable panels with clickable headers and associated content sections, displayed in a single container." + description: "The {ProductName} Accordion helps developers group related content into expandable and collapsible panels inside a vertical layout." --- import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; +import Anatomy from 'igniteui-astro-components/components/mdx/Anatomy.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; +import { Image } from 'astro:assets'; +import accordionAnatomy from '@xplat-images/anatomy-frame-light/Accordion-lt.png'; +import accordionDo from '@xplat-images/accordion/accordion_do1.png'; +import accordionDo2x from '@xplat-images/accordion/accordion_do1@2x.png'; +import accordionDoNot from '@xplat-images/accordion/accordion_do_not1.png'; +import accordionDoNot2x from '@xplat-images/accordion/accordion_dont1@2x.png'; +# Accordion Component +The {ProductName} Accordion is a layout component for organizing expandable content panels in a single vertical container. -# {Platform} Accordion Overview +## Live Demo -The {ProductName} Accordion is a GUI component for building vertical expandable panels with clickable headers and associated content sections, displayed in a single container. The accordion is commonly used to reduce the need of scrolling across multiple sections of content on a single page. It offers keyboard navigation and API to control the underlying panels' expansion state. +<PlatformBlock for="Angular"> -Users are enabled to interact and navigate among a list of items, such as thumbnails or labels. Each one of those items can be toggled (expanded or collapsed) in order to reveal the containing information. Depending on the configuration, there can be a single or multiple expanded items at a time. +<Sample src="/layouts/accordion-overview" height={460} noBackground={false} showThemePicker alt="{Platform} Accordion overview example" /> -## {Platform} Accordion Example +</PlatformBlock> -The following is a basic {ProductName} Accordion example of a FAQ section. It operates as an accordion, with individually working sections. You can toggle each text block with a single click, while expanding multiple panels at the same time. This way you can read information more easily, without having to go back and forth between an automatically expanding and collapsing panel, which conceals the previously opened section every time. +<PlatformBlock for="WebComponents, React, Blazor"> -In it, you can see how to define an accordion and its expansion panels. The sample also demonstrates the two types of expansion behavior. The switch button sets the <ApiLink pkg="core" type="Accordion" member="singleExpand" label="SingleExpand" /> property to toggle between single and multiple branches to be expanded at a time. +<Sample src="/layouts/accordion/overview" height={400} noBackground={true} showThemePicker alt="{Platform} Accordion overview example" /> -<Sample src="/layouts/accordion/overview" height={460} alt="{Platform} Accordion Example" /> +</PlatformBlock> -## Getting Started with {Platform} Accordion +## Anatomy + +The accordion structure consists of an accordion container with one or more expansion panel children. + +<Anatomy + class="accordion-anatomy" + name="{Platform} Accordion anatomy" + description="The accordion anatomy labels the accordion host and child expansion panel structure." + src={accordionAnatomy.src} + alt="{Platform} Accordion anatomy: accordion host and expansion panel structure" +/> + +<span class="ig-typography__body-2" style="display: block; margin-bottom: 24px;"><strong>1. Header:</strong> displays the section title and description and can be clicked to reveal or hide the panel's content<br /> +<strong>2. Icon:</strong> indicates if the panel is open or closed. Could be placed on the left or on the right side of the header<br /> +<strong>3. Panel:</strong> the section of content linked to an accordion header</span> + +<style>{` + .accordion-anatomy { + --igd-anatomy-padding: 64px 32px; + } + + .accordion-anatomy .igd-anatomy__image { + max-width: 640px; + } +`}</style> + +<PlatformBlock for="WebComponents, React, Blazor"> + +```text +igc-accordion // host - manages a set of expansion panels +└─ igc-expansion-panel // child panel + ├─ [slot="title"] // panel header title + ├─ [slot="subtitle"] // optional header subtitle + ├─ [slot="indicator"] // custom collapsed/default indicator + ├─ [slot="indicator-expanded"] // optional custom expanded-state indicator + └─ default slot // expandable panel content +``` -<PlatformBlock for="WebComponents"> +</PlatformBlock> -First, you need to install the {ProductName} by running the following command: +<PlatformBlock for="Angular"> -```cmd -npm install {PackageWebComponents} +```text +igx-accordion // host - manages a set of expansion panels +└─ igx-expansion-panel // child panel + ├─ igx-expansion-panel-header // panel header container + │ ├─ igx-expansion-panel-title // panel header title + │ ├─ igx-expansion-panel-description // optional header description + │ └─ igx-expansion-panel-icon // optional custom expand/collapse icon + └─ igx-expansion-panel-body // expandable panel content ``` -Before using the <ApiLink pkg="core" type="Accordion" />, you need to register it as follows: +</PlatformBlock> -```ts -import { defineComponents, IgcAccordionComponent } from 'igniteui-webcomponents'; +## Getting Started -defineComponents(IgcAccordionComponent); -``` +<PlatformBlock for="Angular"> -For a complete introduction to the {ProductName}, read the [**Getting Started**](../general-getting-started.mdx) topic. +Use the accordion with the {ProductName} version installed in your Angular application. Complete the shared [Getting Started](../general/getting-started.mdx) topic before importing the standalone accordion directives. </PlatformBlock> -<PlatformBlock for="React"> +<PlatformBlock for="WebComponents, React, Blazor"> + +Use the accordion with the {ProductName} version installed in your application. Complete the shared [Getting Started](../general-getting-started.mdx) topic before adding framework-specific imports or registration. -First, you need to the install the corresponding {ProductName} npm package by running the following command: +</PlatformBlock> + +<PlatformBlock for="Angular"> + +Import the standalone accordion directives before you use the component. -```cmd -npm install igniteui-react +```ts +import { Component } from '@angular/core'; +import { IGX_ACCORDION_DIRECTIVES } from 'igniteui-angular/accordion'; + +@Component({ + selector: 'app-accordion', + imports: [IGX_ACCORDION_DIRECTIVES], + templateUrl: './accordion.component.html', +}) +export class AccordionComponent {} ``` -You will then need to import the <ApiLink pkg="core" type="Accordion" /> and the <ApiLink pkg="core" type="ExpansionPanel" /> and its necessary CSS, like so: +</PlatformBlock> + +<PlatformBlock for="WebComponents"> -```tsx +Register the accordion and expansion panel components before you use them. + +```ts import { - IgrAccordion, - IgrExpansionPanel, -} from "igniteui-react"; -import "igniteui-webcomponents/themes/light/bootstrap.css"; + defineComponents, + IgcAccordionComponent, + IgcExpansionPanelComponent, +} from 'igniteui-webcomponents'; +defineComponents(IgcAccordionComponent, IgcExpansionPanelComponent); ``` </PlatformBlock> -Before using the <ApiLink pkg="core" type="Accordion" />, you need to register it as follows: +<PlatformBlock for="React"> -<PlatformBlock for="Blazor"> +Import the React wrappers and the theme stylesheet before you render the accordion. -```csharp -// in Program.cs file - -builder.Services.AddIgniteUIBlazor(typeof(IgbAccordionModule)); +```tsx +import { IgrAccordion, IgrExpansionPanel } from 'igniteui-react'; +import 'igniteui-webcomponents/themes/light/bootstrap.css'; ``` </PlatformBlock> <PlatformBlock for="Blazor"> -You will also need to link an additional CSS file to apply the styling to the <ApiLink pkg="core" type="Accordion" /> component. The following needs to be placed in the **wwwroot/index.html** file in a **Blazor Web Assembly** project or the **Pages/_Host.cshtml** file in a **Blazor Server** project: +Register the accordion module in `Program.cs` and add the theme stylesheet to your host page. + +```csharp +builder.Services.AddIgniteUIBlazor(typeof(IgbAccordionModule)); +``` ```razor <link href="_content/IgniteUI.Blazor/themes/light/bootstrap.css" rel="stylesheet" /> @@ -94,129 +169,722 @@ You will also need to link an additional CSS file to apply the styling to the <A </PlatformBlock> -Now you can start with a basic configuration of the <ApiLink pkg="core" type="Accordion" /> and its panels. - ## Usage -Each section in the {Platform} Accordion Component is defined using an {Platform} Expansion Panel. -Panels provide <ApiLink pkg="core" type="ExpansionPanel" member="disabled" label="Disabled" /> and <ApiLink pkg="core" type="ExpansionPanel" member="open" label="Open" /> properties, which give you the ability to configure the states of the panel as per your requirement. +Build the accordion by placing one or more <ApiLink pkg="core" type="ExpansionPanel" /> components inside an <ApiLink pkg="core" type="Accordion" /> container. + +### Single Expansion + +<PlatformBlock for="Angular"> + +Set <ApiLink type="Accordion" member="singleBranchExpand" label="singleBranchExpand" /> to switch between one-open-panel behavior and multiple-open-panel behavior. + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +Set <ApiLink pkg="core" type="Accordion" member="singleExpand" label="SingleExpand" /> to switch between one-open-panel behavior and multiple-open-panel behavior. + +</PlatformBlock> + +<PlatformBlock for="Angular"> -### Declaring an Accordion +```html +<igx-accordion [singleBranchExpand]="true"> + <igx-expansion-panel> + <igx-expansion-panel-header> + <igx-expansion-panel-title>Title Panel 1</igx-expansion-panel-title> + </igx-expansion-panel-header> + <igx-expansion-panel-body> + <p>Content Panel 1</p> + </igx-expansion-panel-body> + </igx-expansion-panel> + <igx-expansion-panel> + <igx-expansion-panel-header> + <igx-expansion-panel-title>Title Panel 2</igx-expansion-panel-title> + </igx-expansion-panel-header> + <igx-expansion-panel-body> + <p>Content Panel 2</p> + </igx-expansion-panel-body> + </igx-expansion-panel> +</igx-accordion> +``` -The accordion wraps all expansion panels declared inside it. +</PlatformBlock> <PlatformBlock for="WebComponents"> ```html -<igc-accordion id="accordion" single-expand="true"> - <igc-expansion-panel indicator-position="end"> - <span slot="title">Title Panel 1</span> - <p>Content Panel 1</p> - </igc-expansion-panel> - <igc-expansion-panel indicator-position="end"> - <span slot="title">Title Panel 2</span> - <p>Content Panel 2</p> - </igc-expansion-panel> +<igc-accordion single-expand="true"> + <igc-expansion-panel> + <span slot="title">Title Panel 1</span> + <p>Content Panel 1</p> + </igc-expansion-panel> + <igc-expansion-panel> + <span slot="title">Title Panel 2</span> + <p>Content Panel 2</p> + </igc-expansion-panel> </igc-accordion> ``` </PlatformBlock> +<PlatformBlock for="React"> + +```tsx +<IgrAccordion singleExpand={true}> + <IgrExpansionPanel> + <span slot="title">Title Panel 1</span> + <p>Content Panel 1</p> + </IgrExpansionPanel> + <IgrExpansionPanel> + <span slot="title">Title Panel 2</span> + <p>Content Panel 2</p> + </IgrExpansionPanel> +</IgrAccordion> +``` + +</PlatformBlock> + <PlatformBlock for="Blazor"> ```razor <IgbAccordion SingleExpand=true> - <IgbExpansionPanel> + <IgbExpansionPanel> + <span slot="title">Title Panel 1</span> + <p>Content Panel 1</p> + </IgbExpansionPanel> + <IgbExpansionPanel> + <span slot="title">Title Panel 2</span> + <p>Content Panel 2</p> + </IgbExpansionPanel> +</IgbAccordion> +``` + +</PlatformBlock> + +### Programmatic Expansion + +<PlatformBlock for="Angular"> + +Use <ApiLink type="Accordion" member="collapseAll" label="collapseAll()" /> and <ApiLink type="Accordion" member="expandAll" label="expandAll()" /> to collapse or expand the accordion panels programmatically. + +<DocsAside type="info"> +Calling <ApiLink type="Accordion" member="expandAll" label="expandAll()" /> expands only the last enabled panel when <ApiLink type="Accordion" member="singleBranchExpand" label="singleBranchExpand" /> is `true`. +</DocsAside> + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +Use <ApiLink pkg="core" type="Accordion" member="hideAll" label="HideAll" /> and <ApiLink pkg="core" type="Accordion" member="showAll" label="ShowAll" /> to collapse or expand all available panels programmatically. + +<DocsAside type="info"> +Calling <ApiLink pkg="core" type="Accordion" member="showAll" label="ShowAll" /> expands all panels, even when <ApiLink pkg="core" type="Accordion" member="singleExpand" label="SingleExpand" /> is `true`. +</DocsAside> + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +```html +<button type="button" (click)="accordion.expandAll()">Show All</button> +<button type="button" (click)="accordion.collapseAll()">Hide All</button> + +<igx-accordion #accordion> + <igx-expansion-panel> + <igx-expansion-panel-header> + <igx-expansion-panel-title>Title Panel 1</igx-expansion-panel-title> + </igx-expansion-panel-header> + <igx-expansion-panel-body> + <p>Content Panel 1</p> + </igx-expansion-panel-body> + </igx-expansion-panel> + <igx-expansion-panel> + <igx-expansion-panel-header> + <igx-expansion-panel-title>Title Panel 2</igx-expansion-panel-title> + </igx-expansion-panel-header> + <igx-expansion-panel-body> + <p>Content Panel 2</p> + </igx-expansion-panel-body> + </igx-expansion-panel> +</igx-accordion> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<button id="show-all">Show All</button> +<button id="hide-all">Hide All</button> + +<igc-accordion id="accordion"> + <igc-expansion-panel> + <span slot="title">Title Panel 1</span> + <p>Content Panel 1</p> + </igc-expansion-panel> + <igc-expansion-panel> + <span slot="title">Title Panel 2</span> + <p>Content Panel 2</p> + </igc-expansion-panel> +</igc-accordion> +``` + +```ts +const accordion = document.getElementById('accordion') as IgcAccordionComponent; + +document.getElementById('show-all').addEventListener('click', () => accordion.showAll()); +document.getElementById('hide-all').addEventListener('click', () => accordion.hideAll()); +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +const accordionRef = useRef<IgrAccordion>(null); + +return ( + <> + <IgrButton onClick={() => accordionRef.current?.showAll()}>Show All</IgrButton> + <IgrButton onClick={() => accordionRef.current?.hideAll()}>Hide All</IgrButton> + + <IgrAccordion ref={accordionRef}> + <IgrExpansionPanel> <span slot="title">Title Panel 1</span> <p>Content Panel 1</p> - </IgbExpansionPanel> - <IgbExpansionPanel> + </IgrExpansionPanel> + <IgrExpansionPanel> <span slot="title">Title Panel 2</span> <p>Content Panel 2</p> - </IgbExpansionPanel> -</IgbAccordion> + </IgrExpansionPanel> + </IgrAccordion> + </> +); ``` </PlatformBlock> -<PlatformBlock for="React"> +<PlatformBlock for="Blazor"> -```tsx -<IgrAccordion singleExpand={true}> - <IgrExpansionPanel> +```razor +<IgbButton @onclick="ShowAll">Show All</IgbButton> +<IgbButton @onclick="HideAll">Hide All</IgbButton> + +<IgbAccordion @ref="accordion"> + <IgbExpansionPanel> <span slot="title">Title Panel 1</span> <p>Content Panel 1</p> - </IgrExpansionPanel> - <IgrExpansionPanel> + </IgbExpansionPanel> + <IgbExpansionPanel> <span slot="title">Title Panel 2</span> <p>Content Panel 2</p> + </IgbExpansionPanel> +</IgbAccordion> + +@code { + private IgbAccordion accordion; + + private async Task ShowAll() => await accordion.ShowAllAsync(); + + private async Task HideAll() => await accordion.HideAllAsync(); +} +``` + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +<Sample src="/layouts/accordion-programmatic-expansion" height={580} noBackground={false} showThemePicker alt="{Platform} Accordion programmatic expansion example" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +<Sample src="/layouts/accordion/programmatic-expansion" height={560} noBackground={true} showThemePicker alt="{Platform} Accordion programmatic expansion example" /> + +</PlatformBlock> + +### Customize Panel Content + +<PlatformBlock for="Angular"> + +Customize panel headers with title and description elements, and place expandable content inside the panel body. + +```html +<igx-accordion> + <igx-expansion-panel> + <igx-expansion-panel-header> + <igx-expansion-panel-title>Billing</igx-expansion-panel-title> + <igx-expansion-panel-description>Payment and invoice settings</igx-expansion-panel-description> + </igx-expansion-panel-header> + <igx-expansion-panel-body> + <p>Update payment methods, billing contacts, and invoice delivery options.</p> + </igx-expansion-panel-body> + </igx-expansion-panel> +</igx-accordion> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +Customize the panel headers and content through the underlying <ApiLink pkg="core" type="ExpansionPanel" /> slots. + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-accordion> + <igc-expansion-panel open> + <span slot="title">Billing</span> + <span slot="subtitle">Payment and invoice settings</span> + <p>Update payment methods, billing contacts, and invoice delivery options.</p> + </igc-expansion-panel> +</igc-accordion> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrAccordion> + <IgrExpansionPanel open> + <span slot="title">Billing</span> + <span slot="subtitle">Payment and invoice settings</span> + <p>Update payment methods, billing contacts, and invoice delivery options.</p> </IgrExpansionPanel> </IgrAccordion> ``` </PlatformBlock> +<PlatformBlock for="Blazor"> + +```razor +<IgbAccordion> + <IgbExpansionPanel Open> + <span slot="title">Billing</span> + <span slot="subtitle">Payment and invoice settings</span> + <p>Update payment methods, billing contacts, and invoice delivery options.</p> + </IgbExpansionPanel> +</IgbAccordion> +``` + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +<Sample src="/layouts/accordion-customization" height={640} noBackground={false} showThemePicker alt="{Platform} Accordion customization example" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +<Sample src="/layouts/accordion/customization" height={560} noBackground={true} showThemePicker alt="{Platform} Accordion customization example" /> + +</PlatformBlock> + +### Nest Accordions + +Nest an accordion inside an expansion panel when you need a second level of grouped disclosure. + +<PlatformBlock for="Angular"> + +```html +<igx-accordion> + <igx-expansion-panel> + <igx-expansion-panel-header> + <igx-expansion-panel-title>Account Settings</igx-expansion-panel-title> + </igx-expansion-panel-header> + <igx-expansion-panel-body> + <igx-accordion> + <igx-expansion-panel> + <igx-expansion-panel-header> + <igx-expansion-panel-title>Notifications</igx-expansion-panel-title> + </igx-expansion-panel-header> + <igx-expansion-panel-body> + <p>Configure email and product notification preferences.</p> + </igx-expansion-panel-body> + </igx-expansion-panel> + </igx-accordion> + </igx-expansion-panel-body> + </igx-expansion-panel> +</igx-accordion> +``` + +</PlatformBlock> + <PlatformBlock for="WebComponents"> -Using the <ApiLink pkg="core" type="Accordion" member="panels" label="Panels" /> accessor you can get a reference to the collection containing all expansion panels children of the <ApiLink pkg="core" type="Accordion" />. +```html +<igc-accordion> + <igc-expansion-panel open> + <span slot="title">Workspace Settings</span> + <igc-accordion> + <igc-expansion-panel> + <span slot="title">Notifications</span> + <p>Configure email and product notification preferences.</p> + </igc-expansion-panel> + </igc-accordion> + </igc-expansion-panel> +</igc-accordion> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrAccordion> + <IgrExpansionPanel open> + <span slot="title">Workspace Settings</span> + <IgrAccordion> + <IgrExpansionPanel> + <span slot="title">Notifications</span> + <p>Configure email and product notification preferences.</p> + </IgrExpansionPanel> + </IgrAccordion> + </IgrExpansionPanel> +</IgrAccordion> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbAccordion> + <IgbExpansionPanel Open> + <span slot="title">Workspace Settings</span> + <IgbAccordion> + <IgbExpansionPanel> + <span slot="title">Notifications</span> + <p>Configure email and product notification preferences.</p> + </IgbExpansionPanel> + </IgbAccordion> + </IgbExpansionPanel> +</IgbAccordion> +``` + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +<Sample src="/layouts/accordion-nested-scenario" height={780} noBackground={false} showThemePicker alt="{Platform} nested accordion example" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +<Sample src="/layouts/accordion/nested-scenario" height={670} noBackground={true} showThemePicker alt="{Platform} nested accordion example" /> + +</PlatformBlock> + +### Do/Don't + +**When to use:** Use the accordion when you need to organize secondary content, FAQ entries, settings groups, or other related vertical sections that users expand on demand. Keep panel titles short and descriptive, and enable single-expansion behavior when users should focus on one section at a time. + +<PlatformBlock for="Angular"> + +**When not to use:** Use the [Expansion Panel](../expansion-panel.mdx) when you need a single standalone expandable section instead of a coordinated container that manages multiple panels together. Do not use an accordion to hide essential primary content or to group unrelated sections. + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +**When not to use:** Use the [Expansion Panel](./expansion-panel.mdx) when you need a single standalone expandable section instead of a coordinated container that manages multiple panels together. Do not use an accordion to hide essential primary content or to group unrelated sections. + +</PlatformBlock> + +<div class="table-responsive"> + <table class="table" style="width: 100%; table-layout: fixed; border-collapse: collapse; border: 1px solid #d3d3d3; margin-bottom: 24px;"> + <thead> + <tr> + <th style="width: 50%; background-color: #d3d3d3; text-align: left; padding: 16px 20px; font-size: 18px; font-weight: 500;">Do</th> + <th style="width: 50%; background-color: #d3d3d3; text-align: left; padding: 16px 20px; font-size: 18px; font-weight: 500;">Don't</th> + </tr> + </thead> + <tbody> + <tr> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={accordionDo} srcset={`${accordionDo.src} 1x, ${accordionDo2x.src} 2x`} alt="{Platform} Accordion do guidance" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={accordionDoNot} srcset={`${accordionDoNot.src} 1x, ${accordionDoNot2x.src} 2x`} alt="{Platform} Accordion don't guidance" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + </tr> + </tbody> + </table> +</div> + +## Properties + +The accordion exposes container-level controls; panel-specific state is configured on each <ApiLink pkg="core" type="ExpansionPanel" />. + +<PlatformBlock for="Angular"> + +| Name | Type | Default | Description | +| -- | -- | -- | -- | +| <ApiLink type="Accordion" member="singleBranchExpand" label="singleBranchExpand" /> | `boolean` | `false` | Controls whether one or multiple panels can stay expanded at the same time. | +| <ApiLink type="Accordion" member="panels" label="panels" /> | `QueryList<IgxExpansionPanelComponent>` | n/a | Returns the collection of child expansion panels in the accordion. | + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +| Name | Type | Default | Description | +| -- | -- | -- | -- | +| <ApiLink pkg="core" type="Accordion" member="singleExpand" label="SingleExpand" /> | `boolean` | `false` | Controls whether one or multiple panels can stay expanded at the same time. | +| <ApiLink pkg="core" type="Accordion" member="panels" label="Panels" /> | <ApiLink pkg="core" type="ExpansionPanel" label="ExpansionPanel[]" /> | n/a | Returns the collection of child expansion panels in the accordion. | -```typescript -private accordion: IgcAccordionComponent; -private panels: IgcExpansionPanelComponent[]; +</PlatformBlock> + +## Methods + +Use the accordion methods when you need to change panel state from your code. + +<PlatformBlock for="Angular"> + +| Name | Description | +| -- | -- | +| <ApiLink type="Accordion" member="expandAll" label="expandAll" /> | Expands the available panels. | +| <ApiLink type="Accordion" member="collapseAll" label="collapseAll" /> | Collapses the available panels. | + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +| Name | Description | +| -- | -- | +| <ApiLink pkg="core" type="Accordion" member="showAll" label="ShowAll" /> | Expands all available panels. | +| <ApiLink pkg="core" type="Accordion" member="hideAll" label="HideAll" /> | Collapses the available panels. | + +</PlatformBlock> + +## Styling + +Style the {Platform} accordion with CSS parts and Ignite UI theme variables. + +<PlatformBlock for="Angular"> + +<Sample src="/layouts/accordion-styling" height={440} noBackground={true} alt="{Platform} Accordion styling example" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +<Sample src="/layouts/accordion/styling" height={390} noBackground={true} alt="{Platform} Accordion styling example" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +Style the accordion by targeting the parts exposed by its child <ApiLink pkg="core" type="ExpansionPanel" /> components. + +### Styling Variables + +Use {ProductName} theme CSS variables as values when styling the expansion panel parts. + +| Variable | What it changes | +| -- | -- | +| `--ig-secondary-900` | Supplies the dark background color used by the panel and header in the example below. | +| `--ig-secondary-900-contrast` | Supplies a readable foreground color for content on `--ig-secondary-900`. | +| `--ig-warn-500` | Supplies the accent color used by the indicator, title, and subtitle in the example below. | + +```css +igc-expansion-panel { + background-color: var(--ig-secondary-900); + color: var(--ig-secondary-900-contrast); +} + +igc-expansion-panel::part(header) { + background-color: var(--ig-secondary-900); +} -constructor() { - this.accordion = document.getElementById("accordion") as IgcAccordionComponent; - this.panels = this.accordion.panels; +igc-expansion-panel::part(indicator), +igc-expansion-panel::part(title), +igc-expansion-panel::part(subtitle) { + color: var(--ig-warn-500); } ``` +### CSS Parts + +| Part | What it changes | +| -- | -- | +| `header` | The container for the expansion indicator, title, and subtitle. | +| `title` | The title container. | +| `subtitle` | The subtitle container. | +| `indicator` | The indicator container. | +| `content` | The expansion panel content wrapper. | + </PlatformBlock> -As demonstrated above, the <ApiLink pkg="core" type="Accordion" member="singleExpand" label="SingleExpand" /> property gives you the ability to set whether single or multiple panels can be expanded at a time. +<PlatformBlock for="Angular"> -By using the <ApiLink pkg="core" type="Accordion" member="hideAll" label="HideAll" /> and <ApiLink pkg="core" type="Accordion" member="showAll" label="ShowAll" /> methods you can respectively collapse and expand all <ApiLink pkg="core" type="ExpansionPanel" />s of the <ApiLink pkg="core" type="Accordion" /> programmatically. +### Sass Theming -<DocsAside type="info"> -If <ApiLink pkg="core" type="Accordion" member="singleExpand" label="SingleExpand" /> property is set to **true** calling <ApiLink pkg="core" type="Accordion" member="showAll" label="ShowAll" /> method would expand only the focused panel. -</DocsAside> +Use the <ApiLink kind="sass" module="themes" type="function-expansion-panel-theme" label="expansion-panel-theme" code={true} /> function to create a custom expansion panel theme, then include the generated tokens in the component stylesheet. + +```scss +@use "igniteui-angular/theming" as *; + +$custom-panel-theme: expansion-panel-theme( + $header-background: #011627, + $body-background: #f0ece7, + $expanded-margin: 10px +); + +:host { + @include tokens($custom-panel-theme); +} +``` + +### Styling Variables -### {Platform} Accordion Customization Example +| Variable | What it changes | +| -- | -- | +| `$header-background` | The panel header background color. | +| `$header-focus-background` | The panel header background color when focused. | +| `$header-title-color` | The panel header title text color. | +| `$header-description-color` | The panel header description text color. | +| `$header-icon-color` | The panel header icon color. | +| `$body-background` | The panel body background color. | +| `$body-color` | The panel body text color. | +| `$expanded-margin` | The margin applied to expanded panels when they are placed inside an accordion. | +| `$border-radius` | The expansion panel border radius. | -With the {Platform} Accordion, you can customize the header and content panel's appearance. +</PlatformBlock> + +### Styling with Tailwind + +Use Tailwind utility classes with CSS part selectors when you want to keep the styling close to the component markup. + +<PlatformBlock for="Angular"> + +<Sample src="/layouts/accordion-tailwind-styling" height={440} noBackground={true} alt="{Platform} Accordion Tailwind styling example" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +<Sample src="/layouts/accordion/tailwind-styling" height={390} noBackground={true} alt="{Platform} Accordion Tailwind styling example" /> + +</PlatformBlock> + +## Accessibility + +The accordion supports keyboard interaction for moving focus between panels and changing their expanded state. + +### Keyboard Interaction + +<PlatformBlock for="Angular"> + +Use the keyboard shortcuts below to move through the accordion and open or close panels. + +| Key | Action | +| -- | -- | +| <kbd>Down Arrow</kbd> | Moves focus to the panel below. | +| <kbd>Up Arrow</kbd> | Moves focus to the panel above. | +| <kbd>Alt</kbd> + <kbd>Down Arrow</kbd> | Opens the focused panel. | +| <kbd>Alt</kbd> + <kbd>Up Arrow</kbd> | Closes the focused panel. | +| <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>Down Arrow</kbd> | Opens all enabled panels. If <ApiLink type="Accordion" member="singleBranchExpand" label="singleBranchExpand" /> is `true`, opens the last enabled panel. | +| <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>Up Arrow</kbd> | Closes all enabled panels. | +| <kbd>Home</kbd> | Moves focus to the first enabled panel. | +| <kbd>End</kbd> | Moves focus to the last enabled panel. | + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> -The sample below demonstrates how elaborate filtering options can be implemented using the built-in slots of the <ApiLink pkg="core" type="ExpansionPanel" />. +Use the keyboard shortcuts below to move through the accordion and open or close panels. -<Sample src="/layouts/accordion/customization" height={550} alt="{Platform} Accordion Customization Example" /> +| Key | Action | +| -- | -- | +| <kbd>Down Arrow</kbd> | Moves focus to the panel below. | +| <kbd>Up Arrow</kbd> | Moves focus to the panel above. | +| <kbd>Alt</kbd> + <kbd>Down Arrow</kbd> | Opens the focused panel. | +| <kbd>Alt</kbd> + <kbd>Up Arrow</kbd> | Closes the focused panel. | +| <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>Down Arrow</kbd> | Opens all enabled panels. If <ApiLink pkg="core" type="Accordion" member="singleExpand" label="SingleExpand" /> is `true`, opens only the focused panel. | +| <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>Up Arrow</kbd> | Closes all enabled panels. | +| <kbd>Home</kbd> | Moves focus to the first enabled panel. | +| <kbd>End</kbd> | Moves focus to the last enabled panel. | -### Nested {Platform} Accordions Scenario +</PlatformBlock> -In the following {Platform} Accordion example is created a complex FAQ section in order to illustrate how you can go about this common application scenario. In the sample nested <ApiLink pkg="core" type="Accordion" /> is achieved by adding an accordion inside an expansion panel. +### Screen Readers / ARIA -<Sample src="/layouts/accordion/nested-scenario" height={550} alt="{Platform} Accordion Nested Example" /> +The accordion's accessibility semantics are provided through its child expansion panels and their headers. -## Keyboard Navigation +- Each panel header exposes `role="button"`, `aria-expanded`, and `aria-controls`. +- Each panel body exposes `role="region"` and a label through `aria-labelledby` or `aria-label`. +- Use clear title text for each panel so assistive technologies can announce a meaningful label. +- Keep interactive content inside panel bodies in a logical tab order. -Keyboard navigation in the {Platform} Accordion provides a rich variety of keyboard interactions to the end-user. This functionality is enabled by default and allows end-users to easily navigate through the panels. +### Accessibility Compliance -The Accordion navigation is compliant with W3C accessibility standards and convenient to use. +Infragistics documents {ProductName} accessibility support for Section 508 and WCAG 2.1 guideline areas in the [Accessibility Compliance](../interactivity/accessibility-compliance.mdx) topic. The accordion's compliance evidence comes from the child <ApiLink pkg="core" type="ExpansionPanel" /> components that provide the interactive headers and regions. -**Key Combinations** -- <kbd>↓</kbd> - moves the focus to the panel below -- <kbd>↑</kbd> - moves the focus to the panel above -- <kbd>ALT</kbd> + <kbd>↓</kbd> - opens the focused panel in the accordion -- <kbd>ALT</kbd> + <kbd>↑</kbd> - closes the focused panel in the accordion -- <kbd>SHIFT</kbd> + <kbd>ALT</kbd> + <kbd>↓</kbd> - opens all enabled panels (if singleExpand is set to true opens the focused panel) -- <kbd>SHIFT</kbd> + <kbd>ALT</kbd> + <kbd>↑</kbd> - closes all enabled panels -- <kbd>HOME</kbd> - navigates to the FIRST enabled panel in the accordion -- <kbd>END</kbd> - navigates to the LAST enabled panel in the accordion +| Criterion | How the component complies | +| -- | -- | +| [2.1.1 Keyboard](https://www.w3.org/WAI/WCAG21/Understanding/keyboard) | The accordion supports keyboard commands for moving focus and opening or closing panels. | +| [2.4.3 Focus Order](https://www.w3.org/WAI/WCAG21/Understanding/focus-order) | Focus moves through enabled panels in sequence, with shortcuts for jumping to the first and last panel. | -<igc-divider></igc-divider> +Your responsibilities: +- Provide panel titles that describe the content behind each disclosure area. +- Preserve a logical focus order in the surrounding page layout. +- Validate any custom styling against your application's contrast and focus-indicator requirements. ## API References + <ApiLink pkg="core" type="Accordion" /> <ApiLink pkg="core" type="ExpansionPanel" /> + +## Dependencies + +The accordion depends on <ApiLink pkg="core" type="ExpansionPanel" /> for its visible sections. + +<PlatformBlock for="React, Blazor"> + +The accordion also depends on the shared theme stylesheet for its default appearance. + +</PlatformBlock> + ## Additional Resources +Use these resources to continue with {ProductName} Accordion support, source, and related layout guidance. + - [{ProductName} **Forums**]({ForumsLink}) - [{ProductName} **GitHub**]({GithubLink}) + +## Related Components + +<PlatformBlock for="Angular"> + +- [Expansion Panel](../expansion-panel.mdx) - The collapsible section the accordion is built from. See it for configuring individual panels. + +</PlatformBlock> + +<PlatformBlock for="WebComponents, React, Blazor"> + +- [Expansion Panel](./expansion-panel.mdx) - The collapsible section the accordion is built from. See it for configuring individual panels. + +</PlatformBlock> + +## FAQ + +<Faq> + <FaqItem question="Should multiple accordion panels be open at the same time?" indicatorPosition="end"> + Allow multiple panels to stay open when users need to compare or cross-reference their content. Use single-expansion behavior when the workflow is clearer with one active section at a time. + </FaqItem> + <FaqItem question="When should I avoid using an accordion?" indicatorPosition="end"> + Avoid using an accordion for essential, long, or comparison-heavy content that users need to read at once. Use clear headings, a separate page, or another layout when hiding the content would make it harder to find or compare. + </FaqItem> + <FaqItem question="How should I write accordion headers?" indicatorPosition="end"> + Use short, descriptive headers that clearly identify the content revealed by each panel. Users should be able to scan the headers and decide which section to open. + </FaqItem> + <FaqItem question="Can an accordion header contain other buttons or links?" indicatorPosition="end"> + Avoid placing other interactive controls inside an accordion header. Keep secondary actions outside the header so the panel trigger remains clear and does not contain nested interactive elements. + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/en/components/layouts/avatar.mdx b/docs/xplat/src/content/en/components/layouts/avatar.mdx index e605e9839d..34f9d30cd0 100644 --- a/docs/xplat/src/content/en/components/layouts/avatar.mdx +++ b/docs/xplat/src/content/en/components/layouts/avatar.mdx @@ -32,13 +32,13 @@ Use the avatar to provide a compact visual identity in lists, cards, profile men <PlatformBlock for="WebComponents, React, Blazor"> -<Sample spacing="sm" height={300} src="/layouts/avatar/overview" alt="{Platform} Avatar overview example" /> +<Sample spacing="sm" showThemePicker height={300} src="/layouts/avatar/overview" alt="{Platform} Avatar overview example" /> </PlatformBlock> <PlatformBlock for="Angular"> -<Sample spacing="sm" height={300} src="/layouts/avatar-overview" alt="{Platform} Avatar overview example" /> +<Sample spacing="sm" showThemePicker height={300} src="/layouts/avatar-overview" alt="{Platform} Avatar overview example" /> </PlatformBlock> @@ -224,13 +224,13 @@ Set only the content source you intend to show. The Angular avatar renders `src` <PlatformBlock for="WebComponents, React, Blazor"> -<Sample position="center" spacing="sm" height={300} src="/layouts/avatar/variants" alt="{Platform} Avatar variants example" /> +<Sample position="center" spacing="sm" showThemePicker height={300} src="/layouts/avatar/variants" alt="{Platform} Avatar variants example" /> </PlatformBlock> <PlatformBlock for="Angular"> -<Sample position="center" spacing="sm" height={300} src="/layouts/avatar-variants" alt="{Platform} Avatar variants example" /> +<Sample position="center" spacing="sm" showThemePicker height={300} src="/layouts/avatar-variants" alt="{Platform} Avatar variants example" /> </PlatformBlock> @@ -272,13 +272,13 @@ Set <ApiLink pkg="core" type="Avatar" member="shape" label="Shape" /> to `square <PlatformBlock for="WebComponents, React, Blazor"> -<Sample position="center" spacing="sm" height={300} src="/layouts/avatar/shape" alt="{Platform} Avatar shape example" /> +<Sample position="center" spacing="sm" showThemePicker height={300} src="/layouts/avatar/shape" alt="{Platform} Avatar shape example" /> </PlatformBlock> <PlatformBlock for="Angular"> -<Sample position="center" spacing="sm" height={300} src="/layouts/avatar-shape" alt="{Platform} Avatar shape example" /> +<Sample position="center" spacing="sm" showThemePicker height={300} src="/layouts/avatar-shape" alt="{Platform} Avatar shape example" /> </PlatformBlock> @@ -306,13 +306,13 @@ igc-avatar { <PlatformBlock for="WebComponents, React, Blazor"> -<Sample position="center" spacing="sm" height={300} src="/layouts/avatar/size" alt="{Platform} Avatar size example" /> +<Sample position="center" spacing="sm" showThemePicker height={300} src="/layouts/avatar/size" alt="{Platform} Avatar size example" /> </PlatformBlock> <PlatformBlock for="Angular"> -<Sample position="center" spacing="sm" height={300} src="/layouts/avatar-size" alt="{Platform} Avatar size example" /> +<Sample position="center" spacing="sm" showThemePicker height={300} src="/layouts/avatar-size" alt="{Platform} Avatar size example" /> </PlatformBlock> diff --git a/docs/xplat/src/content/en/components/layouts/virtual-scroll.mdx b/docs/xplat/src/content/en/components/layouts/virtual-scroll.mdx new file mode 100644 index 0000000000..8ffc42f3d3 --- /dev/null +++ b/docs/xplat/src/content/en/components/layouts/virtual-scroll.mdx @@ -0,0 +1,709 @@ +--- +title: "Virtual Scroll" +description: "The Virtual Scroll is a component that renders only the items in its viewport plus a small buffer, so large lists scroll smoothly." +keywords: "{Platform} Virtual Scroll, virtualization, virtual list, large lists, infinite scroll, remote data, {ProductName}" +last_updated: "2026-09-17" +license: MIT +mentionedTypes: ["VirtualScroll"] +relatedComponents: ["List", "Card"] +llms: + description: "The {ProductName} Virtual Scroll is a component that renders large lists by keeping only the items in its viewport, plus a configurable buffer, in the DOM." +--- +import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; +import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; +import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; +import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; + +# Virtual Scroll Component + +The {ProductName} Virtual Scroll is a component that renders large lists by keeping only the items in its viewport, plus a configurable buffer, in the DOM. The scrollbar still spans the whole collection, so a virtual list of a hundred thousand items scrolls like a regular list. + +## Live Demo + +<PlatformBlock for="Angular"> + +<Sample src="/data-display/virtual-scroll-overview" height={560} alt="Angular Virtual Scroll with 100,000 employees" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +<Sample src="/layouts/virtual-scroll/overview" height={560} alt="{Platform} Virtual Scroll with 100,000 employees" /> + +</PlatformBlock> + +## Anatomy + +The {Platform} Virtual Scroll renders the visible items plus a configurable buffer, and its track preserves the scroll range of the whole collection. + +{/*TODO: add the Virtual Scroll anatomy image and render it with the <Anatomy> component.*/} + +<PlatformBlock for="Angular"> + +```text +igx-virtual-scroll — scrollable viewport (role="list") +└── .igx-virtual-scroll__track — provides the collection's scroll range + └── .igx-virtual-scroll__content — positions the rendered window + └── .igx-virtual-item — one wrapper per rendered item (data-index); hosts the item template +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```text +igc-virtual-scroll — scrollable viewport +└── [part="virtualization-track"] — provides the collection's scroll range + └── [part="virtualization-content"] — positions the rendered window + └── div[data-vs-index] — one wrapper per rendered item; hosts the item template +``` + +</PlatformBlock> + +## Getting Started + +<PlatformBlock for="Angular"> + +Set up {ProductName} with the [Getting Started](../general/getting-started.mdx) topic, then import the <ApiLink type="VirtualScroll" /> and the `IgxVirtualItemDirective`, which marks the item template: + +```ts +import { Component } from '@angular/core'; +import { IgxVirtualItemDirective, IgxVirtualScrollComponent } from 'igniteui-angular/virtual-scroll'; + +@Component({ + selector: 'app-employees', + imports: [IgxVirtualScrollComponent, IgxVirtualItemDirective], + templateUrl: './employees.component.html' +}) +export class EmployeesComponent { + public items = Array.from({ length: 100_000 }, (_, i) => ({ name: `Item ${i}` })); +} +``` + +```html +<igx-virtual-scroll [data]="items" style="height: 400px"> + <ng-template igxVirtualItem let-item let-index="index"> + <div class="row">{{ index }}: {{ item.name }}</div> + </ng-template> +</igx-virtual-scroll> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +Set up {ProductName} with the [Getting Started](../general-getting-started.mdx) topic, then register the <ApiLink type="VirtualScroll" /> and give it an item template and data: + +```ts +import { defineComponents, IgcVirtualScrollComponent } from 'igniteui-webcomponents'; +import type { VirtualScrollItemContext } from 'igniteui-webcomponents'; +import { html } from 'lit'; + +defineComponents(IgcVirtualScrollComponent); + +const virtualScroll = document.querySelector('igc-virtual-scroll') as IgcVirtualScrollComponent<Item>; +virtualScroll.itemTemplate = (ctx: VirtualScrollItemContext<Item>) => + html`<div class="row">${ctx.index}: ${ctx.value.name}</div>`; +virtualScroll.data = Array.from({ length: 100_000 }, (_, i) => ({ name: `Item ${i}` })); +``` + +```html +<igc-virtual-scroll style="height: 400px"></igc-virtual-scroll> +``` + +</PlatformBlock> + +The Virtual Scroll host needs a fixed height for vertical scrolling or a fixed width for horizontal scrolling. A host that grows with its content has no viewport to fill. + +### Prerequisites and Version Compatibility + +<PlatformBlock for="Angular"> + +| Requirement | Value | +| --- | --- | +| Package | `igniteui-angular` (MIT) | +| Entry point | `igniteui-angular/virtual-scroll` | +| First release with the component | 22.2.0 | + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +| Requirement | Value | +| --- | --- | +| Package | `igniteui-webcomponents` (MIT) | +| First release with the component | 7.3.0 | +| Item templates | Lit's `html` tag. `lit` is a dependency of `igniteui-webcomponents`; add it to your own dependencies when you import it directly. | + +</PlatformBlock> + +## Usage + +### Item Template + +The Virtual Scroll item template receives the item and its position in the whole collection. Use the index and the total count for position-dependent content, such as alternating styles or `aria-posinset` and `aria-setsize`. + +<PlatformBlock for="Angular"> + +Mark an `ng-template` with `igxVirtualItem`, or pass a template defined elsewhere through <ApiLink type="VirtualScroll" member="itemTemplate" label="itemTemplate" />, which takes precedence. The template context provides `$implicit` (the item), `index`, `count`, `first`, `last`, `even`, and `odd`. + +```html +<igx-list> + <igx-virtual-scroll [data]="employees" [estimatedItemSize]="64" style="height: 480px"> + <ng-template igxVirtualItem let-employee let-index="index" let-count="count"> + <igx-list-item [attr.aria-posinset]="index + 1" [attr.aria-setsize]="count"> + <igx-avatar igxListThumbnail shape="circle" [initials]="employee.initials"></igx-avatar> + <span igxListLineTitle>{{ employee.name }}</span> + <span igxListLineSubTitle>{{ employee.email }}</span> + </igx-list-item> + </ng-template> + </igx-virtual-scroll> +</igx-list> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +Set <ApiLink type="VirtualScroll" member="itemTemplate" label="itemTemplate" /> to a function that returns a Lit template. The function receives a `VirtualScrollItemContext` with `value` (the item), `index`, `count`, `isFirst`, and `isLast`. Without an item template, the component renders nothing. + +```ts +virtualScroll.itemTemplate = (ctx: VirtualScrollItemContext<Employee>) => html` + <igc-list-item aria-posinset=${ctx.index + 1} aria-setsize=${ctx.count}> + <igc-avatar slot="start" shape="circle" initials=${ctx.value.initials}></igc-avatar> + <span slot="title">${ctx.value.name}</span> + <span slot="subtitle">${ctx.value.email}</span> + </igc-list-item> +`; +``` + +</PlatformBlock> + +### Data + +The Virtual Scroll <ApiLink type="VirtualScroll" member="data" label="data" /> collection is compared by reference. Assign a new array to update the list; changing the bound array in place, for example with `push`, does not update it. + +<PlatformBlock for="Angular"> + +```ts +this.employees = [...this.employees, newEmployee]; +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```ts +virtualScroll.data = [...virtualScroll.data, newEmployee]; +``` + +</PlatformBlock> + +When `data` changes, the component keeps the measured sizes of the items before the first changed index and measures the rest again when they render. Appending keeps every existing measurement; replacing, filtering, or sorting discards the measurements from the first changed item onwards. + +### Estimated Item Size + +The Virtual Scroll <ApiLink type="VirtualScroll" member="estimatedItemSize" label="estimatedItemSize" /> is the size in pixels an item has until it renders and is measured (`50` by default). Items can have different sizes: each measured size replaces the estimate. Set the estimate close to the average item size to keep the scrollbar and `scrollToIndex` accurate before items are measured. + +<PlatformBlock for="Angular"> + +```html +<igx-virtual-scroll [data]="employees" [estimatedItemSize]="80" style="height: 480px">...</igx-virtual-scroll> +``` + +<Sample src="/data-display/virtual-scroll-variable-size" height={560} alt="Angular Virtual Scroll with variable item heights" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-virtual-scroll estimated-item-size="80" style="height: 480px"></igc-virtual-scroll> +``` + +<Sample src="/layouts/virtual-scroll/variable-size" height={560} alt="{Platform} Virtual Scroll with variable item heights" /> + +</PlatformBlock> + +Items are measured by their border box, so margins are not part of an item's size. Space items with padding, or with a `gap` inside the item, instead of margins. + +### Orientation + +The Virtual Scroll <ApiLink type="VirtualScroll" member="orientation" label="orientation" /> sets the scroll axis: `vertical` (default) or `horizontal`. In a horizontal list, give each item a width and the host a height. In a right-to-left context, horizontal scrolling and item positioning are mirrored. + +<PlatformBlock for="Angular"> + +```html +<igx-virtual-scroll orientation="horizontal" [data]="employees" [estimatedItemSize]="220" style="height: 200px"> + <ng-template igxVirtualItem let-employee> + <div style="width: 220px">...</div> + </ng-template> +</igx-virtual-scroll> +``` + +<Sample src="/data-display/virtual-scroll-horizontal" height={260} alt="Angular Virtual Scroll with horizontal cards" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-virtual-scroll orientation="horizontal" estimated-item-size="220" style="height: 200px"></igc-virtual-scroll> +``` + +<Sample src="/layouts/virtual-scroll/horizontal" height={260} alt="{Platform} Virtual Scroll with horizontal cards" /> + +</PlatformBlock> + +### Over-Scan + +The Virtual Scroll <ApiLink type="VirtualScroll" member="overScan" label="overScan" /> is the number of extra items rendered beyond each edge of the viewport (`2` by default). A larger value reduces blank areas during fast scrolling and renders more elements. + +<PlatformBlock for="Angular"> + +```html +<igx-virtual-scroll [data]="items" [overScan]="6" style="height: 400px">...</igx-virtual-scroll> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-virtual-scroll over-scan="6" style="height: 400px"></igc-virtual-scroll> +``` + +</PlatformBlock> + +### Scroll to Index + +The Virtual Scroll <ApiLink type="VirtualScroll" member="scrollToIndex" label="scrollToIndex" /> method scrolls an item into view. Its options are those of the native `scrollIntoView`: `block` (`start`, `center`, `end`, or `nearest`), `inline` for a horizontal list, and `behavior` (`auto` or `smooth`). Items that have not rendered only have an estimated size, so the component measures the items where it lands and corrects the position; the returned promise resolves on the final position. + +<PlatformBlock for="Angular"> + +```ts +private readonly virtualScroll = viewChild.required(IgxVirtualScrollComponent); + +public async goTo(index: number): Promise<void> { + await this.virtualScroll().scrollToIndex(index, { block: 'center' }); +} +``` + +<Sample src="/data-display/virtual-scroll-scroll-to-index" height={620} alt="Angular Virtual Scroll scrolling to an index" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```ts +await virtualScroll.scrollToIndex(index, { block: 'center' }); +``` + +<Sample src="/layouts/virtual-scroll/scroll-to-index" height={620} alt="{Platform} Virtual Scroll scrolling to an index" /> + +</PlatformBlock> + +With `block: 'nearest'`, the position does not change when the item is already fully visible. Indices outside the collection are clamped to the first or last item. + +### Infinite Scroll + +<PlatformBlock for="Angular"> + +The Virtual Scroll <ApiLink type="VirtualScroll" member="dataRequest" label="dataRequest" /> output supports append-only loading from remote data. It is emitted when the rendered window nears the end of `data`, and on the first render when the loaded items do not fill the viewport. Append the requested items as a new array: + +```html +<igx-virtual-scroll [data]="employees()" [estimatedItemSize]="64" (dataRequest)="loadMore($event)" style="height: 440px"> + <ng-template igxVirtualItem let-employee>...</ng-template> +</igx-virtual-scroll> +``` + +```ts +public readonly employees = signal<Employee[]>(firstPage); + +public loadMore(request: VirtualScrollDataRequest): void { + this.service.fetch(request.startIndex, request.count).subscribe(page => { + this.employees.update(current => [...current, ...page]); + }); +} +``` + +<Sample src="/data-display/virtual-scroll-infinite-scroll" height={560} alt="Angular Virtual Scroll loading more items while scrolling" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +The Virtual Scroll `igcDataRequest` event supports append-only loading from remote data. It is emitted when the rendered window nears the end of `data`, and on the first render when the loaded items do not fill the viewport. Append the requested items as a new array: + +```ts +virtualScroll.addEventListener('igcDataRequest', (event: CustomEvent<VirtualScrollDataRequest>) => { + const { startIndex, count } = event.detail; + fetchEmployees(startIndex, count).then(page => { + virtualScroll.data = [...virtualScroll.data, ...page]; + }); +}); +``` + +<Sample src="/layouts/virtual-scroll/infinite-scroll" height={560} alt="{Platform} Virtual Scroll loading more items while scrolling" /> + +</PlatformBlock> + +Only one data request is pending at a time; the next one follows the next `data` change. An empty `data` emits no request, so load the first page yourself. When the source has no more items, stop appending: the component does not request the same start index again. + +<PlatformBlock for="Angular"> + +### Paged Data + +The Angular Virtual Scroll <ApiLink type="VirtualScroll" member="dataWindow" label="dataWindow" /> input binds a page of a larger collection instead of `data`. The list is as long as `totalCount`, so the scrollbar spans the whole collection while only the page is in memory, and indices that the page does not cover render nothing. + +```ts +interface VirtualDataWindow<T> { + readonly items: readonly T[]; // the loaded page + readonly startIndex: number; // the index of items[0] in the whole collection + readonly totalCount: number; // the size of the whole collection +} +``` + +Load the next page from the range that <ApiLink type="VirtualScroll" member="stateChange" label="stateChange" /> reports. Cancel the previous request, so a slow response cannot replace a newer page: + +```html +<igx-virtual-scroll [dataWindow]="page()" [estimatedItemSize]="64" (stateChange)="onStateChange($event)" style="height: 440px"> + <ng-template igxVirtualItem let-employee>...</ng-template> +</igx-virtual-scroll> +``` + +```ts +public readonly page = signal<VirtualDataWindow<Employee>>({ items: [], startIndex: 0, totalCount: 100_000 }); +private pending?: Subscription; + +public onStateChange(state: VirtualScrollState): void { + const page = this.page(); + if (state.startIndex >= page.startIndex && state.endIndex < page.startIndex + page.items.length) { + return; // The loaded page already covers the range. + } + + const startIndex = Math.max(0, state.startIndex - 30); + const count = state.endIndex + 30 - startIndex + 1; + + this.pending?.unsubscribe(); + this.pending = this.service.fetch(startIndex, count).subscribe(result => { + this.page.set({ items: result.items, startIndex, totalCount: result.total }); + }); +} +``` + +<Sample src="/data-display/virtual-scroll-paged-data" height={560} alt="Angular Virtual Scroll loading pages of a remote collection" /> + +Measured sizes are kept per index while `totalCount` stays the same; a page with a different `totalCount`, such as a filtered result, is measured again. `dataRequest` is not emitted while `dataWindow` is bound. The component stores one size entry per index, so its memory grows with `totalCount`: roughly 17 MB for a million items. + +</PlatformBlock> + +### Layout Complete + +The Virtual Scroll <ApiLink type="VirtualScroll" member="layoutComplete" label="layoutComplete" /> property is a promise that resolves when the current render, the measurements it triggers, and the renders they schedule are complete. Await it before you read rendered items after a `data` change, a scroll, or a resize. + +<PlatformBlock for="Angular"> + +```ts +this.employees = await firstValueFrom(this.service.fetchAll()); +await this.virtualScroll().layoutComplete; +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```ts +virtualScroll.data = await fetchEmployees(); +await virtualScroll.layoutComplete; +``` + +</PlatformBlock> + +### Do/Don't + +{/*TODO: add the Virtual Scroll Do/Don't guidance image from Indigo.Design when it is available.*/} + +<PlatformBlock for="Angular"> + +**When to use:** Use the Virtual Scroll for a long list that is too large to render at once, such as a directory, a feed, a log, or a strip of cards, including lists that load remote data while scrolling. + +**When not to use:** Render a short list directly with the [List](../list.mdx) and `@for`. Use the [Grid](../grid/grid.mdx) for tabular data with columns, sorting, or filtering. Show a small set of rich items as [Card](../card.mdx) elements without virtualization. + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +**When to use:** Use the Virtual Scroll for a long list that is too large to render at once, such as a directory, a feed, a log, or a strip of cards, including lists that load remote data while scrolling. + +**When not to use:** Render a short list directly with the [List](../grids/list.mdx). Show a small set of rich items as [Card](./card.mdx) elements without virtualization. + +</PlatformBlock> + +| Do | Don't | +| --- | --- | +| Give the host a fixed height (vertical) or width (horizontal). | Let the host grow with its content. | +| Set `estimatedItemSize` close to the average item size. | Keep the 50px default for much larger or smaller items. | +| Assign a new array when the collection changes. | Change the bound array in place. | +| Space items with padding or `gap`. | Space items with margins. | + +## Properties + +<PlatformBlock for="Angular"> + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| <ApiLink type="VirtualScroll" member="data" label="data" /> | `T[]` | `[]` | The collection to virtualize. Compared by reference. | +| <ApiLink type="VirtualScroll" member="dataWindow" label="dataWindow" /> | `VirtualDataWindow<T> \| null` | `null` | A page of a larger collection, used instead of `data` while it is set. | +| <ApiLink type="VirtualScroll" member="orientation" label="orientation" /> | `'vertical' \| 'horizontal'` | `'vertical'` | The scroll axis. | +| <ApiLink type="VirtualScroll" member="overScan" label="overScan" /> | `number` | `2` | Extra items rendered beyond each edge of the viewport. | +| <ApiLink type="VirtualScroll" member="estimatedItemSize" label="estimatedItemSize" /> | `number` | `50` | The size in pixels of an item until it is measured. A non-positive value uses `50`. | +| <ApiLink type="VirtualScroll" member="itemTemplate" label="itemTemplate" /> | `TemplateRef<IgxVsItemContext<T>> \| null` | `null` | The item template. Takes precedence over a projected `ng-template[igxVirtualItem]`. | +| <ApiLink type="VirtualScroll" member="layoutComplete" label="layoutComplete" /> | `Promise<void>` (read-only) | — | Resolves when rendering and item measurement have settled. | + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| <ApiLink type="VirtualScroll" member="data" label="data" /> | `T[]` | `[]` | The collection to virtualize. Compared by reference. Property only. | +| <ApiLink type="VirtualScroll" member="orientation" label="orientation" /> | `'vertical' \| 'horizontal'` | `'vertical'` | The scroll axis. Attribute: `orientation`. | +| <ApiLink type="VirtualScroll" member="overScan" label="overScan" /> | `number` | `2` | Extra items rendered beyond each edge of the viewport. Attribute: `over-scan`. | +| <ApiLink type="VirtualScroll" member="estimatedItemSize" label="estimatedItemSize" /> | `number` | `50` | The size in pixels of an item until it is measured. A non-positive value uses `50`. Attribute: `estimated-item-size`. | +| <ApiLink type="VirtualScroll" member="itemTemplate" label="itemTemplate" /> | `VirtualScrollItemTemplate<T> \| null` | `null` | The function that renders each item. Property only. | +| <ApiLink type="VirtualScroll" member="layoutComplete" label="layoutComplete" /> | `Promise<void>` (read-only) | — | Resolves when rendering and item measurement have settled. | + +</PlatformBlock> + +## Methods + +| Name | Returns | Description | +| --- | --- | --- | +| <ApiLink type="VirtualScroll" member="scrollToIndex" label="scrollToIndex(index: number, options?: ScrollIntoViewOptions)" /> | `Promise<void>` | Scrolls the item at `index` into view and resolves when the corrected position is stable. | + +## Events + +<PlatformBlock for="Angular"> + +| Name | Payload | Description | +| --- | --- | --- | +| <ApiLink type="VirtualScroll" member="stateChange" label="stateChange" /> | `VirtualScrollState` | Emitted when the rendered window changes: `startIndex`, `endIndex`, `viewportSize`, `totalSize`. | +| <ApiLink type="VirtualScroll" member="dataRequest" label="dataRequest" /> | `VirtualScrollDataRequest` | Emitted when the rendered window nears the end of `data`: `startIndex`, `count`. Not emitted while `dataWindow` is bound. | + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +| Name | Detail | Description | +| --- | --- | --- | +| `igcStateChange` | `VirtualScrollState` | Emitted when the rendered window changes: `startIndex`, `endIndex`, `viewportSize`, `totalSize`. | +| `igcDataRequest` | `VirtualScrollDataRequest` | Emitted when the rendered window nears the end of `data`: `startIndex`, `count`. | + +</PlatformBlock> + +## Styling + +The {Platform} Virtual Scroll has no theme of its own: it lays out the viewport, and the rendered items take their styles from the elements and components in the item template. + +<PlatformBlock for="Angular"> + +Size the host and target the rendered items with the classes from the [Anatomy](#anatomy): + +```scss +.employees igx-virtual-scroll { + block-size: 480px; +} + +.employees .igx-virtual-item:nth-child(even) { + background: var(--ig-gray-100); +} +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +The component renders into its light DOM, so regular selectors reach the rendered items. Its default styles give the host a height of `18.75rem`; override the height to size the viewport. + +```css +igc-virtual-scroll.employees { + height: 480px; +} + +igc-virtual-scroll.employees [data-vs-index]:nth-child(even) { + background: var(--ig-gray-100); +} +``` + +</PlatformBlock> + +## Accessibility + +The {Platform} Virtual Scroll keeps only the rendered window in the DOM, so the item template has to expose each item's position in the whole collection. + +### Keyboard Interaction + +The {Platform} Virtual Scroll adds no key handlers. The host is a native scroll container, and a focused scroll container scrolls with the browser's keys: + +| Key | Action | +| --- | --- | +| Arrow Up / Arrow Down | Scrolls a vertical list. | +| Arrow Left / Arrow Right | Scrolls a horizontal list. | +| Page Up / Page Down | Scrolls by about one viewport. | +| Home / End | Scrolls to the start or the end of the collection. | + +The host has no `tabindex`. Browsers differ in whether a scroll container without focusable content can receive focus, so set `tabindex="0"` on the host when the items contain nothing focusable. Items scrolled out of view leave the DOM, so focus inside a removed item is lost. + +### Screen Readers / ARIA + +<PlatformBlock for="Angular"> + +- The host has `role="list"`; the track, the content element, and the item wrappers have `role="presentation"`. Items that render `role="listitem"`, such as `igx-list-item`, are exposed as items of that list. +- Map the `index` and `count` template variables to `aria-posinset` and `aria-setsize`. +- Give a focusable host an accessible name with `aria-label` or `aria-labelledby`. + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +- The track, the content element, and the item wrappers have `role="presentation"`. The host has no role: place it inside an element with a list role, such as `igc-list`, or give it `role="list"` when the items render `role="listitem"`. +- Map the `index` and `count` context properties to `aria-posinset` and `aria-setsize`. +- Give a focusable host a role that supports an accessible name, such as `role="list"`, and name it with `aria-label` or `aria-labelledby`. + +</PlatformBlock> + +### Accessibility Compliance + +Infragistics documents the accessibility standards that {ProductName} targets in the [Accessibility Compliance](../interactivity/accessibility-compliance.mdx) topic. This topic makes no conformance claim for the Virtual Scroll: the table lists what the component provides, and the list after it covers what the application must add. + +| Criterion | How the component supports the requirement | +| --- | --- | +| [1.3.1 Info and Relationships](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships) | The wrappers are presentational, so the list structure comes from the host and the item template, which can expose each item's position with `aria-posinset` and `aria-setsize`. | +| [2.1.1 Keyboard](https://www.w3.org/WAI/WCAG21/Understanding/keyboard) | The host is a native scroll container that scrolls with the keyboard once it has focus. Reaching it with the keyboard depends on the application; see the list below. | + +Your responsibilities: + +- Make the host keyboard-reachable with `tabindex="0"` when the items contain nothing focusable, and give it an accessible name. +- Expose the item position with `aria-posinset` and `aria-setsize` from the item template. +- Provide list semantics that fit the item template (see [Screen Readers / ARIA](#screen-readers--aria)). +- Keep application state, such as a selection, in the data rather than in the rendered item elements. + +## Troubleshooting + +### Why does the Virtual Scroll render no items? + +The host has no size on the scroll axis, the item template is missing, or `data` is empty. Give the host a fixed height (vertical) or width (horizontal), set the item template, and check the bound collection. + +### Why does the list not update when I add an item? + +The Virtual Scroll compares `data` by reference, so a change in place is not detected. Assign a new array, for example `[...items, newItem]`. + +### Why does the scrollbar change size while I scroll? + +Items that have not rendered use `estimatedItemSize`, and the total size is corrected as items are measured. Set `estimatedItemSize` close to the average item size. + +### Why do items drift out of place further down the list? + +Margins are not part of an item's measured size. Replace item margins with padding, or with a `gap` inside the item. + +<PlatformBlock for="Angular"> + +### Why does a list inside a drop-down or dialog show its items one frame late? + +A container that is hidden until it opens has no size in the change detection pass that reveals it, so the host is measured after that render and the items render in the next frame. Read the rendered items after `layoutComplete` resolves. + +### How do I replace an igxForOf list with the Virtual Scroll? + +The Virtual Scroll measures items at runtime and creates its own scroll container, so the container size and scroll container inputs of `igxForOf` have no equivalent. The `igxForOf` directive is deprecated in favor of the Virtual Scroll; existing lists keep working, but use the Virtual Scroll for new lists that virtualize a single axis. + +| igxForOf | Virtual Scroll | +| --- | --- | +| `*igxFor="let item of data"` | `[data]="data"` with an `ng-template igxVirtualItem` | +| `igxForScrollOrientation` | `orientation` | +| `igxForContainerSize` | The host's height or width, set with CSS | +| `igxForItemSize` | `estimatedItemSize` (a starting estimate; items are measured) | +| `igxForScrollContainer` | Not needed: the host is the scroll container | +| `scrollTo(index)` | `scrollToIndex(index, options)`, which returns a promise | +| `chunkLoad`, `chunkPreload` | `stateChange` | +| `igxForRemote` with `totalItemCount` | `dataWindow` with `totalCount`, or `data` with `dataRequest` for append-only loading | +| `index`, `count`, `first`, `last`, `even`, `odd` | The same template variables | + +The grids keep their own row and column virtualization; see [Grid Virtualization](../grid/virtualization.mdx). + +</PlatformBlock> + +## Known Limitations + +- The {Platform} Virtual Scroll virtualizes one axis. Rows and columns that are both virtualized require a grid. +- Items scrolled out of view are removed from the DOM together with their focus and internal state. + +<PlatformBlock for="Angular"> + +- With `dataWindow`, a page that keeps `totalCount` but places different records at the same indices keeps the measured sizes of the previous records until those rows render again. + +</PlatformBlock> + +## API References + +- <ApiLink type="VirtualScroll" /> + +## Dependencies + +<PlatformBlock for="Angular"> + +The Angular Virtual Scroll has no dependencies on other components. Import `IgxVirtualScrollComponent` and `IgxVirtualItemDirective` from `igniteui-angular/virtual-scroll`; the structural styles ship with the component. + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +The {Platform} Virtual Scroll has no dependencies on other components and needs no theme of its own. It uses `lit` to render item templates, and the components in the item template need a theme stylesheet. + +</PlatformBlock> + +## Additional Resources + +- [{ProductName} **Forums**]({ForumsLink}) +- [{ProductName} **GitHub**]({GithubLink}) + +## Related Components + +<PlatformBlock for="Angular"> + +- [List](../list.mdx) - Use the List for a short list, or as the container of a virtualized list. +- [Card](../card.mdx) - Use cards for a small set of rich items, or as items of a horizontal Virtual Scroll. +- [Virtual ForOf Directive](../for-of.mdx) - The directive-based virtualization used by existing lists. + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +- [List](../grids/list.mdx) - Use the List for a short list, or as the container of a virtualized list. +- [Card](./card.mdx) - Use cards for a small set of rich items, or as items of a horizontal Virtual Scroll. + +</PlatformBlock> + +## FAQ + +<Faq> + <FaqItem question="How many items can the Virtual Scroll handle?" indicatorPosition="end"> + The {Platform} Virtual Scroll keeps only the items in its viewport and the over-scan buffer in the DOM, so the size of the collection does not change how many elements render. When the total size of a collection exceeds the browser's scroll limit, the Virtual Scroll maps the collection onto the scroll range the browser supports. + </FaqItem> + <FaqItem question="Do Virtual Scroll items need the same size?" indicatorPosition="end"> + Items in the {Platform} Virtual Scroll can have different sizes, because each item is measured once it renders. Set `estimatedItemSize` close to the average item size so that the scrollbar is accurate before items are measured. + </FaqItem> + <FaqItem question="How do I scroll the Virtual Scroll to a specific item?" indicatorPosition="end"> + Call the {Platform} Virtual Scroll `scrollToIndex` method with the item index and optional `block` and `behavior` options. The method returns a promise that resolves when the corrected position is stable. + </FaqItem> + <FaqItem question="How do I load remote data into the Virtual Scroll while the user scrolls?" indicatorPosition="end"> + <PlatformBlock for="Angular"> + The Angular Virtual Scroll supports two models. For append-only loading, handle `dataRequest` and assign a new array that includes the requested items. For a collection read a page at a time, bind `dataWindow` and load the range that `stateChange` reports. + </PlatformBlock> + <PlatformBlock for="WebComponents"> + The {Platform} Virtual Scroll supports append-only loading through the `igcDataRequest` event. Handle the event and assign a new array that includes the requested items to `data`. + </PlatformBlock> + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/en/components/themes/accessibility.mdx b/docs/xplat/src/content/en/components/themes/accessibility.mdx new file mode 100644 index 0000000000..70109bbd96 --- /dev/null +++ b/docs/xplat/src/content/en/components/themes/accessibility.mdx @@ -0,0 +1,289 @@ +--- +title: "{Platform} Styling and Themes | {Platform} Accessibility | Infragistics" +description: "How the {ProductName} theming engine supports accessibility - automatic text contrast, relative text scaling, and a color-vision-deficiency chart palette." +keywords: "{ProductName}, Infragistics, Accessibility, Contrast, WCAG, Styling, Themes" +license: MIT +last_updated: "2026-08-31" +mentionedTypes: [] +llms: + description: "{ProductName} calculates text colors against a WCAG contrast threshold at runtime, keeps every type scale relative, and ships an opt-in color-vision-deficiency chart palette." +--- + +{/*This topic serves Angular, React, Web Components and Blazor. Angular-specific content sits in Angular-only platform blocks; everything else is shared. The Angular doc set still carries its own copy at docs/angular/src/content/en/components/themes/accessibility.mdx because this page is excluded for Angular in src/content/en/toc.json; keep the two in sync until that exclude is lifted. Never write a literal PlatformBlock tag in prose or a comment - the generator strips blocks with a regex that does not skip comments, and an unpaired tag swallows the rest of the page.*/} + +import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; +import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; + +# Accessibility in {ProductName} + +The {ProductName} theming engine builds accessibility into the styling layer: it calculates a text color for any background color at runtime and measures it against a WCAG contrast threshold, expresses every type scale in relative units so text scales with the user's settings, and ships an opt-in color palette for readers with color-vision deficiency. + +## Overview + +Accessibility in {ProductName} is delivered by two layers that you configure independently: + +| Layer | What it is responsible for | Where it is documented | +|---|---|---| +| **Theming engine** (`igniteui-theming`) | Color contrast, text sizing, chart color palettes, and the styling utilities that keep custom controls reachable by assistive technology. | This page. | +| **Component library** (`{PackageCommon}`) | Keyboard operability, focus movement, ARIA roles and states, and screen-reader announcements. | [Accessibility Compliance](../interactivity/accessibility-compliance.mdx) and each component topic. | + +This page covers the first layer. It describes capabilities that apply to every component you style with the theming engine, including components you build yourself on top of it. + +The table below summarizes what the theming engine does for the person ultimately using your application. Each row is an input your application builds on, not a conformance outcome: you supply the colors, the engine generates pairings measured against a WCAG threshold, and verifying that the finished product conforms remains your responsibility. + +| A person who… | What the theming engine provides | +|---|---| +| Needs readable text on colored buttons, chips, and badges | A foreground color is calculated in the browser for every generated palette color — including brand colors you supply — and measured against the WCAG contrast level you configure (AA by default). | +| Enlarges their default browser font size | Every type scale is expressed in relative units, and the library never pins the page font size. | +| Has a color-vision deficiency and reads charts | An opt-in chart palette chosen to stay distinguishable under common forms of color-vision deficiency. | +| Prefers a dark interface for light sensitivity | A complete dark palette for each of the four shipped themes. | +| Uses a screen reader with a custom-styled form control | A styling utility that hides a native input visually while keeping it in the accessibility tree. | + +## Before You Start + +Three boundaries determine what you can rely on from this page. + +**The theming engine styles; it does not add semantics.** ARIA roles, keyboard handling, and focus management come from the component library, not from the theme. Applying a theme does not make a custom control accessible on its own. + +**The contrast calculation applies to generated palette colors.** The engine calculates foreground colors for palettes produced by the `palette()` generator. Individual component themes may also pair a specific foreground token with a specific background token by hand; those pairings are set per theme and are not produced by the contrast calculation described below. When you override component tokens directly, verify the result with [`contrast()`](#check-a-contrast-ratio-yourself). + +**Conformance of the finished product is yours to verify.** The engine controls its inputs — palettes, calculated pairings, type scales — not how your application uses them. A palette built from your brand colors can reach full conformance, but the engine cannot claim that outcome for you; confirm the rendered result before stating conformance. + +<DocsAside type="note"> +The capabilities on this page describe the theming engine's behavior. They are not a conformance statement for {ProductName} as a product. For per-component conformance information, see [Accessibility Compliance](../interactivity/accessibility-compliance.mdx). +</DocsAside> + +## Next Steps + +- Use [`contrast-color()`](#keep-text-readable-on-a-brand-color) wherever you place text on a palette color, instead of hard-coding a foreground. +- Turn on the [color-vision-deficiency chart palette](#enable-the-color-vision-deficiency-chart-palette) if your application renders charts. +- Run any custom color pairing you introduce through [`contrast()`](#check-a-contrast-ratio-yourself) before shipping it. +- If you generate palettes with the [Theming MCP server](../ai/theming-mcp.mdx), it checks surface and gray contrast against WCAG thresholds as it builds them. + +## Available Tools + +The theming engine exposes these Sass functions and mixins for the accessibility behavior described on this page. + +<DocsAside type="note"> +These are Sass APIs: they need a Sass build with `igniteui-theming` resolvable from your load paths, as described in <PlatformBlock for="Angular">[Theming with Sass](sass/index.mdx)</PlatformBlock><PlatformBlock for="React, WebComponents, Blazor">[Customizing with Sass](overview.mdx#customizing-with-sass)</PlatformBlock>. If you use the prebuilt theme CSS instead, you still get calculated contrast colors - pair each palette color with its `-contrast` variable, for example `var(--ig-primary-500-contrast)`, and set the threshold with `--ig-contrast-level`. The chart palette, `hide-default()`, and the `contrast()` and `luminance()` functions have no CSS-only equivalent. +</DocsAside> + +| Tool | Signature | What it does | +|---|---|---| +| `contrast-color()` | `contrast-color($palette: null, $color: primary, $variant: 500, $opacity: null)` | Returns a readable foreground color for a palette color. Every argument is optional; omit `$palette` to resolve the shade through its CSS variable. | +| `adaptive-contrast()` | `adaptive-contrast($color)` | Returns a readable foreground color for any color you pass, including one held in a CSS variable. | +| `contrast()` | `contrast($background, $foreground)` | Returns the WCAG contrast ratio between two colors. | +| `luminance()` | `luminance($color)` | Returns a color's relative luminance, from `0` (black) to `1` (white). | +| `configure-colors()` | `configure-colors($enhanced-accessibility: null)` | Switches chart themes to the color-vision-deficiency palette. | +| `hide-default()` | `@include hide-default()` | Hides a native input visually while keeping it in the accessibility tree. | + +## Common Workflows + +### Keep text readable on a brand color + +Pair every background drawn from the palette with `contrast-color()` rather than a hard-coded `black` or `white`: + +```scss +.my-component { + background: color($color: 'primary', $variant: 500); + color: contrast-color($color: 'primary', $variant: 500); +} +``` + +The same pairing in plain CSS, using the variables the theme already emits: + +```css +.my-component { + background: var(--ig-primary-500); + color: var(--ig-primary-500-contrast); +} +``` + +For a color that does not come from the palette — a tenant color, a user preference, a value set at runtime — use `adaptive-contrast()`: + +```scss +.my-component { + --bg: #09f; + + background: var(--bg); + color: adaptive-contrast(var(--bg)); +} +``` + +`adaptive-contrast()` is a thin wrapper over a relative-color expression, so the same result is available without Sass. `--y-contrast` is defined by the theme: + +```css +.my-component { + --bg: #09f; + + background: var(--bg); + color: hsla(from color(from var(--bg) var(--y-contrast)) h 0 l / 1); +} +``` + +The calculation happens in the browser rather than at build time. If the background color changes after the stylesheet is compiled, the foreground color is recalculated to match, so the pairing survives runtime theme switching and per-tenant branding. + +<DocsAside type="note"> +`adaptive-contrast()` selects between black and white. Because those are the two available outcomes, the ratio the mechanism can achieve against a mid-tone background is bounded at roughly 4.6:1. That satisfies the WCAG AA threshold of 4.5:1 for normal text, which is the default the engine is configured for. Do not rely on this mechanism alone to reach the 7:1 AAA threshold; reaching AAA requires choosing background colors that are light or dark enough to allow it. +</DocsAside> + +### Set the contrast level + +The calculated foreground is measured against a WCAG threshold held in the `--ig-contrast-level` CSS variable, which defaults to `var(--ig-wcag-aa)`. Three levels are predefined: `a`, `aa`, and `aaa`. + +Set the level for the whole application when you generate the palette: + +```scss +@include palette($palette, $contrast-level: 'aaa'); +``` + +To raise the level for one part of the page only, override the variable on that scope: + +```css +.high-contrast-panel { + --ig-contrast-level: var(--ig-wcag-aaa); +} +``` + +The contrast level moves the luminance threshold at which the calculated foreground switches between black and white; it does not change which two colors can be chosen, and setting `aaa` does not by itself make a pairing conform — that depends on the background colors you chose. Verify with [`contrast()`](#check-a-contrast-ratio-yourself). See [Palettes](palettes.mdx) for the generated contrast variables. + +### Scale text with the user's browser settings + +No configuration is required. Every type scale in the four shipped themes expresses `font-size`, `line-height`, `letter-spacing`, and margins through the `rem()` function, so all emitted values are relative to the root font size. + +The library records the base size as a value you can read: + +```css +--ig-base-font-size: 16px; +``` + +It never emits a `html { font-size: … }` rule. This matters because writing that rule is the most common way a theming system overrides a user who has enlarged their default text. Because the library only reads the base size, a user who sets a larger default in their browser gets larger {ProductName} text. + +This addresses WCAG 2.1 <a href="https://www.w3.org/WAI/WCAG21/Understanding/resize-text.html" target="_blank" rel="noopener noreferrer">1.4.4 Resize Text</a> (Level AA) at the styling layer. + +### Raise or lower the contrast threshold + +The level at which the calculated foreground flips from black to white is held in a CSS variable, so it can be changed without Sass. It defaults to AA: + +```css +:root { + --ig-contrast-level: var(--ig-wcag-aaa); +} +``` + +From Sass, the `palette()` and `adaptive-contrast()` mixins take `a`, `aa`, or `aaa` directly. + +### Enable the color-vision-deficiency chart palette + +Charts commonly distinguish series by hue alone, which does not work for readers with a color-vision deficiency. The theming engine ships a second chart palette whose colors stay distinguishable under the common forms of that condition. + +The palette is **off by default**. Turn it on with `configure-colors()`: + +```scss +// Include at the top level, before your theme includes. +@include configure-colors($enhanced-accessibility: true); +``` + +Every chart theme then draws from the accessible set. The chart brushes are set when the theme is generated, so this one requires Sass; the prebuilt theme CSS exposes no variables for them. + +<PlatformBlock for="Angular"> + +In {ProductName} the same switch is available at setup: + +```scss +@include core($enhanced-accessibility: true); +``` + +</PlatformBlock> + +<DocsAside type="note"> +Color alone should not be the only way a chart conveys meaning. Pair this palette with direct labels, distinct markers, or dash patterns so the chart also works in grayscale. +</DocsAside> + +### Check a contrast ratio yourself + +The engine implements the WCAG relative-luminance formula and exposes it, so you can check your own color choices against the same implementation the library uses: + +```scss +$ratio: contrast(#09f, #000); // 7 +$lum: luminance(#09f); // 0.3 +``` + +Use this whenever you override a component token directly, or introduce a color pairing the palette generator did not produce. These two run at compile time and have no CSS equivalent - a stylesheet cannot compute a ratio. + +### Hide an input without hiding it from screen readers + +Custom-styled checkboxes, radios, and switches usually keep a native input underneath for semantics and keyboard behavior. Hide it with `hide-default()`: + +```scss +.my-checkbox input { + @include hide-default(); +} +``` + +The mixin expands to a fixed set of declarations, so it can be written directly in CSS: + +```css +.my-checkbox input { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + border: none; + clip: rect(0, 0, 0, 0); + outline: 0; + pointer-events: none; + overflow: hidden; + appearance: none; +} +``` + +The mixin moves the input out of view while leaving it in the accessibility tree, so it keeps its role, its keyboard behavior, and its screen-reader announcements. Using `display: none` or `visibility: hidden` instead removes the control from assistive technology entirely and breaks the component for anyone not using their eyes. + +### Use a dark theme + +Each of the four shipped themes — Material, Bootstrap, Fluent, and Indigo — provides a complete dark palette alongside its light one. Dark presentation is an accessibility need for some users, including those with light sensitivity, so treat it as a supported configuration rather than a cosmetic preference. See [Palettes](palettes.mdx) for how to select one. + +## Troubleshooting + +**Text on a component I restyled is hard to read.** You have likely replaced a background token without replacing its paired foreground token. Set the foreground with `contrast-color()` or `adaptive-contrast()` rather than a fixed value, then confirm the result with `contrast()`. + +**I set `$contrast-level: 'aaa'` but my colors did not change much.** The contrast level moves the luminance threshold at which the calculated foreground switches between black and white. It does not tint the foreground, so it cannot raise the achievable ratio past the bound described above. To reach AAA, change the background colors themselves. + +**My chart colors did not change after enabling the accessible palette.** `configure-colors()` must be included before the chart themes are generated. Move the include above your theme includes. + +**Text does not grow when I increase the browser font size.** Check your own application styles for an `html { font-size: … }` rule or `font-size` values in `px`. The theming engine does not emit either. + +## Additional Resources + +- [Palettes](palettes.mdx) — how palette colors and their contrast companions are generated. +- [Typography](typography.mdx) — the type scales and how to customize them. +- [Accessibility Compliance](../interactivity/accessibility-compliance.mdx) — per-component conformance information. +- <a href="https://www.w3.org/WAI/WCAG21/quickref/" target="_blank" rel="noopener noreferrer">WCAG 2.1 Quick Reference</a> — the success criteria referenced on this page. +- <a href="https://www.w3.org/WAI/ARIA/apg/patterns/" target="_blank" rel="noopener noreferrer">WAI-ARIA Authoring Practices</a> — expected keyboard and ARIA behavior per interaction pattern. + +## FAQ + +<Faq> + <FaqItem question="Does applying an Ignite UI theme make my application accessible?" indicatorPosition="end"> + No. The theming engine handles color contrast, text sizing, and chart palettes. Keyboard operability, ARIA semantics, and screen-reader support come from the component library and from your own markup. + </FaqItem> + + <FaqItem question="Do I still get readable text if I supply my own brand color?" indicatorPosition="end"> + Yes — for colors used through the palette, measured against the configured level (AA by default). The foreground is recalculated in the browser whenever the background changes, including at runtime. Pairings you set by hand are outside the calculation; verify them with <code>contrast()</code>. + </FaqItem> + + <FaqItem question="What does the contrast level setting actually change?" indicatorPosition="end"> + It moves the luminance threshold at which the calculated foreground switches from black to white. It does not change the two colors that can be chosen, so it does not raise the maximum ratio the mechanism can reach. + </FaqItem> + + <FaqItem question="Is the color-vision-deficiency chart palette on by default?" indicatorPosition="end"> + No. Enable it with <code>configure-colors($enhanced-accessibility: true)</code><PlatformBlock for="Angular">, or with <code>core($enhanced-accessibility: true)</code> at setup</PlatformBlock>. + </FaqItem> + + <FaqItem question="Do I need to configure anything for text scaling?" indicatorPosition="end"> + No. Every type scale is already relative, and the library never sets the page font size. Check your own application styles if text does not scale. + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/en/components/themes/overview.mdx b/docs/xplat/src/content/en/components/themes/overview.mdx index 10ebc70cbd..5d1219edf8 100644 --- a/docs/xplat/src/content/en/components/themes/overview.mdx +++ b/docs/xplat/src/content/en/components/themes/overview.mdx @@ -72,13 +72,16 @@ Changing the theme at runtime also requires you to replace the global stylesheet {ProductName} allows you to switch the component themes at runtime by using the `ConfigureTheme` function exported by the library. -Calling it and passing one of the four valid themes - `bootstrap`, `material`, `fluent`, or `indigo` as a string will change the loaded component styles; +It takes the theme as its first argument - `bootstrap`, `material`, `fluent`, or `indigo` - and an optional variant as its second, either `light` or `dark`. Omit the variant to keep the one currently active. ```ts import { configureTheme } from "igniteui-webcomponents"; // Sets material as the theme to be used by all components configureTheme("material"); + +// Sets material and switches to its dark variant +configureTheme("material", "dark"); ``` <DocsAside type="info"> @@ -87,6 +90,26 @@ This only tells components to switch their internal styles to the desired theme, </PlatformBlock> +## Customizing with Sass + +The theme files above are prebuilt CSS, and the topics in this section customize them by overriding CSS variables - see [Palettes](palettes.mdx), [Typography](typography.mdx), [Elevations](elevations.mdx), and [Configuration](configuration.mdx). That path needs no build configuration and covers most customization. + +Some capabilities are only reachable from Sass, because they run at compile time rather than through a variable. The contrast and chart-palette functions on the [Accessibility](accessibility.mdx) topic are the main example. To use them, install `igniteui-theming` and import it: + +```scss +@use 'igniteui-theming' as *; + +// Required for $material-type-scale, $indigo-type-scale, and similar preset variables +@use 'igniteui-theming/sass/typography/presets' as *; + +// Required for $material-elevations and $indigo-elevations +@use 'igniteui-theming/sass/elevations/presets' as *; +``` + +<DocsAside type="note"> +If `@use 'igniteui-theming' as *;` does not resolve, your Sass compiler is missing `node_modules` in its load paths. Set `css.preprocessorOptions.scss.loadPaths` in Vite, or `sassOptions.loadPaths` in Next.js. +</DocsAside> + <PlatformBlock for="React, WebComponents"> ## API References diff --git a/docs/xplat/src/content/en/components/themes/palettes.mdx b/docs/xplat/src/content/en/components/themes/palettes.mdx index 438f3bcd08..52b731da0b 100644 --- a/docs/xplat/src/content/en/components/themes/palettes.mdx +++ b/docs/xplat/src/content/en/components/themes/palettes.mdx @@ -58,34 +58,45 @@ As the table above shows, the `gray` color doesn't include the `A100`, `A200`, ` On top of the aforementioned colors, we also include **Level AA** [WCAG](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html) compliant `contrast` colors for each color variant. This means that you can safely use the corresponding `contrast` color variants as foreground colors for the base color variant. <DocsAside type="info"> -Contrast colors are generated at build-time therefore overriding the CSS variables will not update the corresponding contrast colors. +Contrast colors are CSS relative colors calculated at runtime from the corresponding shade color, so overriding a base color variant updates its contrast color along with it. </DocsAside> -Here's an excerpt of the `primary` color as declared in the Light Bootstrap Palette: +Here's an excerpt of the `primary` color as declared in the Light Material Palette: ```css :root { //... --ig-primary-500: #09f; - --ig-primary-500-contrast: black; + --ig-primary-500-contrast: hsla(from color(from var(--ig-primary-500) var(--y-contrast)) h 0 l / 1); + --ig-primary-seed: #09f; --ig-primary-600: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-primary-600-contrast: black; + --ig-primary-600-contrast: hsla(from color(from var(--ig-primary-600) var(--y-contrast)) h 0 l / 1); --ig-primary-700: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.81)); //... --ig-secondary-400: hsl(from var(--ig-secondary-500) h calc(s * 0.875) calc(l * 1.08)); - --ig-secondary-400-contrast: black; + --ig-secondary-400-contrast: hsla(from color(from var(--ig-secondary-400) var(--y-contrast)) h 0 l / 1); --ig-secondary-500: #df1b74; - --ig-secondary-500-contrast: white; + --ig-secondary-500-contrast: hsla(from color(from var(--ig-secondary-500) var(--y-contrast)) h 0 l / 1); --ig-secondary-600: hsl(from var(--ig-secondary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-secondary-600-contrast: white; + --ig-secondary-600-contrast: hsla(from color(from var(--ig-secondary-600) var(--y-contrast)) h 0 l / 1); //... + --ig-wcag-a: 0.31; + --ig-wcag-aa: 0.185; + --ig-wcag-aaa: 0.178; + --ig-contrast-level: var(--ig-wcag-aa); + --y: clamp(0, (y / var(--ig-contrast-level) - 1) * -infinity, 1); + --y-contrast: xyz-d65 var(--y) var(--y) var(--y); } ``` -All primary color variants are derived from one base variable color variant `--ig-primary-500`. The same goes for the other color variables `--ig-secondary-500`, `--ig-surface-500`, etc. The other variants are generated through the relative color function `hsl()` which takes the main variable color variant `500` and changes it's `staturation` and `lightness` according to the variable variant which is assigned on (`600`,`700`, etc.). We decided to use this approach as it allows us to modify all variants of the `primary`, `secondary`, `surface` and other colors at runtime. +All primary color variants are derived from one base variable color variant `--ig-primary-500`. The same goes for the other color variables `--ig-secondary-500`, `--ig-surface-500`, etc. The other variants are generated through the relative color function `hsl()` which takes the main variable color variant `500` and changes its `saturation` and `lightness` according to the variable variant which is assigned on (`600`,`700`, etc.). We decided to use this approach as it allows us to modify all variants of the `primary`, `secondary`, `surface` and other colors at runtime. -<DocsAside type="warning"> -Because the contrast colors are not generated at CSS runtime like the rest, if we change the main color variant(`500`), the contrast color would not be updated. We would need to change them manually. This behavior will be improved upon in an upcoming release, where the contrast colors will also be calculated at CSS runtime. +Alongside the numbered variants, each color exposes a `seed` variable that holds the base color the palette was generated from, unchanged. For `primary`, `secondary`, and the other chromatic colors the seed matches the `500` variant. For `gray` it does not: `--ig-gray-seed` records the color the grayscale was derived from - black or white, chosen from the surface color's luminance - while `--ig-gray-500` is a generated mid-tone. + +The contrast colors are calculated at CSS runtime from the base color's luminance and the chosen contrast level, picking the more readable of black or white. Because the calculation is part of the cascade, changing the main color variant (`500`) updates its contrast colors with it - no manual step is required. + +<DocsAside type="info"> +The threshold is held in `--ig-contrast-level`, which defaults to `var(--ig-wcag-aa)`. Override it on any scope to switch to `var(--ig-wcag-a)` or `var(--ig-wcag-aaa)`. If you compile the themes from Sass instead of using the prebuilt CSS, the `palette` and `adaptive-contrast` mixins accept `a`, `aa`, or `aaa` directly - see [Accessibility](accessibility.mdx). </DocsAside> ## Defining Palettes diff --git a/docs/xplat/src/content/en/toc.json b/docs/xplat/src/content/en/toc.json index 5839d7ff38..f9ac7e04ab 100644 --- a/docs/xplat/src/content/en/toc.json +++ b/docs/xplat/src/content/en/toc.json @@ -70,7 +70,8 @@ }, { "exclude": [ - "Blazor" + "Blazor", + "Angular" ], "name": "Getting Started", "href": "general-getting-started.mdx", @@ -668,7 +669,7 @@ "Angular" ], "name": "Theming", - "href": "grids/theming-grid.mdx", + "href": "grids/grid/theming-grid.mdx", "premium": true }, { @@ -2215,11 +2216,10 @@ "header": true }, { - "exclude": [ - "Angular" - ], + "exclude": [], "name": "Accordion", - "href": "layouts/accordion.mdx" + "href": "layouts/accordion.mdx", + "updated": true }, { "name": "Avatar", @@ -2424,9 +2424,6 @@ "premium": true }, { - "exclude": [ - "Angular" - ], "name": "Data Entry & Display", "header": true }, @@ -2436,11 +2433,9 @@ "updated": true }, { - "exclude": [ - "Angular" - ], "name": "Button", - "href": "inputs/button.mdx" + "href": "inputs/button.mdx", + "updated": true }, { "name": "Button Group", @@ -2483,6 +2478,15 @@ "premium": true, "preview": true }, + { + "exclude": [ + "React", + "Blazor" + ], + "name": "QR Code", + "href": "inputs/qr-code.mdx", + "new": true + }, { "exclude": [ "Angular" @@ -2512,16 +2516,10 @@ "href": "inputs/dropdown.mdx" }, { - "exclude": [ - "Angular" - ], "name": "Icon", "href": "layouts/icon.mdx" }, { - "exclude": [ - "Angular" - ], "name": "Icon Button", "href": "inputs/icon-button.mdx" }, @@ -2579,11 +2577,9 @@ "href": "inputs/rating.mdx" }, { - "exclude": [ - "Angular" - ], "name": "Switch", - "href": "inputs/switch.mdx" + "href": "inputs/switch.mdx", + "updated": true }, { "exclude": [ @@ -2599,6 +2595,15 @@ "name": "Highlight", "href": "inputs/highlight.mdx" }, + { + "exclude": [ + "React", + "Blazor" + ], + "name": "Virtual Scroll", + "href": "layouts/virtual-scroll.mdx", + "new": true + }, { "name": "Interactions", "header": true @@ -2764,6 +2769,11 @@ "name": "Styles", "href": "themes/styles.mdx" }, + { + "name": "Accessibility", + "href": "themes/accessibility.mdx", + "new": true + }, { "name": "Custom Tailwind Classes", "href": "themes/tailwind.mdx", diff --git a/docs/xplat/src/content/jp/components/ai/theming-mcp.mdx b/docs/xplat/src/content/jp/components/ai/theming-mcp.mdx index ed78342b24..98871ef5c6 100644 --- a/docs/xplat/src/content/jp/components/ai/theming-mcp.mdx +++ b/docs/xplat/src/content/jp/components/ai/theming-mcp.mdx @@ -267,6 +267,10 @@ MCP サーバーは、プロンプトに基づいて AI が自動的に使用す 各ツールの簡単な概要を以下に示します。 +<DocsAside type="info"> +パレットを生成する際、サーバーはサーフェス カラーとグレー カラーのコントラスト比を WCAG のしきい値と照合し、組み合わせが基準を満たさない場合は警告します。テーマ設定エンジン自体に組み込まれているコントラストの動作については、[アクセシビリティ](../themes/accessibility.mdx) を参照してください。 +</DocsAside> + | ツール | 説明 | |------|-------------| | `detect_platform` | `package.json` を読み取り、プロジェクトが Ignite UI for Angular、Web Components、React、Blazor のいずれを使用しているかを識別します。以降のすべてのツールに対して正しいインポート パスとコンポーネント セレクターを選択します。 | diff --git a/docs/xplat/src/content/jp/components/inputs/badge.mdx b/docs/xplat/src/content/jp/components/inputs/badge.mdx index a44f04c4d2..d9776bc14c 100644 --- a/docs/xplat/src/content/jp/components/inputs/badge.mdx +++ b/docs/xplat/src/content/jp/components/inputs/badge.mdx @@ -78,30 +78,20 @@ import badgeDoNot from '@xplat-images/badge/badge-do-nоt.png'; ## 作業の開始 -<PlatformBlock for="Angular"> - -{Platform} Badge を使用するには、まず [{ProductName} の作業の開始](../general/getting-started.mdx) トピックに従って基本的なプロジェクトのセットアップを行い、その後、対象プラットフォーム用にコンポーネントを登録してください。 +{Platform} Badge を使用するには、まず <PlatformBlock for="Angular">[{ProductName} の作業の開始](../general/getting-started.mdx)</PlatformBlock><PlatformBlock for="React,WebComponents,Blazor">[{ProductName} の作業の開始](../general-getting-started.mdx)</PlatformBlock> トピックに従って基本的なプロジェクトのセットアップを行い、その後、対象プラットフォーム用にコンポーネントを登録してください。 -</PlatformBlock> +<PlatformBlock for="React,WebComponents"> -<PlatformBlock for="Blazor, React, WebComponents"> +**{PackageCommon}** パッケージを使用する {Platform} の場合は、パッケージをインストールします: -{Platform} Badge を使用するには、まず [{ProductName} の作業の開始](../general-getting-started.mdx) トピックに従って基本的なプロジェクトのセットアップを行い、その後、対象プラットフォーム用にコンポーネントを登録してください。 +```cmd +npm install {PackageCommon} +``` </PlatformBlock> -### 前提条件とバージョンの互換性 - -対象フレームワークでサポートされているバージョンの {ProductName} パッケージを使用してください。フレームワーク パッケージ、Badge パッケージ、テーマ パッケージは同じリリース バージョンに揃えてください。以下の例では、各コード ブロックで使用されているフレームワークとパッケージを明記しているため、周囲のページ コンテキストなしで読んでもスニペットが自己完結的になっています。 - <PlatformBlock for="WebComponents"> -**{PackageWebComponents}** パッケージを使用する Web Components の場合は、パッケージをインストールします: - -```cmd -npm install {PackageWebComponents} -``` - 次に、以下のように <ApiLink pkg="core" type="Badge" />、そのテーマ CSS をインポートし、コンポーネントを登録する必要があります: ```ts @@ -115,12 +105,6 @@ defineComponents(IgcBadgeComponent); <PlatformBlock for="React"> -**igniteui-react** パッケージを使用する React の場合は、パッケージをインストールします: - -```cmd -npm install igniteui-react -``` - 次に、以下のように Badge のラッパーとそのテーマ CSS をインポートする必要があります: ```tsx @@ -156,16 +140,18 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbBadgeModule)); npm install igniteui-angular ``` -次に、Badge コンポーネントをインポートします: +次に、コンポーネントの `imports` コレクションに `IgxBadgeComponent` をインポートします。 ```ts import { IgxBadgeComponent } from 'igniteui-angular/badge'; ``` -コンポーネントの `imports` コレクションに `IgxBadgeComponent` を追加し、テンプレートで `igx-badge` 要素を使用します。 +</PlatformBlock> <ApiLink pkg="core" type="Badge" /> の使用を開始する最も簡単な方法は次のとおりです: +<PlatformBlock for="Angular"> + ```html <igx-badge></igx-badge> ``` @@ -174,8 +160,6 @@ import { IgxBadgeComponent } from 'igniteui-angular/badge'; <PlatformBlock for="WebComponents"> -<ApiLink pkg="core" type="Badge" /> の使用を開始する最も簡単な方法は次のとおりです: - ```html <igc-badge></igc-badge> ``` @@ -702,13 +686,13 @@ igc-badge { <PlatformBlock for="Angular"> -<Sample src="/data-display/badge-outlined" height={212} position="center" noBorder={false} spacing="md" alt="Angular Badge outlined example" /> +<Sample src="/data-display/badge-outlined" height={250} position="center" noBorder={false} spacing="md" alt="Angular Badge outlined example" /> </PlatformBlock> <PlatformBlock for="React,WebComponents,Blazor"> -<Sample src="/inputs/badge/outlined" height={212} position="center" noBorder={false} spacing="md" alt="{Platform} Badge Example" /> +<Sample src="/inputs/badge/outlined" height={250} position="center" noBorder={false} spacing="md" alt="{Platform} Badge Example" /> アウトライン バッジのボーダー カラーは、`--border-color` CSS 変数を使用してカスタマイズすることもできます。 @@ -805,18 +789,16 @@ Blazor Badge は、次のプロパティを公開します。 ### CSS 変数 -```css -igc-badge::part(base) { - --background-color: var(--ig-error-A100); - --border-radius: 2px; -} -``` - | 変数 | 変更内容 | | --- | --- | | `--background-color` | バッジの背景色。 | +| `--border-color` | バッジのボーダー カラー。 | | `--border-radius` | バッジの角の半径。 | -| `--border-color` | アウトライン バッジのボーダー カラー。 | +| `--elevation` | バッジのシャドウ。 | +| `--icon-color` | バッジのアイコンの色。 | +| `--text-color` | バッジのテキストの色。 | +| `--size` | バッジのサイズ。 | +| `--dot-size` | ドット タイプのバッジのサイズ。 | ### スタイル パーツ @@ -824,6 +806,13 @@ igc-badge::part(base) { | --- | --- | | `base` | バッジのルート要素。 | +```css +igc-badge::part(base) { + --background-color: var(--ig-error-A100); + --border-radius: 2px; +} +``` + <PlatformBlock for="Angular"> <Sample src="/data-display/badge-styling" height={212} position="center" noBorder={false} spacing="md" alt="Angular Badge styling example" /> @@ -944,7 +933,7 @@ igc-badge::part(base) { ## トラブルシューティング -{Platform} Badge のトラブルシューティング ガイダンスは、一般的なスタイルおよびコンテンツの問題について、問題 → 原因 → 対処法の形式で構成されています。 +Badge をインタラクティブなコントロールとして扱ったり、ステータスの唯一の表示手段として扱ったりする前に、このセクションで制約と一般的な判断のポイントを確認してください。 ### カスタムの背景色を設定してもバッジが変わらないのはなぜですか? @@ -986,18 +975,20 @@ igc-badge::part(base) { ## FAQ -これらの FAQ は、{Platform} Badge の一般的なコンテンツ、インジケーター、パッケージの選択について説明します。 - <Faq> <FaqItem question="バッジはアイコンとテキストの両方を表示できますか?"> - はい。**使用方法** に示されているプラットフォーム固有の value と icon の API を使用してください。コンテンツを子要素として直接指定する場合は、アイコンとテキストをコンポーネントのデフォルトのコンテンツ領域内に保持してください。 + はい。テキストには Badge のコンテンツ領域を使用し、視覚的なインジケーターにはサポートされているアイコン コンテンツを使用します。コンパクトなステータスまたはカテゴリのラベルとして機能するように、組み合わせは短くしてください。 </FaqItem> <FaqItem question="コンテンツのない通知ドットを表示するにはどうすればよいですか?"> プラットフォーム固有の `dot` プロパティまたは属性を設定します。ドット バッジは、意図的にテキストやその他のコンテンツなしでレンダリングされます。 </FaqItem> + <FaqItem question="テキスト バッジではなくドット バッジを使用するのはどのような場合ですか?"> + ステータスが存在するかどうかだけで伝わる場合は、ドット バッジを使用します。ユーザーが色や位置に頼らずにステータス、カテゴリ、またはカウントを理解する必要がある場合は、テキスト バッジを使用します。 + </FaqItem> + <FaqItem question="Badge にはどのパッケージをインストールすればよいですか?"> Angular には `igniteui-angular`、React には `igniteui-react`、Web Components には `igniteui-webcomponents`、Blazor には `IgniteUI.Blazor` を使用してください。関連する Ignite UI パッケージは同じリリース バージョンに揃えてください。 </FaqItem> diff --git a/docs/xplat/src/content/jp/components/inputs/button-group.mdx b/docs/xplat/src/content/jp/components/inputs/button-group.mdx index 59a1da73fd..c956bb78b9 100644 --- a/docs/xplat/src/content/jp/components/inputs/button-group.mdx +++ b/docs/xplat/src/content/jp/components/inputs/button-group.mdx @@ -28,7 +28,13 @@ import buttonGroupDoNot3 from '@xplat-images/button-group/button-group-do-not-3. # ボタン グループ コンポーネント +<PlatformBlock for="Angular"> +{Platform} ボタン グループ コンポーネントは、<ApiLink type="IgxButtonDirective" label="IgxButton" /> ディレクティブを持つボタンを、水平 / 垂直配置、単一 / 複数選択、切り替えを備えたスタイル付きボタン グループに編成するために使用されます。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> {Platform} ボタン グループ コンポーネントは、<ApiLink pkg="core" type="ToggleButton" /> を、水平 / 垂直配置、単一 / 複数選択、切り替えを備えたスタイル付きボタン グループに編成するために使用されます。 +</PlatformBlock> ## ライブ デモ @@ -93,18 +99,18 @@ Button Group </PlatformBlock> -### 前提条件とバージョン互換性 - -ターゲット フレームワークでサポートされているバージョンの {ProductName} パッケージを使用してください。フレームワーク パッケージ、ボタン グループ パッケージ、テーマ パッケージを同じリリース バージョンに保ってください。 +<PlatformBlock for="React,WebComponents"> -<PlatformBlock for="WebComponents"> - -**{PackageWebComponents}** パッケージを使用する Web Components の場合は、パッケージをインストールします。 +**{PackageCommon}** パッケージを使用する {Platform} の場合は、パッケージをインストールします。 ```cmd -npm install {PackageWebComponents} +npm install {PackageCommon} ``` +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + 次に、<ApiLink pkg="core" type="ButtonGroup" /> とそのテーマ CSS をインポートし、コンポーネントを登録します。 ```ts @@ -118,12 +124,6 @@ defineComponents(IgcButtonGroupComponent); <PlatformBlock for="React"> -**igniteui-react** パッケージを使用する React の場合は、パッケージをインストールします。 - -```cmd -npm install igniteui-react -``` - 次に、ボタン グループ ラッパーとそのテーマ CSS をインポートします。 ```tsx @@ -135,7 +135,7 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; <PlatformBlock for="Blazor"> -**IgniteUI.Blazor** パッケージを使用する Blazor の場合は、次のようにボタン グループ モジュールを登録します。 +**IgniteUI.Blazor** パッケージを使用する {Platform} の場合は、次のようにボタン グループ モジュールを登録します。 ```csharp // in Program.cs file @@ -159,18 +159,22 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonGroupModule)); ng add igniteui-angular ``` -次に、NgModule アプリケーションでは `IgxButtonGroupModule` をインポートするか、コンポーネントの `imports` コレクションに `IGX_BUTTON_GROUP_DIRECTIVES` と必要なスタンドアロン コンポーネントをインポートします。 +次に、コンポーネントの `imports` コレクションに `IGX_BUTTON_GROUP_DIRECTIVES` と必要なスタンドアロン コンポーネントをインポートします。 ```ts import { IGX_BUTTON_GROUP_DIRECTIVES } from 'igniteui-angular/button-group'; import { IgxIconComponent } from 'igniteui-angular/icon'; ``` -Ignite UI for Angular の完全な紹介については、[**作業の開始**](/general/getting-started) トピックをお読みください。 +</PlatformBlock> +<PlatformBlock for="Angular"> +<ApiLink type="IgxButtonGroupComponent" label="IgxButtonGroup" /> を使用する最もシンプルな方法は次のとおりです。 </PlatformBlock> +<PlatformBlock for="React,WebComponents,Blazor"> <ApiLink pkg="core" type="ButtonGroup" /> を使用する最もシンプルな方法は次のとおりです。 +</PlatformBlock> <PlatformBlock for="WebComponents"> @@ -206,7 +210,13 @@ Ignite UI for Angular の完全な紹介については、[**作業の開始**]( ## 使用方法 +<PlatformBlock for="Angular"> +<ApiLink type="IgxButtonGroupComponent" label="IgxButtonGroup" /> を使用して、<ApiLink type="IgxButtonDirective" label="IgxButton" /> ディレクティブを使用するボタンをラップします。デフォルトでボタンを選択するには、そのボタンで `selected` 入力を設定します。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> <ApiLink pkg="core" type="ButtonGroup" /> を使用して <ApiLink pkg="core" type="ToggleButton" /> コンポーネントをラップします。デフォルトでボタンを選択するには、<ApiLink pkg="core" type="ToggleButton" member="selected" label="Selected" /> 属性を使用します。 +</PlatformBlock> <PlatformBlock for="Angular"> @@ -306,7 +316,13 @@ Ignite UI for Angular の完全な紹介については、[**作業の開始**]( ### 配置 +<PlatformBlock for="Angular"> +ボタン グループは水平および垂直レイアウトをサポートします。<ApiLink type="IgxButtonGroupComponent" member="alignment" label="Alignment" /> プロパティを使用して、グループ内のボタンの方向を設定します。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> ボタン グループは水平および垂直レイアウトをサポートします。<ApiLink pkg="core" type="ButtonGroup" member="alignment" label="Alignment" /> プロパティを使用して、グループ内のボタンの方向を設定します。 +</PlatformBlock> <PlatformBlock for="Angular"> @@ -339,7 +355,20 @@ public alignment = ButtonGroupAlignment.vertical; ### 選択 -{ProductName} <ApiLink pkg="core" type="ButtonGroup" /> の選択を構成するには、プラットフォーム固有の選択プロパティを使用します。Angular の場合は <ApiLink pkg="core" type="ButtonGroup" member="selectionMode" label="selectionMode" />、React、Web Components、Blazor の場合は <ApiLink pkg="core" type="ButtonGroup" member="selection" label="selection" /> を使用します。使用可能なモードは次のとおりです。 +{ProductName} ボタン グループの選択を構成するには、プラットフォーム固有の選択プロパティを使用します。 + +<PlatformBlock for="Angular"> +{Platform} の場合は、<ApiLink pkg="core" type="ButtonGroup" member="selectionMode" label="selectionMode" /> プロパティを使用します。使用可能なモードは次のとおりです。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents"> +{Platform} の場合は、<ApiLink pkg="core" type="ButtonGroup" member="selection" label="selection" /> プロパティを使用します。使用可能なモードは次のとおりです。 +</PlatformBlock> + +<PlatformBlock for="Blazor"> +{Platform} の場合は、<ApiLink pkg="IgniteUI.Blazor" type="IgbButtonGroup" member="selection" label="selection" /> プロパティを使用します。使用可能なモードは次のとおりです。 +</PlatformBlock> + - **single** - ボタン グループのデフォルトの選択モードです。ユーザーは単一のボタンを選択/選択解除できます。 - **single-required** - ラジオ グループの動作を模倣します。選択できるボタンは 1 つだけで、最初に選択すると、ユーザーの操作によって選択解除することはできません。 - **multiple** - グループ内の複数のボタンを選択または選択解除できます。 @@ -370,7 +399,13 @@ Angular の選択モードは `single`、`singleRequired`、`multi` です。 </PlatformBlock> +<PlatformBlock for="Angular"> +<ApiLink type="IgxButtonDirective" label="IgxButton" /> は、その `selected` 入力またはボタン グループの <ApiLink type="IgxButtonGroupComponent" member="values" label="values" /> 入力を通じて選択済みとしてマークできます。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> <ApiLink pkg="core" type="ToggleButton" /> は、<ApiLink pkg="core" type="ToggleButton" member="selected" label="Selected" /> 属性または <ApiLink pkg="core" type="ButtonGroup" /> の <ApiLink pkg="core" type="ButtonGroup" member="selectedItems" label="SelectedItems" /> 属性を通じて選択済みとしてマークできます。 +</PlatformBlock> <PlatformBlock for="WebComponents"> @@ -439,12 +474,23 @@ Angular の選択モードは `single`、`singleRequired`、`multi` です。 <DocsAside type="info"> +<PlatformBlock for="Angular"> +<ApiLink type="IgxButtonGroupComponent" member="values" label="values" /> 入力でボタン グループを初期化する場合は、各ボタンに一意の `value` を設定してください。 +</PlatformBlock> +<PlatformBlock for="React,WebComponents,Blazor"> <ApiLink pkg="core" type="ButtonGroup" /> の <ApiLink pkg="core" type="ButtonGroup" member="selectedItems" label="SelectedItems" /> プロパティを使用するには、<ApiLink pkg="core" type="ToggleButton" /> の <ApiLink pkg="core" type="ToggleButton" member="value" label="Value" /> 属性の設定が必須です。 +</PlatformBlock> </DocsAside> ### 状態 +<PlatformBlock for="Angular"> +グループ内の各ボタンは、有効および無効のバリアントをサポートし、選択済みまたは未選択の状態にできます。含まれる <ApiLink type="IgxButtonDirective" label="IgxButton" /> コンポーネントが提供する状態動作を使用します。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> グループ内の各ボタンは、有効および無効のバリアントをサポートし、選択済みまたは未選択の状態にできます。含まれる <ApiLink pkg="core" type="ToggleButton" /> コンポーネントが提供する状態動作を使用します。 +</PlatformBlock> <PlatformBlock for="Angular"> @@ -460,7 +506,13 @@ Angular の選択モードは `single`、`singleRequired`、`multi` です。 ### インタラクション状態 +<PlatformBlock for="Angular"> +グループ内の有効なボタンは、アイドル、ホバー、フォーカスのインタラクション状態をサポートします。含まれる <ApiLink type="IgxButtonDirective" label="IgxButton" /> コンポーネントが提供する状態動作を使用します。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> グループ内の有効なボタンは、アイドル、ホバー、フォーカスのインタラクション状態をサポートします。含まれる <ApiLink pkg="core" type="ToggleButton" /> コンポーネントが提供する状態動作を使用します。 +</PlatformBlock> <PlatformBlock for="Angular"> @@ -528,7 +580,7 @@ public bordersButtons: IButton[] = [ <PlatformBlock for="WebComponents"> -Web Components の場合は、個々のトグル ボタンを使用してカスタム ボタン グループを作成します。各ボタンには独自の値、アイコン、ラベル、選択状態、無効状態を定義できます。 +{Platform} の場合は、個々のトグル ボタンを使用してカスタム ボタン グループを作成します。各ボタンには独自の値、アイコン、ラベル、選択状態、無効状態を定義できます。 ボタン グループとトグル ボタン コンポーネントを登録します。 @@ -560,7 +612,7 @@ defineComponents(IgcButtonGroupComponent, IgcToggleButtonComponent, IgcIconCompo <PlatformBlock for="React"> -React の場合は、個々のトグル ボタンを使用してカスタム ボタン グループを作成します。各ボタンには独自の値、アイコン、ラベル、選択状態、無効状態を定義できます。 +{Platform} の場合は、個々のトグル ボタンを使用してカスタム ボタン グループを作成します。各ボタンには独自の値、アイコン、ラベル、選択状態、無効状態を定義できます。 ボタン グループ、トグル ボタン、アイコン コンポーネントをインポートします。 @@ -590,7 +642,7 @@ import { IgrButtonGroup, IgrToggleButton, IgrIcon } from 'igniteui-react'; <PlatformBlock for="Blazor"> -Blazor の場合は、個々のトグル ボタンを使用してカスタム ボタン グループを作成します。各ボタンには独自の値、アイコン、ラベル、選択状態、無効状態を定義できます。 +{Platform} の場合は、個々のトグル ボタンを使用してカスタム ボタン グループを作成します。各ボタンには独自の値、アイコン、ラベル、選択状態、無効状態を定義できます。 `Program.cs` でボタン グループ モジュールを登録します。 @@ -701,15 +753,40 @@ igx-buttongroup { ## プロパティ -ボタン グループのプロパティはコンポーネント API リファレンスから生成されます。 +<PlatformBlock for="Angular"> + +Angular ボタン グループは、次のプロパティを公開します。 + +| 名前 | タイプ | デフォルト | 説明 | +| --- | --- | --- | --- | +| <ApiLink type="IgxButtonGroupComponent" member="alignment" label="alignment" /> | `ButtonGroupAlignment` | `horizontal` | グループ内のボタンの方向を設定します。 | +| <ApiLink type="IgxButtonGroupComponent" member="values" label="values" /> | `IButton[]` | `[]` | グループに表示されるボタン アイテムを定義します。 | + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents"> -プロパティの行は、ドキュメントのビルド時に型付き API ソースから注入されます。 +{Platform} ボタン グループは、次のプロパティを公開します。 | 名前 | タイプ | デフォルト | 説明 | | --- | --- | --- | --- | -| <ApiLink pkg="core" type="ButtonGroup" member="alignment" label="alignment" /> | `ButtonGroupAlignment` | `horizontal` | グループ内のボタンの方向を設定します。 | -| <ApiLink pkg="core" type="ButtonGroup" member="selection" label="selection" /> | `ButtonGroupSelection` | `single` | グループ内のボタンの選択モードを設定します。 | -| <ApiLink pkg="core" type="ButtonGroup" member="selectedItems" label="selectedItems" /> | `string[]` | `[]` | 選択されているボタンの値を取得または設定します。各トグル ボタンには一意の `value` が必要です。 | +| <ApiLink type="ButtonGroup" member="alignment" label="alignment" /> | `ButtonGroupAlignment` | `horizontal` | グループ内のボタンの方向を設定します。 | +| <ApiLink type="ButtonGroup" member="selection" label="selection" /> | `ButtonGroupSelection` | `single` | グループ内のボタンの選択モードを設定します。 | +| <ApiLink type="ButtonGroup" member="selectedItems" label="selectedItems" /> | `string[]` | `[]` | 選択されているボタンの値を取得または設定します。 | + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +Blazor ボタン グループは、次のプロパティを公開します。 + +| 名前 | タイプ | デフォルト | 説明 | +| --- | --- | --- | --- | +| <ApiLink pkg="IgniteUI.Blazor" type="IgbButtonGroup" member="alignment" label="alignment" /> | `ButtonGroupAlignment` | `horizontal` | グループ内のボタンの方向を設定します。 | +| <ApiLink pkg="IgniteUI.Blazor" type="IgbButtonGroup" member="selection" label="selection" /> | `ButtonGroupSelection` | `single` | グループ内のボタンの選択モードを設定します。 | +| <ApiLink pkg="IgniteUI.Blazor" type="IgbButtonGroup" member="selectedItems" label="selectedItems" /> | `string[]` | `[]` | 選択されているボタンの値を取得または設定します。 | + +</PlatformBlock> ## スタイル設定 @@ -1004,7 +1081,7 @@ igc-toggle-button::part(toggle) { ## トラブルシューティング -{Platform} ボタン グループのトラブルシューティング ガイダンスは、一般的な選択の問題に対して問題、原因、修正のフォーマットで提供されます。 +ボタン グループを単一のトグル、フォーム フィールド、またはアクション グループとして扱う前に、このセクションで制約と一般的な判断のポイントを確認してください。 ### selectedItems でボタンが選択されないのはなぜですか? @@ -1020,16 +1097,53 @@ igc-toggle-button::part(toggle) { ## API リファレンス -{Platform} ボタン グループ API リファレンスは、コンポーネントと関連するトグル ボタン機能の完全な API サーフェスを提供します。 +{Platform} ボタン グループ API リファレンスは、コンポーネントと関連するボタン機能の完全な API サーフェスを提供します。 + +<PlatformBlock for="Angular"> +<ApiLink type="IgxButtonGroupComponent" label="IgxButtonGroup" /> +<ApiLink type="IgxButtonDirective" label="IgxButton" /> +<ApiLink type="IgxRippleDirective" label="IgxRipple" /> +<ApiLink type="IgxIconComponent" label="IgxIcon" /> +</PlatformBlock> + +<PlatformBlock for="React"> +<ApiLink pkg="core" type="ButtonGroup" /> +<ApiLink type="IgrToggleButton" label="IgrToggleButton" /> +<ApiLink type="IgrRipple" label="IgrRipple" /> +<ApiLink pkg="core" type="Icon" /> +</PlatformBlock> +<PlatformBlock for="WebComponents"> <ApiLink pkg="core" type="ButtonGroup" /> <ApiLink pkg="core" type="ToggleButton" /> -<ApiLink pkg="core" type="Ripple" /> +<ApiLink type="IgcRippleComponent" label="IgcRipple" /> <ApiLink pkg="core" type="Icon" /> +</PlatformBlock> + +<PlatformBlock for="Blazor"> +<ApiLink pkg="core" type="ButtonGroup" /> +<ApiLink pkg="IgniteUI.Blazor" type="IgbToggleButton" label="IgbToggleButton" /> +<ApiLink pkg="IgniteUI.Blazor" type="IgbRipple" label="IgbRipple" /> +<ApiLink pkg="core" type="Icon" /> +</PlatformBlock> ## 依存関係 -{Platform} ボタン グループは、プラットフォーム パッケージとそのテーマ スタイルシートが必要です。サンプルではトグル ボタン、アイコン、リップル コンポーネントも使用します。 +<PlatformBlock for="Angular"> +Angular ボタン グループには、Angular パッケージとそのテーマ スタイルシートが必要です。サンプルでは <ApiLink type="IgxButtonDirective" label="IgxButton" />、<ApiLink type="IgxIconComponent" label="IgxIcon" />、<ApiLink type="IgxRippleDirective" label="IgxRipple" /> コンポーネントも使用します。 +</PlatformBlock> + +<PlatformBlock for="React"> +React ボタン グループには、React パッケージとそのテーマ スタイルシートが必要です。サンプルでは <ApiLink type="IgrToggleButton" label="IgrToggleButton" />、<ApiLink pkg="core" type="Icon" />、<ApiLink type="IgrRipple" label="IgrRipple" /> コンポーネントも使用します。 +</PlatformBlock> + +<PlatformBlock for="WebComponents"> +Web Components ボタン グループには、Web Components パッケージとそのテーマ スタイルシートが必要です。サンプルでは <ApiLink pkg="core" type="ToggleButton" />、<ApiLink pkg="core" type="Icon" />、<ApiLink type="IgcRippleComponent" label="IgcRipple" /> コンポーネントも使用します。 +</PlatformBlock> + +<PlatformBlock for="Blazor"> +Blazor ボタン グループには、Blazor パッケージとそのテーマ スタイルシートが必要です。サンプルでは <ApiLink pkg="IgniteUI.Blazor" type="IgbToggleButton" label="IgbToggleButton" />、<ApiLink pkg="core" type="Icon" />、<ApiLink pkg="IgniteUI.Blazor" type="IgbRipple" label="IgbRipple" /> コンポーネントも使用します。 +</PlatformBlock> ## その他のリソース @@ -1040,26 +1154,22 @@ API の詳細とプロジェクト サポートについては、次の {Platfor ## 関連コンポーネント -{Platform} ボタン グループは選択可能なトグル ボタンで構成されています。グループではなく個別のトグル アクションが必要な場合は、次の関連コンポーネントを使用してください。 - -- <ApiLink pkg="core" type="ToggleButton" /> +- [Button](./button.mdx) - 選択可能なグループではなく個別のアクションが必要な場合は、Button を使用します。 ## FAQ -これらのよくある質問は、{Platform} ボタン グループの選択、コンテンツ、設定に関する一般的なシナリオをカバーします。 - <Faq> -<FaqItem question="ボタン グループはどの選択モードをサポートしていますか?"> -ボタン グループは `single`、`single-required`、`multiple` の選択モードをサポートします。必要なインタラクションに合ったモードを選択するには `selection` プロパティを使用します。 +<FaqItem question="ボタン グループで選択されるボタンを設定するにはどうすればよいですか?"> +すべてのボタン アイテムに一意の値を指定し、プラットフォーム固有の選択アイテム設定を使用して、最初に選択状態にするアイテムを指定します。一意の値により、サポートされるすべてのプラットフォームでグループが選択を一貫して追跡できます。 </FaqItem> -<FaqItem question="selectedItems でボタンを選択するにはどうすればよいですか?"> -すべての <ApiLink pkg="core" type="ToggleButton" /> に一意の `value` を割り当て、ボタン グループの `selectedItems` プロパティを通じて対応する値を設定します。 +<FaqItem question="ボタン グループでアイコンとラベルを使用できますか?"> +はい。各ボタン アイテムには、アイコン、ラベル、またはその両方を含めることができます。グループ全体でコンテンツのパターンを統一し、アイコンだけではオプションを説明できない場合は、表示ラベルまたはアクセシブル名を提供してください。 </FaqItem> -<FaqItem question="ボタン グループにアイコンを表示できますか?"> -はい。各 <ApiLink pkg="core" type="ToggleButton" /> にアイコンを追加し、グループ全体でボタン コンテンツを統一してください。 +<FaqItem question="ボタン グループを垂直に表示できますか?"> +はい。プラットフォーム固有の配置プロパティを垂直オプションに設定します。関連する選択肢を 1 行で表示する場合は、水平配置を使用します。 </FaqItem> </Faq> diff --git a/docs/xplat/src/content/jp/components/inputs/button.mdx b/docs/xplat/src/content/jp/components/inputs/button.mdx index 81967cea12..8248907655 100644 --- a/docs/xplat/src/content/jp/components/inputs/button.mdx +++ b/docs/xplat/src/content/jp/components/inputs/button.mdx @@ -1,9 +1,11 @@ --- -title: "{Platform} Button コンポーネント | {ProductName}" +title: "Button コンポーネント" description: "{Platform} Button コンポーネントの使用を開始します。{Platform} Button OnClick イベントを通じて、ボタンのバリアントを選択し、サイズを構成し、スタイルを定義し、柔軟性を獲得します。" keywords: "{Platform}, UI controls, web widgets, UI widgets, {Platform} Button Components, Infragistics, UI コントロール, web ウィジェット, UI ウィジェット, {Platform} Button コンポーネント, インフラジスティックス" -license: MIT mentionedTypes: ["Button", "ButtonBase"] +license: MIT +last_updated: 2026-08-13 +relatedComponents: ["IconButton"] _language: ja llms: description: "{Platform} Button コンポーネントを使用すると、{Platform} アプリでアクションをトリガーするクリック可能な要素を有効にできます。" @@ -11,35 +13,168 @@ llms: import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; +import Anatomy from 'igniteui-astro-components/components/mdx/Anatomy.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; +import { Image } from 'astro:assets'; +import buttonAnatomy from '@xplat-images/anatomy-content-light/button-lt-a.png'; +import buttonDo1 from '@xplat-images/button/button-do-1.png'; +import buttonDo2 from '@xplat-images/button/button-do-2.png'; +import buttonDo3 from '@xplat-images/button/button-do-3.png'; +import buttonDoNot1 from '@xplat-images/button/button-do-not-1.png'; +import buttonDoNot2 from '@xplat-images/button/button-do-not-2.png'; +import buttonDoNot3 from '@xplat-images/button/button-do-not-3.png'; + +# Button コンポーネント -# {Platform} Button (ボタン) の概要 +{Platform} Button コンポーネントを使用すると、{Platform} アプリでアクションをトリガーするクリック可能な要素を有効にできます。ボタンのバリアント、スタイル、サイズを完全に制御できます。また、Button コンポーネントでは、クリックの処理、ボタンの切り替え、必要に応じたボタンの無効化も行えます。 -<PlatformBlock for="WebComponents, Blazor"> +## ライブ デモ -{Platform} Button コンポーネントを使用すると、{Platform} アプリでアクションをトリガーするクリック可能な要素を有効にできます。ボタンのバリアントの設定方法、ラップされた要素のスタイルの構成方法、およびサイズの定義方法を完全に制御できます。Button コンポーネントは、{Platform} Button OnClick イベント、{Platform} ボタンの切り替え、{Platform} ボタンの無効化などを通じて柔軟性を提供します。 +<PlatformBlock for="Angular"> + +<Sample src="/data-entries/button-overview" height={404} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button の例" /> </PlatformBlock> -<PlatformBlock for="React"> +<PlatformBlock for="React,WebComponents,Blazor"> -{Platform} Button コンポーネントを使用すると、{Platform} アプリでアクションをトリガーするクリック可能な要素を有効にできます。ボタンのバリアントの設定方法、ラップされた要素のスタイルの構成方法、およびサイズの定義方法を完全に制御できます。Button コンポーネントは、{Platform} Button クリックされたコールバック、{Platform} ボタンの切り替え、{Platform} ボタンの無効化などを通じて柔軟性を提供します。 +<Sample src="/inputs/button/overview" height={404} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Button の例" /> </PlatformBlock> -## {Platform} Button の例 +## 構造 -<Sample src="/inputs/button/overview" height={100} alt="{Platform} Button の例" /> +{Platform} Button は、ラベルとオプションのプレフィックスおよびサフィックス コンテンツをコンポーネントのシャドウ DOM 内にレンダリングします。 -## 使用方法 +<Anatomy + class="button-anatomy" + name="Button" + description="Button コンポーネントは、オプションのプレフィックスおよびサフィックス コンテンツを持つ、操作可能なコントロールをレンダリングします。" + src={buttonAnatomy.src} + alt="Button の構造" +/> -<PlatformBlock for="WebComponents"> +<style>{` + .button-anatomy { + --igd-anatomy-padding: 64px; + } + + .button-anatomy .igd-anatomy__image { + max-width: 100%; + } + + .button-anatomy-legend { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + column-gap: 48px; + margin-bottom: 24px; + } + + .button-anatomy-legend div { + display: flex; + flex-direction: column; + gap: 8px; + } + + .button-anatomy-legend strong { + margin-bottom: 12px; + } + + .button-anatomy-legend span { + display: block; + } + + @media (max-width: 768px) { + .button-anatomy-legend { + grid-template-columns: 1fr 1fr; + row-gap: 24px; + } + } + + @media (max-width: 480px) { + .button-anatomy-legend { + grid-template-columns: 1fr; + } + } +`}</style> + +<div class="button-anatomy-legend ig-typography__body-2"> + <div> + <strong>A - Contained ボタン</strong> + <span>1. アイコン (オプション)</span> + <span>2. ラベル</span> + <span>3. コンテナー</span> + </div> + <div> + <strong>B - Outlined ボタン</strong> + <span>4. アイコン (オプション)</span> + <span>5. ラベル</span> + <span>6. コンテナー</span> + </div> + <div> + <strong>C - Flat ボタン</strong> + <span>7. アイコン (オプション)</span> + <span>8. ラベル</span> + </div> + <div> + <strong>D - Fab アイコン ボタン</strong> + <span>9. アイコン</span> + <span>10. コンテナー</span> + </div> +</div> -まず、次のコマンドを実行して {ProductName} をインストールする必要があります。 +Button は、そのコンテンツを `base` CSS パーツ内にレンダリングします。ラベルにはデフォルト スロットを使用し、ラベルの前後のオプションのコンテンツには `prefix` スロットと `suffix` スロットを使用します。 + +```text +<igc-button> +├── ::part(base) +├── prefix slot +├── default slot content +└── suffix slot +</igc-button> +``` + +## 作業の開始 + +{Platform} Button を使用するには、基本的なプロジェクトのセットアップについて <PlatformBlock for="Angular">[{ProductName} の作業の開始](../general/getting-started.mdx)</PlatformBlock><PlatformBlock for="React,WebComponents,Blazor">[{ProductName} の作業の開始](../general-getting-started.mdx)</PlatformBlock> トピックに従い、その後ターゲット プラットフォーム用にコンポーネントを登録します。 + +<PlatformBlock for="Angular"> + +**igniteui-angular** パッケージを使用する Angular の場合は、パッケージをインストールします: ```cmd -npm install {PackageWebComponents} +npm install igniteui-angular +``` + +次に、`IgxButtonDirective` をインポートし、コンポーネントの `imports` コレクションに追加します。 + +```ts +import { Component } from '@angular/core'; +import { IgxButtonDirective } from 'igniteui-angular/directives'; + +@Component({ + selector: 'app-button', + imports: [IgxButtonDirective], + template: '<button igxButton>Save changes</button>' +}) +export class ButtonComponent {} ``` +</PlatformBlock> + +<PlatformBlock for="React,WebComponents"> + +**{PackageCommon}** パッケージを使用する {Platform} の場合は、パッケージをインストールします: + +```cmd +npm install {PackageCommon} +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + 次に、以下のように、<ApiLink pkg="core" type="Button" /> とそれに必要な CSS をインポートし、そのモジュールを登録する必要があります: ```ts @@ -49,18 +184,10 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; defineComponents(IgcButtonComponent); ``` -{ProductName} の完全な概要については、[作業の開始](../general-getting-started.mdx)トピックを参照してください。 - </PlatformBlock> <PlatformBlock for="React"> -まず、次のコマンドを実行して、対応する {ProductName} npm パッケージをインストールする必要があります: - -```cmd -npm install igniteui-react -``` - 次に、以下のように、<ApiLink pkg="core" type="Button" /> と必要な CSS をインポートする必要があります: ```tsx @@ -72,7 +199,7 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; <PlatformBlock for="Blazor"> -<ApiLink pkg="core" type="Button" /> を使用する前に、次のように登録する必要があります。 +**IgniteUI.Blazor** パッケージを使用する Blazor の場合は、次のように Button モジュールを登録します: ```csharp // in Program.cs file @@ -86,15 +213,22 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonModule)); <link href="_content/IgniteUI.Blazor/themes/light/bootstrap.css" rel="stylesheet" /> ``` - </PlatformBlock> <ApiLink pkg="core" type="Button" /> の使用を開始する最も簡単な方法は次のとおりです: +<PlatformBlock for="Angular"> + +```html +<button igxButton></button> +``` + +</PlatformBlock> + <PlatformBlock for="WebComponents"> ```html -<igc-button>Click me</igc-button> +<igc-button></igc-button> ``` </PlatformBlock> @@ -115,15 +249,66 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonModule)); </PlatformBlock> -## Prefix / Suffix +## 使用方法 + +{Platform} Button は、アクションのトリガー、フォーム データの送信、または別のページへの移動に使用します。アクションに適したボタンのタイプとバリアントを選択し、必要に応じてアイコンなどのオプションのコンテンツを追加します。 + +Button のコンテンツは、そのデフォルト スロットに配置されます。アクションの目的がすべてのユーザーに明確になるように、アクションのラベルをボタンのコンテンツとして追加してください。 + +<PlatformBlock for="Angular"> + +```html +<button igxButton>Save changes</button> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrButton>Save changes</IgrButton> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-button>Save changes</igc-button> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbButton>Save changes</IgbButton> +``` + +</PlatformBlock> <ApiLink pkg="core" type="Button" /> コンポーネントの `prefix` スロットと `suffix` スロットを使用すると、ボタンのメイン コンテンツの前後に異なるコンテンツを追加できます。 +`prefix` スロットと `suffix` スロットにシンプルなテキスト、記号、絵文字を追加する場合は `<span>` 要素を、アイコンを追加する場合は <ApiLink pkg="core" type="Icon" /> コンポーネントを使用することをお勧めします。 + +<PlatformBlock for="Angular"> + +```html +<button igxButton="contained"> + <span igxButtonIcon="prefix">download</span> + Download + <span igxButtonIcon="suffix">arrow_forward</span> +</button> +``` + +</PlatformBlock> + <PlatformBlock for="React"> ```tsx <IgrButton type="button" variant="contained"> - <span slot="prefix">+</span>Click me<span slot="suffix">-</span> + <span slot="prefix">Download</span> + <IgrIcon slot="suffix" name="download"></IgrIcon> </IgrButton> ``` @@ -133,7 +318,8 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonModule)); ```html <igc-button type="button" variant="contained"> - <span slot="prefix">+</span>Click me<span slot="suffix">-</span> + <span slot="prefix">Download</span> + <igc-icon slot="suffix" name="download"></igc-icon> </igc-button> ``` @@ -143,13 +329,14 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonModule)); ```razor <IgbButton Variant="@ButtonVariant.Contained"> - <span slot="prefix">+</span>Click me<span slot="suffix">-</span> + <span slot="prefix">Download</span> + <IgbIcon slot="suffix" IconName="download"></IgbIcon> </IgbButton> ``` </PlatformBlock> -## タイプ +### タイプ <ApiLink pkg="core" type="Button" member="href" label="Href" /> 属性が設定されている場合、ボタン コンポーネントはその内部構造を [`<button>`](https://developer.mozilla.org/ja/docs/Web/HTML/Element/button) から [`<a>`](https://developer.mozilla.org/ja/docs/Web/HTML/Element/a) タイプの要素に変更します。その場合、ボタンは通常のリンクと考えることができます。<ApiLink pkg="core" type="Button" member="href" label="Href" /> 属性を設定すると、<ApiLink pkg="core" type="Button" member="rel" label="Rel" />、<ApiLink pkg="core" type="Button" member="target" label="Target" /> および <ApiLink pkg="core" type="Button" member="download" label="Download" /> 属性も設定できます。 ボタン コンポーネントが実際の [`<button>`](https://developer.mozilla.org/ja/docs/Web/HTML/Element/button) 要素を内部で使用する場合、プロパティを次のいずれかの値に設定することで、その <ApiLink pkg="core" type="Button" member="type" label="DisplayType" /> を指定できます。 @@ -158,16 +345,18 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonModule)); - `reset` - フォーム データを初期値にリセットする場合 - `button` - ウェブページのどこかにカスタム機能を備えたボタンを追加する場合 -## Button のバリアント +### バリアント -### Contained ボタン +5 種類のボタンがサポートされています。目立たせたい主要なアクションには `contained` ボタン、二次的なアクションには `outlined` ボタン、控えめなアクションには `flat` ボタン、目立たせたいメインのアクションには `floating action` ボタン (Fab)、アイコンで表されるアクションには `icon` ボタンを使用します。Icon Button では、他の 4 つのバリアントのいずれも使用できます。 -<ApiLink pkg="core" type="Button" member="variant" label="Variant" /> 属性を使用して、コンポーネント テンプレートにシンプルな contained ボタンを追加します。バリアントを設定しない場合、デフォルトでは contained に設定されることに注意してください。 +#### Contained ボタン + +<PlatformBlock for="Angular"><ApiLink type="IgxButtonDirective" label="Variant" /></PlatformBlock><PlatformBlock for="React,WebComponents,Blazor"><ApiLink pkg="core" type="Button" member="variant" label="Variant" /></PlatformBlock> 属性を使用して、コンポーネント テンプレートにシンプルな contained ボタンを追加します。バリアントを設定しない場合、デフォルトでは contained に設定されることに注意してください。 <PlatformBlock for="React"> ```tsx -<IgrButton variant="contained"><span>Contained</span></IgrButton> +<IgrButton variant="contained">Contained</IgrButton> ``` </PlatformBlock> @@ -188,16 +377,26 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonModule)); </PlatformBlock> -<Sample src="/inputs/button/contained" height={70} alt="{Platform} button contained" /> +<PlatformBlock for="Angular"> + +<Sample src="/data-entries/button-contained" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button contained" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/button/contained" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} button contained" /> -### Outlined ボタン +</PlatformBlock> + +#### Outlined ボタン -`outlined` ボタンを作成するために必要なのは、<ApiLink pkg="core" type="Button" member="variant" label="Variant" /> プロパティの値を変更することだけです。 +`outlined` ボタンを作成するために必要なのは、<PlatformBlock for="Angular"><ApiLink type="IgxButtonDirective" label="Variant" /></PlatformBlock><PlatformBlock for="React,WebComponents,Blazor"><ApiLink pkg="core" type="Button" member="variant" label="Variant" /></PlatformBlock> プロパティの値を変更することだけです: <PlatformBlock for="React"> ```tsx -<IgrButton variant="outlined"><span>Outlined</span></IgrButton> +<IgrButton variant="outlined">Outlined</IgrButton> ``` </PlatformBlock> @@ -218,16 +417,26 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonModule)); </PlatformBlock> -<Sample src="/inputs/button/outlined" height={80} alt="{Platform} button outlined" /> +<PlatformBlock for="Angular"> -### Flat ボタン +<Sample src="/data-entries/button-outlined" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button outlined" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/button/outlined" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} button outlined" /> + +</PlatformBlock> + +#### Flat ボタン 同様に、`flat` バリアントに切り替えることができます。 <PlatformBlock for="React"> ```tsx -<IgrButton variant="flat"><span>Flat</span></IgrButton> +<IgrButton variant="flat">Flat</IgrButton> ``` </PlatformBlock> @@ -248,16 +457,26 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonModule)); </PlatformBlock> -<Sample src="/inputs/button/flat" height={70} alt="{Platform} button flat" /> +<PlatformBlock for="Angular"> + +<Sample src="/data-entries/button-flat" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button flat" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/button/flat" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} button flat" /> -### Floating Action ボタン +</PlatformBlock> + +#### Floating Action ボタン -<ApiLink pkg="core" type="Button" member="variant" label="Variant" /> プロパティを `fab` に設定することで、フローティング アクション ボタンを作成できます。 +<PlatformBlock for="Angular"><ApiLink type="IgxButtonDirective" label="Variant" /></PlatformBlock><PlatformBlock for="React,WebComponents,Blazor"><ApiLink pkg="core" type="Button" member="variant" label="Variant" /></PlatformBlock> プロパティを `fab` に設定することで、フローティング アクション ボタンを作成できます: <PlatformBlock for="React"> ```tsx -<IgrButton variant="fab"><span>Fab</span></IgrButton> +<IgrButton variant="fab">Fab</IgrButton> ``` </PlatformBlock> @@ -278,17 +497,35 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbButtonModule)); </PlatformBlock> -<Sample src="/inputs/button/fab" height={70} alt="{Platform} button fab" /> +<PlatformBlock for="Angular"> -## ボタンのサイズ設定 +<Sample src="/data-entries/button-fab" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button floating action button" /> -ユーザーは、CSS 変数 `--ig-size` を使用して <ApiLink pkg="core" type="Button" /> のサイズを変更できます。次の例では、すべてのサイズ値を表示するためのラジオ ボタンをいくつか追加します。このようにして、選択されるたびにボタンの size プロパティを変更します。 +</PlatformBlock> -<PlatformBlock for="WebComponents"> +<PlatformBlock for="React,WebComponents,Blazor"> -```ts -import { defineComponents, IgcButtonComponent, IgcRadioComponent, IgcRadioGroupComponent } from 'igniteui-webcomponents'; -defineComponents(IgcButtonComponent, IgcRadioComponent, IgcRadioGroupComponent); +<Sample src="/inputs/button/fab" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} button fab" /> +</PlatformBlock> + +### 状態 + +すべてのボタンは有効と無効の両方のバリアントをサポートしているため、各 Button を無効状態で挿入することもできます。Figma では、プロパティ パネルのブール型プロパティを使用して 2 つの状態を切り替えることができます。コードでは、アクションが現在利用できない場合に `disabled` プロパティまたは属性を使用します。 + +<PlatformBlock for="Angular"> + +```html +<button igxButton="contained" [disabled]="true">Disabled</button> +``` + +<Sample src="/data-entries/button-states" height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button の状態の例" /> + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrButton variant="contained" disabled={true}>Disabled</IgrButton> ``` </PlatformBlock> @@ -296,71 +533,87 @@ defineComponents(IgcButtonComponent, IgcRadioComponent, IgcRadioGroupComponent); <PlatformBlock for="WebComponents"> ```html -<igc-radio-group id="radio-group" alignment="horizontal"> - <igc-radio name="size" value="small" label-position="after">Small</igc-radio> - <igc-radio name="size" value="medium" label-position="after" checked>Medium</igc-radio> - <igc-radio name="size" value="large" label-position="after">Large</igc-radio> -</igc-radio-group> +<igc-button variant="contained" disabled>Disabled</igc-button> ``` </PlatformBlock> -<PlatformBlock for="WebComponents"> +<PlatformBlock for="Blazor"> -```ts -this.radioGroup = document.getElementById('radio-group') as IgcRadioGroupComponent; -this.outlinedButton = document.getElementById('outlined-btn') as IgcButtonComponent; -this.flatButton = document.getElementById('flat-btn') as IgcButtonComponent; -this.containedButton = document.getElementById('contained-btn') as IgcButtonComponent; -this.fabButton = document.getElementById('fab-btn') as IgcButtonComponent; +```razor +<IgbButton Variant="@ButtonVariant.Contained" Disabled="true">Disabled</IgbButton> +``` + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/button/states" height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Button の状態の例" /> + +</PlatformBlock> + +### インタラクション状態 + +Figma では、有効なボタンは **Idle**、**Hover**、**Focused**、**Focused & Hover** の状態をサポートしており、`State` プロパティを変更することで切り替えることができます。コードでは、これらのインタラクション状態はプラットフォームの Button コンポーネントによって提供され、キーボード ユーザーのために可視のフォーカス インジケーターを維持する必要があります。 + +<PlatformBlock for="Angular"> + +```html +<button igxButton="contained" igxRipple="white" [igxRippleCentered]="true" [igxRippleDuration]="2000"> + Ripple +</button> +``` + +<Sample src="/data-entries/button-interaction-states" height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button のインタラクション状態の例" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +```html +<igc-button variant="contained">Ripple and focus states</igc-button> +``` + +<Sample src="/inputs/button/interaction-states" height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Button のインタラクション状態の例" /> + +</PlatformBlock> -this.radioGroup.addEventListener('click', (radio: any) => { - this.outlinedButton.style.setProperty('--ig-size', `var(--ig-size-${radio.target.value})`); - this.flatButton.style.setProperty('--ig-size', `var(--ig-size-${radio.target.value})`); - this.containedButton.style.setProperty('--ig-size', `var(--ig-size-${radio.target.value})`); - this.fabButton.style.setProperty('--ig-size', `var(--ig-size-${radio.target.value})`); -}); +### レイアウト テンプレート + +Contained、Outlined、Flat、および Floating Action ボタンは、柔軟なアイコンとラベルのテンプレートをサポートします。Figma では、アイコンの表示 / 非表示を `Left Icon` および `Right Icon` のブール型プロパティで切り替えることができます。Icon Button にする場合は、`Content` プロパティを `Icon` に設定します。 + +<PlatformBlock for="Angular"> + +```html +<span igxButton="outlined" igxButtonColor="white" igxButtonBackground="#72da67" igxRipple="white"> + Span button +</span> ``` +<Sample src="/data-entries/button-layout" height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button のレイアウトの例" /> + </PlatformBlock> <PlatformBlock for="React"> ```tsx -import { IgrButton, IgrRadio, IgrRadioGroup } from 'igniteui-react'; - -const [size, setSize] = useState("small"); - -const onRadioChange = (e: IgrRadioChangeEventArgs) => { - setSize(e.detail.value); -}; - -<IgrRadioGroup alignment="horizontal" style={{ display: "flex", margin: "0 auto", width: "15%" }}> - <IgrRadio name="size" value="small" labelPosition="after" checked={size === "small"} onChange={onRadioChange}> - <span>Small</span> - </IgrRadio> - <IgrRadio name="size" value="medium" labelPosition="after" onChange={onRadioChange}> - <span>Medium</span> - </IgrRadio> - <IgrRadio name="size" value="large" labelPosition="after" onChange={onRadioChange}> - <span>Large</span> - </IgrRadio> -</IgrRadioGroup> - -<div className="button-container"> - <IgrButton className={"size-" + size} variant="flat"> - <span>Flat</span> - </IgrButton> - <IgrButton className={"size-" + size} variant="contained"> - <span>Contained</span> - </IgrButton> - <IgrButton className={"size-" + size} variant="outlined"> - <span>Outlined</span> - </IgrButton> - <IgrButton className={"size-" + size} variant="fab"> - <span>Like</span> - </IgrButton> -</div> +<IgrButton variant="outlined"> + <span slot="prefix">★</span> + Save changes + <span slot="suffix">→</span> +</IgrButton> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-button variant="outlined"> + <span slot="prefix">★</span> + Save changes + <span slot="suffix">→</span> +</igc-button> ``` </PlatformBlock> @@ -368,45 +621,100 @@ const onRadioChange = (e: IgrRadioChangeEventArgs) => { <PlatformBlock for="Blazor"> ```razor -<IgbRadioGroup id="radioGroup" Alignment="ContentOrientation.Horizontal" > - <IgbRadio Value="small" LabelPosition="RadioLabelPosition.After" @onclick="OnSmallClick">Small</IgbRadio> - <IgbRadio Value="medium" LabelPosition="RadioLabelPosition.After" @onclick="OnMediumClick">Medium</IgbRadio> - <IgbRadio Value="large" LabelPosition="RadioLabelPosition.After" Checked="true" @onclick="OnLargeClick">Large</IgbRadio> -</IgbRadioGroup> +<IgbButton Variant="@ButtonVariant.Outlined"> + <span slot="prefix">★</span> + Save changes + <span slot="suffix">→</span> +</IgbButton> +``` -@code { - private SizableComponentSize SizableComponentSize = SizableComponentSize.Large; +</PlatformBlock> - protected override void OnInitialized() - { - } +<PlatformBlock for="React,WebComponents,Blazor"> - public void OnSmallClick(EventArgs e) - { - SizableComponentSize = SizableComponentSize.Small; - } +<Sample src="/inputs/button/layout" height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Button のレイアウトの例" /> - public void OnMediumClick(EventArgs e) - { - SizableComponentSize = SizableComponentSize.Medium; - } +</PlatformBlock> - public void OnLargeClick(EventArgs e) - { - SizableComponentSize = SizableComponentSize.Large; - } -} +### サイズ + +ユーザーは、CSS 変数 `--ig-size` を使用して <ApiLink pkg="core" type="Button" /> のサイズを変更できます。 + +<PlatformBlock for="WebComponents"> + +```html +<igc-button class="button-size-small" variant="contained"> + Small +</igc-button> +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrButton className="button-size-small" variant="contained"> + Small +</IgrButton> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbButton Class="button-size-small" Variant="ButtonVariant.Contained"> + Small +</IgbButton> ``` </PlatformBlock> +```css +.button-size-small { + --ig-size: var(--ig-size-small); +} +``` + 上記のコードを実装した結果は、次のようになります: -<Sample src="/inputs/button/size" height={200} alt="{Platform} Button のサイズ設定" /> +<PlatformBlock for="Angular"> + + +<Sample src="/data-entries/button-size" height={404} position="start center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button のサイズ設定の例" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/button/size" height={404} position="start center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Button のサイズ設定の例" /> + +</PlatformBlock> ### ダウンロード -<ApiLink pkg="core" type="Button" member="download" label="Download" /> プロパティを設定すると、リンクされた URL に移動する代わりに、保存するように求められます。 +<PlatformBlock for="Angular"> +<ApiLink type="IgxButtonDirective" label="Download" /> Button 属性を設定すると、リンクされた URL に移動する代わりに、保存するように求められます。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> +<PlatformBlock for="Angular"><ApiLink type="IgxButtonDirective" label="Download" /> 属性を設定すると、リンクされた URL に移動する代わりに、保存するように求められます。</PlatformBlock> +<PlatformBlock for="React,WebComponents,Blazor"><ApiLink pkg="core" type="Button" member="download" label="Download" /> プロパティを設定すると、リンクされた URL に移動する代わりに、保存するように求められます。</PlatformBlock> +</PlatformBlock> + +<PlatformBlock for="Angular"> + +```html +<button + igxButton="contained" + href="" + download="url" + target="_blank"> + Download +</button> +``` + +</PlatformBlock> <PlatformBlock for="React"> @@ -416,7 +724,7 @@ const onRadioChange = (e: IgrRadioChangeEventArgs) => { variant="contained" download="url" target="_blank" > - <span>Download</span> + Download </IgrButton> ``` @@ -446,11 +754,127 @@ const onRadioChange = (e: IgrRadioChangeEventArgs) => { </PlatformBlock> -<Sample src="/inputs/button/download" height={70} alt="{Platform} button download" /> +<PlatformBlock for="Angular"> + +<Sample src="/data-entries/button-download" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button のダウンロードの例" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/button/download" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} button download" /> + +</PlatformBlock> + +### 使用すべき場合と使用すべきでない場合 + +**使用すべき場合:** 状態を変更する、データを送信する、またはアプリケーションのコマンドをトリガーするアクションには Button を使用します。 + +**使用すべきでない場合:** アクションがアイコンのみで表され、テキスト ラベルを必要としない場合は、[Icon Button](./icon-button.mdx) を使用します。 + +<div class="table-responsive"> + <table class="table" style="width: 100%; table-layout: fixed; border-collapse: collapse; border: 1px solid #d3d3d3; margin-bottom: 24px;"> + <thead> + <tr> + <th style="width: 50%; background-color: #d3d3d3; text-align: left; padding: 16px 20px; font-size: 18px; font-weight: 500;">Do</th> + <th style="width: 50%; background-color: #d3d3d3; text-align: left; padding: 16px 20px; font-size: 18px; font-weight: 500;">Don't</th> + </tr> + </thead> + <tbody> + <tr> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={buttonDo1} alt="Button の Do 例 1" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={buttonDoNot1} alt="Button の Don't 例 1" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + </tr> + <tr> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={buttonDo2} alt="Button の Do 例 2" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={buttonDoNot2} alt="Button の Don't 例 2" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + </tr> + <tr> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={buttonDo3} alt="Button の Do 例 3" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={buttonDoNot3} alt="Button の Don't 例 3" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + </tr> + </tbody> + </table> +</div> + + +## プロパティ + +{Platform} Button は、そのコンテンツ、外観、動作を制御するためのプラットフォーム固有のプロパティを公開します。 + +<PlatformBlock for="Angular"> + +Angular Button はディレクティブとして提供され、次のプロパティを公開します。完全な型定義については API リファレンスを参照してください。 + +| 名前 | 型 | デフォルト | 説明 | +| --- | --- | --- | --- | +| <ApiLink type="IgxButtonDirective" label="variant" /> | string | `flat` | Button の視覚的なバリアントを設定します。 | +| <ApiLink type="IgxButtonDirective" label="type" /> | string | `button` | ネイティブ ボタンのタイプを設定します。 | + +</PlatformBlock> + +<PlatformBlock for="React"> + +{Platform} Button は、次のプロパティを公開します。 + +| 名前 | 型 | デフォルト | 説明 | +|--|--|--|--| +| <ApiLink type="IgrButton" member="variant" label="variant" /> | ButtonVariant | `contained` | Button の視覚的なバリアントを選択します。 | +| <ApiLink type="IgrButton" member="type" label="type" /> | string | `button` | コンポーネントがボタンとしてレンダリングされる場合に、ネイティブ ボタンのタイプを設定します。 | +| <ApiLink type="IgrButton" member="href" label="href" /> | string | — | リンク先を設定し、Button をナビゲーションに使用します。 | +| <ApiLink type="IgrButton" member="rel" label="rel" /> | string | — | 現在のドキュメントとリンク先との関係を設定します。 | +| <ApiLink type="IgrButton" member="target" label="target" /> | string | — | `href` が設定されている場合に、リンク先を開く場所を設定します。 | +| <ApiLink type="IgrButton" member="download" label="download" /> | string | — | `href` が設定されている場合に、リンクされたリソースのダウンロードをユーザーに求めます。 | + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +{Platform} Button は、次のプロパティを公開します。 + +| 名前 | 型 | デフォルト | 説明 | +| --- | --- | --- | --- | +| <ApiLink type="Button" member="variant" label="variant" /> | ButtonVariant | `contained` | Button の視覚的なバリアントを選択します。 | +| <ApiLink type="Button" member="type" label="type" /> | string | `button` | ネイティブ ボタンのタイプを設定します。 | +| <ApiLink type="Button" member="href" label="href" /> | string | — | ナビゲーションのリンク先を設定します。 | + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +Blazor Button は、次のプロパティを公開します。 + +| 名前 | 型 | デフォルト | 説明 | +| --- | --- | --- | --- | +| <ApiLink pkg="IgniteUI.Blazor" type="IgbButton" member="variant" label="variant" /> | ButtonVariant | `contained` | Button の視覚的なバリアントを選択します。 | +| <ApiLink pkg="IgniteUI.Blazor" type="IgbButton" member="type" label="type" /> | string | `button` | ネイティブ ボタンのタイプを設定します。 | +| <ApiLink pkg="IgniteUI.Blazor" type="IgbButton" member="href" label="href" /> | string | — | ナビゲーションのリンク先を設定します。 | + +</PlatformBlock> ## スタイル設定 -<ApiLink pkg="core" type="Button" /> は、スタイル設定に使用できる 3 つの CSS パーツを公開します。 +テーマ設定、CSS 変数、または CSS パーツを使用して、アプリケーションのビジュアル言語に合わせて Button をカスタマイズします。 + +### Sass テーマ + +標準の {ProductName} テーマ ワークフローを使用して、アプリケーションの他の部分と一貫性のあるスタイルで Button をカスタマイズします。 + +### CSS 変数 + +Button 要素で生成された CSS 変数を使用して、特定のインスタンスのテーマ値をオーバーライドします。バリアント固有のテーマ関数は、プライマリ テーマ パラメーターから関連するインタラクション状態の値を導出します。 + +| プライマリ プロパティ | 依存プロパティ | 説明 | +| --- | --- | --- | +| `$background` | `$hover-background`、`$focus-background`、`$active-background` | インタラクション状態ごとの Button の背景色。 | +| `$foreground` | `$hover-foreground`、`$focus-foreground`、`$active-foreground` | インタラクション状態ごとの Button のテキスト色。 | +| `$border-color` | `$hover-border-color`、`$focus-border-color`、`$active-border-color` | インタラクション状態ごとの Button のボーダー カラー。 | +| `$shadow-color` | `$resting-shadow`、`$hover-shadow`、`$focus-shadow`、`$active-shadow` | Button のシャドウの色とエレベーション。 | +| `$disabled-background` | `$disabled-foreground`、`$disabled-icon-color`、`$disabled-border-color` | 無効時の Button の色。 | + +### スタイル パーツ + +<ApiLink pkg="core" type="Button" /> は、スタイル設定に使用できる 3 つの CSS パーツを公開します: |名前|説明| |--|--| @@ -468,15 +892,202 @@ igc-button::part(base) { } ``` -<Sample src="/inputs/button/styling" height={100} alt="{Platform} Button スタイル設定の例" /> +<PlatformBlock for="Angular"> + +<Sample src="/data-entries/button-styling" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button スタイル設定の例" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/button/styling" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Button スタイル設定の例" /> + +</PlatformBlock> + +### Tailwind によるスタイル設定 + +<PlatformBlock for="Angular"> + +カスタム Tailwind ユーティリティ クラスを使用して Button をスタイル設定できます。最初に [Tailwind を設定](/themes/tailwind) してください。 + +グローバル スタイルシートの Tailwind インポートと併せて、ユーティリティ ファイルを含めます: + +```scss +@import "tailwindcss"; +@use 'igniteui-theming/tailwind/utilities/material.css'; +``` + +`light-flat-button`、`light-contained-button`、`light-outlined-button`、`light-fab-button` などのバリアント固有のクラスを使用します: + +```html +<button igxButton="contained" class="!light-contained-button ![--background:#7B9E89]"> + Contained Button +</button> +``` + +感嘆符 (`!`) は、ユーティリティ クラスが Button のデフォルト テーマより優先されるようにします。 + +<Sample src="/data-entries/button-tailwind-styling" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Button Tailwind スタイル設定の例" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +`igniteui-theming` のカスタム Tailwind ユーティリティ クラスを使用して Button をスタイル設定できます。最初に [Tailwind を設定](/themes/tailwind) してから、グローバル スタイルシートに Ignite UI ユーティリティをインポートします: + +```css +@import "tailwindcss"; +@import "igniteui-theming/tailwind/utilities/material.css"; +``` + +<PlatformBlock for="React"> + +```jsx +<IgrButton className="!light-contained-button ![--background:#7B9E89]">Contained Button</IgrButton> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-button class="!light-contained-button ![--background:#7B9E89]">Contained Button</igc-button> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbButton Class="!light-contained-button ![--background:#7B9E89]">Contained Button</IgbButton> +``` + +</PlatformBlock> + +感嘆符 (`!`) は、Tailwind ユーティリティを Button のデフォルト テーマ スタイルより優先させます。 + +<Sample src="/inputs/button/tailwind-styling" height={212} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Button Tailwind スタイル設定の例" /> + +</PlatformBlock> + +## アクセシビリティ + +{Platform} Button は、アクションのための、また `href` が設定されている場合はナビゲーションのためのインタラクティブなコントロールです。 +コマンドにはネイティブのボタン動作を使用し、ナビゲーションにはリンクの動作を維持してください。 + +### キーボード インタラクション + +Button は、レンダリングされるネイティブ コントロールのキーボード動作を使用します。無効な Button はインタラクティブではなく、`href` を持つ Button はコマンド ボタンではなくリンクとしてレンダリングされます。 + +| キー | アクション | +| -- | -- | +| Tab / Shift+Tab | Button がキーボードでフォーカス可能な場合、Button にフォーカスを移動する、または Button からフォーカスを外します。 | +| Enter / Space | フォーカスされたコマンド Button をアクティブ化します。リンクとして使用される Button は Enter でアクティブ化されます。 | + +### スクリーン リーダー / ARIA + +Button は、コマンド アクションの場合はネイティブの `button` を、`href` が設定されている場合は `a` 要素をレンダリングします。 +ネイティブ要素が適切なロールとキーボード セマンティクスを提供します。 + +<PlatformBlock for="WebComponents, React, Blazor"> + +- Button に意味のあるテキストが含まれている場合、その表示コンテンツがアクセシブル名として使用されます。 +- アイコンのみの Button には、`aria-label` または他のアクセシブルな名前付けの仕組みを提供してください。 +- 無効な Button は、レンダリングされたネイティブ コントロールを通じて無効状態を公開します。 +- Button のクリック イベント ハンドラーはアプリケーションのアクションを実行するものであり、Button のアクセシブル名、ロール、状態を置き換えるものではありません。 + +</PlatformBlock> + +<PlatformBlock for="Angular"> + +- Button はネイティブの `button` または `a` 要素を使用するため、支援技術は対応するネイティブのロールとキーボード セマンティクスを受け取ります。 +- アイコンのみの Button には、`aria-label` または他のアクセシブルな名前付けの仕組みを提供してください。 +- 無効な Button はキーボードでのインタラクティブ操作に対応しません。 +- クリック イベント ハンドラーはアプリケーションのアクションを実行します。アクションが表示コンテンツやネイティブ属性から伝わらない場合は、アクセシブル名と状態を別途追加してください。 + +</PlatformBlock> + +### アクセシビリティ準拠 + +このトピックは、製品レベルの WCAG、Section 508、または EN 301 549 への適合を主張するものではありません。レンダリングされた Button とその周囲のアプリケーションを、対象プロジェクトに適用されるアクセシビリティ要件に照らして検証してください。 + +| 基準 | コンポーネントの準拠方法 | +| -- | -- | +| [2.1.1 キーボード](https://www.w3.org/WAI/WCAG21/Understanding/keyboard) | ネイティブのコマンド ボタンはキーボードによるアクティブ化をサポートし、`href` を持つ Button はネイティブのリンクのアクティブ化を使用します。 | +| [4.1.2 名前、役割、値](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value) | レンダリングされたネイティブ要素がロールと状態のセマンティクスを提供します。Button の表示コンテンツが意味のあるものである場合、それがアクセシブル名になります。 | +| [2.4.4 リンクの目的](https://www.w3.org/WAI/WCAG21/Understanding/link-purpose-in-context) | `href` が設定されている場合、Button はナビゲーション リンクになります。リンク先または目的を識別できる名前を提供してください。 | + +ユーザー側の責任: + +- すべての Button、特にアイコンのみの Button に、意味のあるアクセシブル名を付けてください。 +- アクションにはコマンド Button を、ナビゲーションには `href` を使用してください。一方をもう一方で模倣しないでください。 +- アクションや状態を伝える手段として、色、ホバー、フォーカスのスタイルのみに頼らないでください。 +- Button のテーマをカスタマイズする際は、十分なコントラストと可視のフォーカス インジケーターを維持してください。 + +## トラブルシューティング + +Button をコマンド、ナビゲーション リンク、またはフォーム コントロールとして扱う前に、このセクションで制約と一般的な判断のポイントを確認してください。 + +### Button がリンクのように動作するのはなぜですか? + +`href` が設定されている場合、Button はコマンド アクションではなくナビゲーションに使用されます。コントロールが URL への移動ではなくアプリケーション ロジックをトリガーする必要がある場合は、`href` を削除してください。 + +### Button がキーボードでフォーカスできないのはなぜですか? + +Button が無効になっていないか、または周囲のアプリケーションがフォーカス動作を変更していないかを確認してください。キーボード ナビゲーションで利用できる必要があるアクションには、フォーカス可能な Button を使用してください。 + +### 既知の制限 + +Button には、プラットフォームに依存しない次の制限があります: + +- すべてのアクションには、テキスト ラベルまたは他のアクセシブルな名前付けの仕組みを使用してください。ラベルのないアイコンのみの Button は、それ自体ではその目的を伝えません。 +- `href` を設定すると、Button はアクション コントロールからナビゲーション コントロールに変わります。アイコンのみのアクションには [Icon Button](./icon-button.mdx) を使用し、そのアクセシブル名を別途検証してください。 +- Button の視覚的な外観は、周囲のアプリケーションのアクションが利用可能または有効かどうかを決定するものではありません。その状態とフィードバックはアプリケーション ロジックが提供する必要があります。 ## API リファレンス -<ApiLink pkg="core" type="Button" /><br /> -<ApiLink pkg="core" type="RadioGroup" /><br /> -<ApiLink pkg="core" type="Radio" /><br /> +{Platform} Button API リファレンスには、対象プラットフォーム向けの検証済みの完全な API サーフェスが記載されています。 +<PlatformBlock for="Angular"> +<ApiLink type="IgxButtonDirective" label="IgxButton" /> +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> +<ApiLink pkg="core" type="Button" /> +</PlatformBlock> + +## 依存関係 + +<PlatformBlock for="Angular"> +{Platform} Button には、対応する {Platform} パッケージとテーマ スタイルシートが必要です。サイズ設定の例では、<ApiLink pkg="core" type="Radio" /> および <ApiLink type="IgxRadioGroupDirective" label="IgxRadioGroup" /> コンポーネントも使用しています。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> +{Platform} Button には、対応する {Platform} パッケージとテーマ スタイルシートが必要です。サイズ設定の例では、<ApiLink pkg="core" type="Radio" /> および <ApiLink pkg="core" type="RadioGroup" /> コンポーネントも使用しています。 +</PlatformBlock> ## その他のリソース +次のリソースでは、{Platform} Button に関する追加のガイダンスとプロジェクトのサポートを提供します。 + - [{ProductName} **フォーラム (英語)**]({ForumsLink}) - [{ProductName} **GitHub (英語)**]({GithubLink}) + +## 関連コンポーネント + +{Platform} Button は、アクションに特別な表現が必要な場合に、関連コンポーネントと組み合わせて使用されることが一般的です。 + +- [Icon Button](./icon-button.mdx) は、アイコンのみのアクションを対象としています。 + +## FAQ + +<Faq> + <FaqItem question="アイコンのみのアクションにはどのコンポーネントを使用すればよいですか?" indicatorPosition="end"> + [Icon Button](./icon-button.mdx) コンポーネントを使用し、アクションのアクセシブル名を提供してください。 + </FaqItem> + <FaqItem question="Button を無効にするにはどうすればよいですか?" indicatorPosition="end"> + 検証済みの `disabled` プロパティを設定して、Button を利用不可にし、アクティブ化されないようにします。 + </FaqItem> + <FaqItem question="Button のサイズを変更するにはどうすればよいですか?" indicatorPosition="end"> + プラットフォームでサポートされているサイズ設定オプション、または `--ig-size` CSS 変数を使用して、Button の密度をカスタマイズします。 + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/jp/components/inputs/switch.mdx b/docs/xplat/src/content/jp/components/inputs/switch.mdx index c02ed330b4..e288d70b3f 100644 --- a/docs/xplat/src/content/jp/components/inputs/switch.mdx +++ b/docs/xplat/src/content/jp/components/inputs/switch.mdx @@ -1,9 +1,11 @@ --- -title: "{Platform} Switch コンポーネント – {ProductName}" +title: "Switch" description: "{ProductName} Switch コンポーネントを使用すると、開発者はアプリケーション内でバイナリのオン/オフまたは true/false のデータ入力関数を使用できます。" -keywords: "{ProductName}, UI controls, {Platform} widgets, web widgets, UI widgets, {Platform}, Native {Platform} Components Suite, Native {Platform} Controls, Native {Platform} Components Library, {Platform} Switch components, {Platform} Switch controls, UI コントロール, {Platform} ウィジェット, web ウィジェット, UI ウィジェット, ネイティブ {Platform} コンポーネント スイート, ネイティブ {Platform} コントロール, ネイティブ {Platform} コンポーネント ライブラリ, {Platform} Switch コンポーネント, {Platform} Switch コントロール" -license: MIT +keywords: "{ProductName}, UI controls, {Platform} widgets, web widgets, UI widgets, {Platform}, Native {Platform} Components Suite, Native {Platform} Controls, Native {Platform} Components Library, {Platform} Switch components, {Platform} Switch controls" mentionedTypes: ["Switch"] +relatedComponents: [Checkbox, ToggleButton] +license: MIT +last_updated: "2026-08-31" _language: ja llms: description: "{ProductName} Switch コンポーネントは、iOS のスイッチ コンポーネントと同様に動作するバイナリ選択の選択コンポーネントです。" @@ -12,35 +14,97 @@ import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro' import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; +import Anatomy from 'igniteui-astro-components/components/mdx/Anatomy.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; +import { Image } from 'astro:assets'; +import switchAnatomy from '@xplat-images/anatomy-content-light/switch-lt-a.png'; +import switchDo from '@xplat-images/switch/switch-do.png'; +import switchDoNot from '@xplat-images/switch/switch-do-not.png'; +# Switch コンポーネント +{ProductName} Switch コンポーネントは、iOS のスイッチ コンポーネントと同様に動作するバイナリ選択の選択コンポーネントです。 -# {Platform} Switch (スイッチ) +## ライブ デモ -{ProductName} Switch コンポーネントは、iOS のスイッチ コンポーネントと同様に動作するバイナリ選択の選択コンポーネントです。 +<PlatformBlock for="Angular"> -## {Platform} Switch の例 +<Sample src="/data-entries/switch-overview" height={500} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch Example" /> -<Sample src="/inputs/switches/overview" height={100} alt="{Platform} Switch の例" /> +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> +<Sample src="/inputs/switches/overview" height={500} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch Example" /> +</PlatformBlock> +## 構造 -## 使用方法 +{Platform} Switch には、バイナリ状態を変更するコントロールと、オプションのラベルが含まれています。 + +<Anatomy + class="switch-anatomy" + name="Switch" + description="The Switch component contains a control for changing a binary state and an optional label." + src={switchAnatomy.src} + alt="Switch anatomy" +/> + +<style>{` + .switch-anatomy { + --igd-anatomy-padding: 64px 32px; + } + + .switch-anatomy .igd-anatomy__image { + max-width: 142.5px; + } +`}</style> + +<span class="ig-typography__body-2" style="display: block; margin-bottom: 24px;"><strong>1. トラック:</strong> オンとオフの状態間のスイッチのパスを示します。<br /> +<strong>2. つまみ:</strong> 現在の状態を変更します。<br /> +<strong>3. ラベル (オプション):</strong> スイッチが制御する内容を説明します。</span> + +以下の図は、{Platform} Switch の論理構造を示しています。コントロールはバイナリ状態を管理し、オプションのラベルはスイッチによって制御される設定を説明します。 + +```text +Switch +├── Control +└── Label (optional) +``` + +## 作業の開始 + +{Platform} Switch を使用するには、基本的なプロジェクト設定について <PlatformBlock for="Angular">[{ProductName} の作業の開始](../general/getting-started.mdx)</PlatformBlock><PlatformBlock for="React,WebComponents,Blazor">[{ProductName} の作業の開始](../general-getting-started.mdx)</PlatformBlock> トピックに従ってから、ターゲット プラットフォーム用にコンポーネントを登録します。 <ApiLink pkg="core" type="Switch" /> コンポーネントにより、オン/オフ状態を切り替えることができます。デフォルトのスタイル設定はマテリアル デザイン ガイドラインの選択コントロールの仕様に基づきます。 +<PlatformBlock for="Angular"> -<PlatformBlock for="WebComponents"> +**igniteui-angular** パッケージを使用する Angular では、パッケージをインストールします。 +```cmd +npm install igniteui-angular +``` -まず、次のコマンドを実行して {ProductName} をインストールする必要があります: +次に、`IgxSwitchComponent` をインポートします。 + +```ts +import { IgxSwitchComponent } from 'igniteui-angular/switch'; +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +**{PackageWebComponents}** パッケージを使用する Web Components では、パッケージをインストールします。 ```cmd npm install {PackageWebComponents} ``` -次に、以下のように、<ApiLink pkg="core" type="Switch" /> と必要な CSS をインポートする必要があります: +次に、<ApiLink pkg="core" type="Switch" /> と、そのテーマ CSS をインポートし、コンポーネントを登録します。 ```ts import { defineComponents, IgcSwitchComponent } from "igniteui-webcomponents"; @@ -49,23 +113,17 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; defineComponents(IgcSwitchComponent); ``` -{ProductName} の完全な概要については、[作業の開始](../general-getting-started.mdx)トピックを参照してください。 - - </PlatformBlock> - - <PlatformBlock for="React"> - -まず、次のコマンドを実行して、対応する {ProductName} npm パッケージをインストールする必要があります: +**igniteui-react** パッケージを使用する React では、パッケージをインストールします。 ```cmd npm install igniteui-react ``` -次に、以下のように、<ApiLink pkg="core" type="Switch" /> と必要な CSS をインポートする必要があります: +次に、Switch ラッパーとそのテーマ CSS をインポートします。 ```tsx import { IgrSwitch } from 'igniteui-react'; @@ -74,14 +132,9 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; </PlatformBlock> - - <PlatformBlock for="Blazor"> - - -まず、次のコマンドを実行して {ProductName} をインストールする必要があります: - +**IgniteUI.Blazor** パッケージを使用する Blazor では、次のように Switch モジュールを登録します。 ```csharp // in Program.cs file @@ -89,17 +142,23 @@ import 'igniteui-webcomponents/themes/light/bootstrap.css'; builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); ``` -また、追加の CSS ファイルをリンクして、スタイルを <ApiLink pkg="core" type="Switch" /> コンポーネントに適用する必要があります。以下は、**Blazor Web Assembly** プロジェクトの **wwwroot/index.html** ファイルまたは **Blazor Server** プロジェクトの **Pages/_Host.cshtml** ファイルに配置する必要があります: +次に、**Blazor WebAssembly** プロジェクトの場合は **wwwroot/index.html** ファイルに、**Blazor Server** プロジェクトの場合は **Pages/_Host.cshtml** ファイルに、追加の CSS ファイルをリンクします。 ```razor <link href="_content/IgniteUI.Blazor/themes/light/bootstrap.css" rel="stylesheet" /> ``` - </PlatformBlock> +<ApiLink pkg="core" type="Switch" /> の使用を開始する最も簡単な方法は次のとおりです。 + +<PlatformBlock for="Angular"> + +```html +<igx-switch [checked]="true">Simple switch</igx-switch> +``` -<ApiLink pkg="core" type="Switch" /> の使用を開始する最も簡単な方法は次のとおりです: +</PlatformBlock> <PlatformBlock for="WebComponents"> @@ -125,20 +184,32 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); </PlatformBlock> +<PlatformBlock for="Blazor"> + <DocsAside type="warning" title="警告"> -<ApiLink pkg="core" type="Switch" /> コンポーネントは標準の `<form>` 要素では機能しません。代わりに `Form` を使用してください。 +<ApiLink pkg="core" type="Switch" /> コンポーネントは、Blazor の標準 HTML `<form>` 要素では機能しません。代わりに Blazor の `EditForm` コンポーネントを使用してください。 </DocsAside> -## 例 +</PlatformBlock> + +## 使用方法 + +{Platform} Switch は、ユーザーが状態を変更するとすぐに反映される設定用のバイナリ選択コントロールとして使用します。 + +以下の例は、基本的な Switch の構成を示しています。スイッチに意味のあるラベルを付けるには、開始タグと終了タグの間にテキストを配置するだけです。 -### ラベル +<PlatformBlock for="Angular"> -スイッチに意味のあるラベルを付けるには、開始タグと終了タグの間にテキストを配置するだけです。 +```html +<igx-switch>Accept terms</igx-switch> +``` + +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<IgrSwitch><span>Label</span></IgrSwitch> +<IgrSwitch>Accept terms</IgrSwitch> ``` </PlatformBlock> @@ -146,7 +217,7 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="WebComponents"> ```html -<igc-switch>Label</igc-switch> +<igc-switch>Accept terms</igc-switch> ``` </PlatformBlock> @@ -154,17 +225,24 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="Blazor"> ```razor -<IgbSwitch>Label</IgbSwitch> +<IgbSwitch>Accept terms</IgbSwitch> ``` </PlatformBlock> -スイッチの <ApiLink pkg="core" type="Switch" member="labelPosition" label="LabelPosition" /> 属性を設定することにより、スイッチの切り替えの前または後にラベルを配置するかどうかを指定できます。許可される値は、`before` と `after` (デフォルト) です。 +<ApiLink pkg="core" type="Switch" member="required" label="required" /> プロパティを使用して、スイッチを必須としてマークできます。 + +<PlatformBlock for="Angular"> +```html +<igx-switch [required]="true">Label</igx-switch> +``` + +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<IgrSwitch aria-labelledby="switchLabel" labelPosition="before" ><span id="switch-label">Label</span></IgrSwitch> +<IgrSwitch required={true}></IgrSwitch> ``` </PlatformBlock> @@ -172,7 +250,7 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="WebComponents"> ```html -<igc-switch label-position="before">Label</igc-switch> +<igc-switch required></igc-switch> ``` </PlatformBlock> @@ -180,18 +258,24 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="Blazor"> ```razor -<IgbSwitch LabelPosition="@ToggleLabelPosition.Before">Label</IgbSwitch> +<IgbSwitch Required="true" /> ``` </PlatformBlock> -スイッチには、スイッチの外部の要素でラベルを付けることもできます。この場合、ユーザーはニーズに応じてラベルの位置とスタイルを完全に制御できます。 +<ApiLink pkg="core" type="Switch" member="invalid" label="invalid" /> プロパティを使用して、スイッチを無効としてマークできます。 + +<PlatformBlock for="Angular"> +```html +<igx-switch [invalid]="true">Label</igx-switch> +``` + +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<span id="switch-label">Label</span> -<IgrSwitch aria-labelledby="switchLabel"></IgrSwitch> +<IgrSwitch invalid={true}></IgrSwitch> ``` </PlatformBlock> @@ -199,8 +283,7 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="WebComponents"> ```html -<span id="switch-label">Label</span> -<igc-switch aria-labelledby="switch-label"></igc-switch> +<igc-switch invalid></igc-switch> ``` </PlatformBlock> @@ -208,25 +291,43 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="Blazor"> ```razor -<span id="switch-label>Label</span> -<IgbSwitch AriaLabelledBy="switch-label" /> +<IgbSwitch Invalid="true" /> ``` </PlatformBlock> -<Sample src="/inputs/switches/label" height={100} alt="{Platform} Avatar の例" /> +### インタラクション状態 + +Switch は `Enabled` または `Disabled` 状態で挿入できます。`Enabled` 状態では、スイッチは `Hover`、`Focused`、および `Focused & Hover` の状態もサポートします。 + +<PlatformBlock for="Angular"> + +<Sample src="/data-entries/switch-enabled" height={316} position="start center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch interaction states example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> +<Sample src="/inputs/switches/enabled" height={316} position="start center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch interaction states example" /> +</PlatformBlock> +### 無効状態 -### チェック済み +スイッチの状態を `Disabled` に設定して、ユーザーの操作を許可しないようにすることもできます。この状態を設定するには、<ApiLink pkg="core" type="Switch" member="disabled" label="disabled" /> 属性を使用できます。 -スイッチをオンに切り替えるには、<ApiLink pkg="core" type="Switch" member="checked" label="checked" /> 属性を使用できます。 +<PlatformBlock for="Angular"> + +```html +<igx-switch [disabled]="true">Label</igx-switch> +``` + +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<IgrSwitch checked={true}></IgrSwitch> +<IgrSwitch disabled={true}></IgrSwitch> ``` </PlatformBlock> @@ -234,7 +335,7 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="WebComponents"> ```html -<igc-switch checked></igc-switch> +<igc-switch disabled></igc-switch> ``` </PlatformBlock> @@ -242,24 +343,43 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="Blazor"> ```razor -<IgbSwitch Checked="true" /> +<IgbSwitch Disabled="true" /> ``` </PlatformBlock> -<Sample src="/inputs/switches/checking" height={100} alt="{Platform} Switch の例" /> +<PlatformBlock for="Angular"> +<Sample src="/data-entries/switch-disabled" height={212} position="start" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch Disabled Example" /> +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +<Sample src="/inputs/switches/disabled" height={212} position="start" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch Disabled Example" /> + +</PlatformBlock> + +### オン/オフ状態 + +Switch は `On` または `Off` の状態に設定して、設定が有効か無効かを示すことができます。 + +<PlatformBlock for="Angular"> +```html +<igx-switch [checked]="true">On</igx-switch> +<igx-switch [checked]="false">Off</igx-switch> +``` -### 必須 +<Sample src="/data-entries/switch-selected" height={250} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch on and off states example" /> -<ApiLink pkg="core" type="Switch" member="required" label="required" /> 属性を使用して、スイッチを必須としてマークできます。 +</PlatformBlock> <PlatformBlock for="React"> ```tsx -<IgrSwitch required={true}></IgrSwitch> +<IgrSwitch checked={true}>On</IgrSwitch> +<IgrSwitch checked={false}>Off</IgrSwitch> ``` </PlatformBlock> @@ -267,7 +387,8 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="WebComponents"> ```html -<igc-switch required></igc-switch> +<igc-switch checked>On</igc-switch> +<igc-switch>Off</igc-switch> ``` </PlatformBlock> @@ -275,19 +396,43 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="Blazor"> ```razor -<IgbSwitch Required="true" /> +<IgbSwitch Checked="true">On</IgbSwitch> +<IgbSwitch Checked="false">Off</IgbSwitch> ``` </PlatformBlock> -### 無効 +<PlatformBlock for="React,WebComponents,Blazor"> -<ApiLink pkg="core" type="Switch" member="invalid" label="invalid" /> 属性を使用して、スイッチを無効としてマークできます。 +<Sample src="/inputs/switches/selected" height={250} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch on and off states example" /> + +</PlatformBlock> + +### レイアウト + +スイッチの <ApiLink pkg="core" type="Switch" member="labelPosition" label="LabelPosition" /> プロパティを設定することにより、スイッチの切り替えの前または後にラベルを配置するかどうかを指定できます。許可される値は、`before` と `after` (デフォルト) です。 + +<PlatformBlock for="Angular"> +```html +<igx-switch labelPosition="before">Label</igx-switch> +``` + +<Sample src="/data-entries/switch-layout" height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch layout example" /> + +</PlatformBlock> + +<PlatformBlock for="React"> + +```tsx +<IgrSwitch aria-labelledby="switch-label" labelPosition="before"><span id="switch-label">Label</span></IgrSwitch> +``` + +</PlatformBlock> <PlatformBlock for="WebComponents"> ```html -<igc-switch invalid></igc-switch> +<igc-switch label-position="before">Label</igc-switch> ``` </PlatformBlock> @@ -295,19 +440,26 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="Blazor"> ```razor -<IgbSwitch Invalid="true" /> +<IgbSwitch LabelPosition="@ToggleLabelPosition.Before">Label</IgbSwitch> ``` </PlatformBlock> -### オフ +<PlatformBlock for="React,WebComponents,Blazor"> -スイッチをオフにするには、<ApiLink pkg="core" type="Switch" member="disabled" label="disabled" /> 属性を使用できます。 +<Sample src="/inputs/switches/layout" height={212} position="start center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch layout example" /> + +</PlatformBlock> + +スイッチには、スイッチの外部の要素でラベルを付けることもできます。この場合、ユーザーはニーズに応じてラベルの位置とスタイルを完全に制御できます。 <PlatformBlock for="React"> ```tsx -<IgrSwitch disabled="true"></IgrSwitch> +<> + <span id="switch-label">Label</span> + <IgrSwitch aria-labelledby="switch-label"></IgrSwitch> +</> ``` </PlatformBlock> @@ -315,7 +467,8 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="WebComponents"> ```html -<igc-switch disabled></igc-switch> +<span id="switch-label">Label</span> +<igc-switch aria-labelledby="switch-label"></igc-switch> ``` </PlatformBlock> @@ -323,28 +476,57 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); <PlatformBlock for="Blazor"> ```razor -<IgbSwitch Disabled="true" /> +<span id="switch-label">Label</span> +<IgbSwitch AriaLabelledBy="switch-label" /> ``` </PlatformBlock> -<Sample src="/inputs/switches/disabled" height={100} alt="{Platform} Switch の例" /> +### 使用すべき場合と使用すべきでない場合 +**使用する場合:** ユーザーが変更するとすぐに反映されるオン/オフの設定には Switch を使用します。 +<PlatformBlock for="Angular"> +**使用しない場合:** ユーザーが後でフォームを送信するために 1 つ以上のオプションを選択する場合は [Checkbox](../checkbox.mdx) を使用し、コントロールがアクションまたは切り替え可能なコマンドを表す場合は [Button](./button.mdx) を使用します。 -### フォーム +</PlatformBlock> -`Form` でスイッチを使用する場合は、<ApiLink pkg="core" type="Switch" member="name" label="name" /> と <ApiLink pkg="core" type="Switch" member="value" label="value" /> の属性を使用できます。 +<PlatformBlock for="React,WebComponents,Blazor"> -<PlatformBlock for="React"> - -```tsx -<IgrSwitch name="wifi" value="enabled"></IgrSwitch> -``` +**使用しない場合:** ユーザーが後でフォームを送信するために 1 つ以上のオプションを選択する場合は [Checkbox](./checkbox.mdx) を使用し、コントロールがアクションまたは切り替え可能なコマンドを表す場合は [Button](./button.mdx) を使用します。 </PlatformBlock> +<div class="table-responsive"> + <table class="table" style="width: 100%; table-layout: fixed; border-collapse: collapse; border: 1px solid #d3d3d3; margin-bottom: 24px;"> + <thead> + <tr> + <th style="width: 50%; background-color: #d3d3d3; text-align: left; padding: 16px 20px; font-size: 18px; font-weight: 500;">Do</th> + <th style="width: 50%; background-color: #d3d3d3; text-align: left; padding: 16px 20px; font-size: 18px; font-weight: 500;">Don't</th> + </tr> + </thead> + <tbody> + <tr> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={switchDo} alt="Switch used for an immediate on/off setting" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + <td style="border: 1px solid #d3d3d3; padding: 16px 20px;"><Image src={switchDoNot} alt="Switch used for selecting options or representing an action" class="responsive-img" style="display: block; width: 100%; max-width: 100%; height: auto;" /></td> + </tr> + </tbody> + </table> +</div> + +## プロパティ + +| 名前 | タイプ | デフォルト | 説明 | +| --- | --- | --- | --- | +| <ApiLink pkg="core" type="Switch" member="checked" label="checked" /> | `boolean` | `false` | スイッチがオンかどうかを取得または設定します。 | +| <ApiLink pkg="core" type="Switch" member="disabled" label="disabled" /> | `boolean` | `false` | スイッチが無効かどうかを取得または設定します。 | +| <ApiLink pkg="core" type="Switch" member="invalid" label="invalid" /> | `boolean` | `false` | スイッチが無効 (invalid) かどうかを取得または設定します。 | +| <ApiLink pkg="core" type="Switch" member="labelPosition" label="labelPosition" /> | `ToggleLabelPosition` | `after` | コントロールに対するラベルの位置を設定します。 | +| <ApiLink pkg="core" type="Switch" member="name" label="name" /> | `string` | `-` | スイッチがフォームで送信されるときに使用される名前を設定します。 | +| <ApiLink pkg="core" type="Switch" member="required" label="required" /> | `boolean` | `false` | スイッチが必須かどうかを取得または設定します。 | +| <ApiLink pkg="core" type="Switch" member="value" label="value" /> | `string` | `-` | スイッチがフォームで送信されるときに使用される値を設定します。 | + <PlatformBlock for="WebComponents"> ```html @@ -363,36 +545,267 @@ builder.Services.AddIgniteUIBlazor(typeof(IgbSwitchModule)); ## スタイル設定 -<ApiLink pkg="core" type="Switch" /> コンポーネントは、いくつかの CSS パーツを公開して、スタイルを完全に制御できるようにします。 +{Platform} Switch は、CSS パーツと CSS 変数を使用して、トラック、つまみ、およびラベルのスタイルを設定します。 + +<PlatformBlock for="Angular"> + +### Sass テーマ設定 + +スイッチのスタイル設定を開始するには、すべてのテーマ関数と `tokens()` ミックスインがエクスポートされる `index` ファイルをインポートします。 + +```scss +@use "igniteui-angular/theming" as *; +``` + +次に、<ApiLink kind="sass" module="themes" type="function-switch-theme" label="switch-theme" code={true} /> を拡張する新しいテーマを作成します。`$thumb-off-color` と `$thumb-on-color` を指定するだけで、テーマがそれらから残りの色を生成するため、完全にスタイル設定されたスイッチを取得できます。 + +```scss +$custom-switch-theme: switch-theme( + $thumb-off-color: #7cadd5, + $thumb-on-color: #ecaa53, +); +``` + +最後に、カスタム テーマをアプリケーションに含めます。 + +```scss +:host { + @include tokens($custom-switch-theme); +} +``` + +<Sample src="/data-entries/switch-styling" height={500} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch styling example" /> + +### Tailwind でのスタイル設定 + +Ignite UI Tailwind ユーティリティ クラスを使用してスイッチのスタイルを設定できます。まず [Tailwind をセットアップ](/themes/misc/tailwind-classes) してから、グローバル スタイルシートにユーティリティ ファイルをインポートします。 + +```scss +@import "tailwindcss"; +@use 'igniteui-theming/tailwind/utilities/material.css'; +``` + +対応するテーマには `light-switch` または `dark-switch` を使用し、任意のプロパティで生成された CSS 変数をオーバーライドします。プロパティの完全な一覧は、<ApiLink kind="sass" module="themes" type="function-switch-theme" label="IgxSwitch Theme" /> を参照してください。 + +```html +<igx-switch + class="!light-switch ![--thumb-on-color:#FF4E00]" + [checked]="true"> + Label +</igx-switch> +``` + +感嘆符 (`!`) は、コンポーネントのテーマよりも優先されるようにユーティリティ クラスを重要にします。 + +<Sample src="/data-entries/switch-tailwind-styling" height={450} position="center" noBorder={false} noBackground={false} spacing="md" alt="Angular Switch Tailwind styling example" /> + +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> + +### Sass テーマ設定 + +{ProductName} テーマ システムを使用して、アプリケーションの他の部分と一貫性のある Switch のスタイルを設定します。 + +カスタム Switch テーマを作成する前に、テーマ関数をインポートします。 + +```scss +@use "igniteui-theming" as *; +``` + +`switch-theme` を使用してテーマを作成し、それをグローバル スタイルシートに含めます。トラックとつまみのパラメーターは、関連するインタラクション状態の色のベースとして使用されます。 + +```scss +$custom-switch: switch-theme( + $track-on-color: #57a5cd, +); + +igc-switch { + @include switch($custom-switch); +} +``` + +同じテーマが Web Components に直接適用され、React および Blazor ラッパーによってレンダリングされる基になる `igc-switch` 要素にも適用されます。 + +### CSS 変数 + +以下の CSS 変数を使用して、Switch の色とインタラクション状態をカスタマイズします。これらを Switch 要素に設定して、そのトラック、つまみ、およびラベルにスタイルを適用します。 + +| プライマリ プロパティ | 依存プロパティ | 説明 | +| --- | --- | --- | +| `--track-on-color` | `--track-on-hover-color` | スイッチがチェックされているときのトラックの背景。 | +| | `--track-off-color` | スイッチのチェックが外れているときのトラックの背景。 | +| `--thumb-on-color` | `--thumb-off-color` | チェック済みおよびチェック解除の状態のつまみの色。 | +| `--label-color` | `--label-disabled-color` | デフォルトおよび無効状態のラベルの色。 | + +### スタイル パーツ + +以下の CSS パーツを使用して、Switch とその内部要素をターゲットにします。 + +| パーツ | コンポーネント | スタイル設定内容 | +| --- | --- | --- | +| `base` | <ApiLink pkg="core" type="Switch" /> | スイッチの基本ラッパー。 | +| `control` | <ApiLink pkg="core" type="Switch" /> | スイッチの入力要素。 | +| `thumb` | <ApiLink pkg="core" type="Switch" /> | スイッチの位置インジケーター。 | +| `label` | <ApiLink pkg="core" type="Switch" /> | スイッチのラベル。 | + +### カスタム スタイル設定 -|名前|説明| -|--|--| -| `base` | スイッチの基本ラッパー。 | -| `control` | スイッチの入力要素。 | -| `thumb` | スイッチの位置インジケーター。 | -| `label` | スイッチのラベル。 | +以下の例は、チェック済みおよびチェック解除の状態のトラックとつまみの色を変更します。 + +| セレクター | 宣言 | 効果 | +| --- | --- | --- | +| `igc-switch` | `--track-on-color`, `--track-off-color` | チェック済みおよびチェック解除の状態のトラックの背景を変更します。 | +| `igc-switch` | `--thumb-on-color`, `--thumb-off-color` | チェック済みおよびチェック解除の状態のつまみの色を変更します。 | ```css - igc-switch { - --thumb-on-color: white; - --thumb-off-color: var(--ig-success-500); - --track-on-color: var(--ig-success-500); /* Background color when checked */ - --track-off-color: white; /* Background color when unchecked */ - --track-on-hover-color: var(--ig-success-500); /* Background hover color when checked */ - } +igc-switch { + --thumb-on-color: white; + --thumb-off-color: var(--ig-success-500); + --track-on-color: var(--ig-success-500); /* Background color when checked */ + --track-off-color: white; /* Background color when unchecked */ + --track-on-hover-color: var(--ig-success-500); /* Background hover color when checked */ +} +``` + +<Sample src="/inputs/switches/styling" height={500} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch Styling Example" /> + +### Tailwind でのスタイル設定 + +`igniteui-theming` のカスタム Tailwind ユーティリティ クラスを使用して {Platform} Switch のスタイルを設定できます。まず [Tailwind をセットアップ](/themes/tailwind) してから、グローバル スタイルシートに Ignite UI ユーティリティをインポートします。 + +```css +@import "tailwindcss"; +@import "igniteui-theming/tailwind/utilities/material.css"; ``` -<Sample src="/inputs/switches/styling" height={100} alt="{Platform} Switch のスタイル設定" /> +<PlatformBlock for="React"> + +```jsx +<IgrSwitch className="!light-switch ![--track-on-color:#7B9E89]"></IgrSwitch> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-switch class="!light-switch ![--track-on-color:#7B9E89]"></igc-switch> +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + +```razor +<IgbSwitch Class="!light-switch ![--track-on-color:#7B9E89]" /> +``` + +</PlatformBlock> + +感嘆符 (`!`) は、Switch のデフォルトのテーマ スタイルよりも Tailwind ユーティリティを優先させます。 + +<Sample src="/inputs/switches/tailwind-styling" height={450} position="center" noBorder={false} noBackground={false} spacing="md" alt="{Platform} Switch Tailwind styling example" /> + +</PlatformBlock> +## アクセシビリティ +{Platform} Switch はバイナリ状態を公開し、そのラベルまたは ARIA 属性を通じてアクセシブルな名前をサポートします。 +### キーボード操作 + +| キー | アクション | +| --- | --- | +| Tab / Shift+Tab | フォーカスをスイッチに移動またはスイッチから移動します。 | +| Space | フォーカスされているスイッチを切り替えます。 | + +### スクリーン リーダー/ARIA + +Switch は、バイナリのチェック状態を持つインタラクティブなコントロールをレンダリングします。表示されるラベル コンテンツ、または `aria-label` や `aria-labelledby` によるアクセシブルな名前を用意し、ラベルはスイッチが制御する設定に固有のものにしてください。 + +<PlatformBlock for="WebComponents, React, Blazor"> + +- コントロールは、そのチェック状態と無効状態を支援技術に公開します。 +- チェック状態が変更されると、`igcChange` イベントが発生します。 + +</PlatformBlock> + +### アクセシビリティ コンプライアンス + +Infragistics は、Section 508 および WCAG 2.1 ガイドライン領域に対する {ProductName} のアクセシビリティ サポートを [アクセシビリティ コンプライアンス](../interactivity/accessibility-compliance.mdx) トピックで説明しています。 + +| 基準 | コンポーネントがどのように準拠しているか | +| --- | --- | +| [2.1.1 キーボード](https://www.w3.org/WAI/WCAG21/Understanding/keyboard) | スイッチはキーボードで到達でき、Space で切り替えることができます。 | +| [4.1.2 名前、役割、値](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value) | スイッチは、レンダリングされたコントロールを通じて、アクセシブルな名前とバイナリのチェック状態を公開します。 | + +## トラブルシューティング + +このセクションを使用して、Switch をフォーム フィールド、インタラクティブなコマンド、または設定コントロールとして扱う前に、境界と一般的な決定事項を確認してください。 + +### Switch がフォームで送信されないのはなぜですか? + +Switch はフォームに関連付けられますが、フォームが送信されたときに値を提供するには `name` と `value` が必要です。両方のプロパティを設定し、対象プラットフォームでサポートされているフォーム統合を使用してください。 + +### スクリーン リーダーで Switch が正しく読み上げられないのはなぜですか? + +Switch にはアクセシブルな名前が必要です。表示されるラベル コンテンツを追加するか、`aria-labelledby` で外部ラベルを参照してください。表示テキストが利用できない場合は `aria-label` を使用してください。 + +### 既知の制限事項 + +{Platform} Switch には、プラットフォームに依存しない以下の制限事項があります。 + +- Switch は 1 つのバイナリ設定を表します。ユーザーが複数の選択肢または後から行うフォーム選択を必要とする場合は、別のコントロールを使用してください。 +- Switch にラベルまたは ARIA 命名属性がない場合、アクセシブルな名前は自動的には提供されません。 ## API リファレンス +{Platform} Switch の完全な API リファレンスを参照してください。 + +<ApiLink pkg="core" type="Switch" /> + +<PlatformBlock for="Angular"> +<ApiLink kind="sass" module="themes" type="function-switch-theme" label="IgxSwitchComponent Theme" /> +</PlatformBlock> + +## 依存関係 -<ApiLink pkg="core" type="Switch" /><br /> +{Platform} Switch は、視覚的なスタイルを適用するためにテーマ スタイルシートを必要とします。フレームワーク固有のセットアップについては、<PlatformBlock for="Angular">[**作業の開始**](../general/getting-started.mdx)</PlatformBlock><PlatformBlock for="React,WebComponents,Blazor">[**作業の開始**](../general-getting-started.mdx)</PlatformBlock> を参照してください。 ## その他のリソース +API の詳細、例、およびプロジェクトのサポートについては、以下の {Platform} リソースを使用してください。 + +- [Lists - Design System Pattern](https://www.infragistics.com/products/indigo-design/help/patterns/lists) - [{ProductName} **フォーラム (英語)**]({ForumsLink}) - [{ProductName} **GitHub (英語)**]({GithubLink}) + +## 関連コンポーネント + +<PlatformBlock for="Angular"> +- [Checkbox](../checkbox.mdx) - ユーザーが 1 つ以上のオプションを選択する場合、特にフォームの一部として使用する場合は Checkbox を使用します。 +</PlatformBlock> + +<PlatformBlock for="React,WebComponents,Blazor"> +- [Checkbox](./checkbox.mdx) - ユーザーが 1 つ以上のオプションを選択する場合、特にフォームの一部として使用する場合は Checkbox を使用します。 +</PlatformBlock> + +- [Button](./button.mdx) - コントロールが設定ではなくコマンドまたはアクションを表す場合は Button を使用します。 + +## FAQ + +<Faq> + <FaqItem question="Switch を初期のオン状態またはオフ状態に設定するにはどうすればよいですか?"> + <ApiLink pkg="core" type="Switch" member="checked" label="checked" /> プロパティをオン状態の場合は `true` に、オフ状態の場合は `false` に設定します。React、Web Components、および Blazor の構文では、このプロパティはブール値を使用します。 + </FaqItem> + <FaqItem question="Switch のラベルを配置するにはどうすればよいですか?"> + Switch 内にラベル テキストを配置し、<ApiLink pkg="core" type="Switch" member="labelPosition" label="labelPosition" /> プロパティを `before` または `after` に設定します。デフォルトのラベル位置は `after` です。 + </FaqItem> + <FaqItem question="フォームで Switch の値を送信するにはどうすればよいですか?"> + <ApiLink pkg="core" type="Switch" member="name" label="name" /> と <ApiLink pkg="core" type="Switch" member="value" label="value" /> の両方のプロパティを設定します。Blazor では、標準の HTML `form` の代わりに `EditForm` コンポーネントを使用します。 + </FaqItem> + <FaqItem question="Switch を必須または無効にするにはどうすればよいですか?"> + 設定を選択する必要がある場合は <ApiLink pkg="core" type="Switch" member="required" label="required" /> プロパティを設定し、コントロールが無効な状態にある場合は <ApiLink pkg="core" type="Switch" member="invalid" label="invalid" /> を設定します。ユーザーが設定を変更できないようにする場合は <ApiLink pkg="core" type="Switch" member="disabled" label="disabled" /> を使用します。 + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/jp/components/interactivity/accessibility-compliance.mdx b/docs/xplat/src/content/jp/components/interactivity/accessibility-compliance.mdx index aba8f96344..714a687cf0 100644 --- a/docs/xplat/src/content/jp/components/interactivity/accessibility-compliance.mdx +++ b/docs/xplat/src/content/jp/components/interactivity/accessibility-compliance.mdx @@ -1,200 +1,253 @@ --- -title: Ignite UI for {Platform} アクセシビリティの遵守 | Ignite UI for {Platform} | インフラジスティックス -description: Ignite UI for {Platform} のアクセシビリティ準拠 - 第 508 条の遵守、WCAG および ARIA。 -keywords: accessibility, {Platform}, ignite ui for {Platform}, infragistics, アクセシビリティ準拠, インフラジスティックス +title: "{Platform} アクセシビリティ準拠 | {ProductName} | インフラジスティックス" +description: "{ProductName} のアクセシビリティ サポート - 対象とする標準、コンポーネントごとのキーボードおよびスクリーン リーダーの対応状況、およびアクセシビリティの問題の報告方法。" +keywords: "{ProductName}, Infragistics, Accessibility, WCAG, Section 508, EN 301 549, ARIA, Keyboard, インフラジスティックス, アクセシビリティ, アクセシビリティ準拠, キーボード" license: MIT +last_updated: "2026-08-27" mentionedTypes: [] _language: ja llms: - description: "開発者向けの UI および UX ツールのグローバル プロバイダーとして、Infragistics の {Platform} チームは、可能な限り最高のユーザー エクスペリエンスを簡単に作成できるコンポーネントとツールを提供します。" + description: "{ProductName} のアクセシビリティ サポート: 対象とする適合標準、コンポーネントごとのキーボードおよびスクリーン リーダーのドキュメント索引、必要な構成、およびアクセシビリティの問題を報告するためのチャネル。" --- + import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; +import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; -<style>{` -.greenCheck { - content:url("${import.meta.env.BASE_URL.replace(/\/$/, '')}/images/general/greenCheck.png"); -} +# アクセシビリティ準拠 -.redCheck { - content:url("${import.meta.env.BASE_URL.replace(/\/$/, '')}/images/general/redX.png"); -} -`}</style> +このページには、{ProductName} が対象とするアクセシビリティ標準、各コンポーネントのドキュメントが現在カバーしている内容、およびアクセシビリティの問題を報告する方法を記載しています。 -# アクセシビリティ準拠 +アクセシビリティ サポートは、コンポーネント自体と、それらをスタイル設定するテーマ設定エンジンの 2 つのレイヤーによって提供されます。特定のコンポーネントの対応状況を確認するにはこのページを、コントラスト、テキストのスケーリング、チャートの色の動作については[テーマ設定のアクセシビリティ](../themes/accessibility.mdx)を使用してください。 + +<DocsAside type="note"> +**このページの範囲。** 以下の情報は、**デフォルト テーマ**と、各コンポーネントの現在ドキュメント化されている動作を反映しています。これはサポートの概要であり、正式な適合宣言ではありません。カスタム テーマ、タイポグラフィの変更、アニメーションや色のオーバーライドによって結果が変わる可能性があります。 +</DocsAside> -開発者向けの UI および UX ツールのグローバル プロバイダーとして、Infragistics の {Platform} チームは、可能な限り最高のユーザー エクスペリエンスを簡単に作成できるコンポーネントとツールを提供します。私たちの目標は、ユーザーにとって最高のアプリケーションとユーザー エクスペリエンスの作成に集中できるようにすることです。 - -ここでは、Ignite UI for {Platform} 内の {Platform} グリッド、チャート、UI コンポーネントおよびコントロールのアクセシビリティ サポートと準拠に関する特定の情報を見つけることができます。 - -## 第 508 条の遵守 - -リハビリテーション法[第 508 条](http://www.section508.gov/)は、連邦議会によって 1998 年に改正され、すべての連邦政府機関は障害を持つ人が電子情報技術にアクセスできるようにすることを義務付けました。それ以降、第 508 条の準拠は連邦政府機関の要件であるだけでなく、ソフトウェア ソリューションを提供し、Web ページを設計する際にも重要となります。 - -第 508 条の第 1194 部 22 条は、特に Web ベースのイントラネットおよびインターネット情報およびシステムを対象としており、遵守すべき 16 の規則が含まれています。お客様の最小限の努力でお客様の Web アプリケーションおよび Web サイトがこれらの規則に整合できるようにするために、インフラジスティックスは、Ignite UI for {Platform} のコントロールおよびコンポーネントが該当するアクセシビリティ規則に準拠することを保証するための取り組みを続けてきました。 - -以下のマトリックスで、弊社の視覚的コントロール (および関連コンポーネント) によって提供されるアクセシビリティのサポートの高レベルな概要を提供します。個々のコントロール/コンポーネントのアクセシビリティの遵守の詳細は、コントロール/コンポーネント名をクリックしてください。 - -### 第 508 条との Ignite UI for {Platform} 準拠 - -|**コンポーネント/原則**|<a title="あらゆる非テキスト要素に対してテキスト相当物を提供するものとします(つまり、「alt」、「longdesc」を介して、または要素コンテンツで)。"> (a)</a><br/>|<a title="マルチメディア プレゼンテーションに相当する代替物をプレゼンテーションと同期するものとします。">(b)</a><br/>|<a title="色によって伝達されるすべての情報が色を使用しなくても理解できるように (たとえば、コンテキストやマークアップ) Web ページを設計するものとします。">(c)</a><br/>|<a title="ドキュメントは、関連付けられたスタイル シートがなくても読めるように構成されます。">(d)</a><br/>|<a title="サーバー側の画像マップのアクティブな領域ごとに冗長なテキスト リンクが提供されます。">(e)</a><br/>|<a title="その領域を使用可能な幾何学的形状で定義できない場合を除いて、サーバー側の画像マップの代わりにクライアント側の画像マップが提供されます。">(f)</a><br/>|<a title="行ヘッダーと列ヘッダーは、データ テーブル用に識別される必要があります。">(g)</a><br/>|<a title="マークアップは、行または列のヘッダーの 2 つ以上の論理レベルを有するデータ テーブル用にデータ セルとヘッダー セルを関連づけるために使用します。">(h)</a><br/>|<a title="フレームには、フレームの識別とナビゲーションを簡略化するテキストでタイトルが付けられます。">(i)</a><br/>|<a title="ページは、2 Hz より大きく、55 Hz を下回る周波数で画面がちらつかないように設計するものとします。">(j)</a><br/>|<a title="その他のいかなる方法でも規定に準拠できない時に、Web サイトがこの部分の規定に準拠するように、相当する情報または機能を含むテキストのみのページを提供するものとします。主要なページが変更するとテキストのみのページのコンテンツは必ず更新されるものとします。">(k)</a><br/>|<a title="ページがスクリプト言語を利用してコンテンツを表示、またはインターフェイス要素を作成する場合、スクリプトによって提供される情報は支援技術が読み取ることのできる関数テキストで識別されるものとします。">(l)</a><br/>|<a title="ページのコンテンツを解釈するためにアプレット、プラグインまたはその他のアプリケーションがクライアント システムに存在することを Web ページが必要とする時には、ページは §1194.21(a) から (l) に準拠するプラグインまたはアプレットへのリンクを提供する必要があります。">(m)</a><br/>|<a title="オンラインですべての項目に記入するように電子的フォームが設計されている場合には、そのフォームによって、補助技術を使用するユーザーは、すべての指示と手掛かりを含めた、フォームの完成と提出に必要な情報、フィールド要素、および機能にアクセスすることができます。">(n)</a><br/>|<a title="ユーザーが反復するナビゲーション リンクをスキップすることができる方法を提供します。">(o)</a><br/>|<a title="一定の時間内での応答が要求される場合、ユーザーは警告を受け、追加時間が必要な旨を伝える十分な時間が与えられます。">(p)</a><br/>| -|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--| -|_グリッド_||||||||||||||||| -| - Grid|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -| - HierarchicalGrid|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -| - TreeGrid|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -|_その他_||||||||||<span class="greenCheck" />*||||||| -| - Avatar|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Badge|<span class="greenCheck" />||<span class="greenCheck" />|||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Bottom navigation|||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Button|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Button group|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Calendar|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Card|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Carousel|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -| - Checkbox|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Chip|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Circular progress|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Combo|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />||| -| - Date time input|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Date picker|||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Divider|<span class="greenCheck" />||<span class="greenCheck" />|||||||||<span class="greenCheck" />||||| -| - Dialog|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Drop down|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />||| -| - Expansion panel|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Icon|||<span class="greenCheck" />|||||||||<span class="redCheck" />||||| -| - Input|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Input group|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Linear progress|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - List|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Navbar|<span class="greenCheck" />||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Navigation drawer|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Radio group|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Radio|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Select|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />||| -| - Slider|||<span class="greenCheck" />|||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Snackbar|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| -| - Switch|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Tabs|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="greenCheck" />||<span class="greenCheck" />||| -| - Time picker|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||| -| - Toast|||<span class="greenCheck" />|<span class="greenCheck" />||||||<span class="greenCheck" />*||<span class="redCheck" />||<span class="greenCheck" />||<span class="redCheck" />| - - -**凡例** - -|||| +## 対象とする標準 + +| 標準 | 地域 | 要求事項 | |---|---|---| -|<span class="greenCheck" />|コントロール/コンポーネントは、この特定の領域でユーザー補助に完全に対応しています。|| -|<span class="greenCheck" />*|コントロール/コンポーネントは、この特定の領域で特定の構成を実装した後にアクセスできます。| 例: **NoopAnimationsModule**ユーティリティ モジュールを使用してアニメーションの無効化を許可します。| -|<span class="redCheck" />|コントロール/コンポーネント: 一部の種類のアクションを実行しない限り、完全にはユーザー補助に対応しません。|| -|'空白'|この特定の規則はコントロールに適用されません。|| +| <a href="https://www.w3.org/WAI/WCAG21/quickref/" target="_blank" rel="noopener noreferrer">WCAG 2.1 Level AA</a> | 国際 | 以下に示す達成基準。他の 2 つの標準が参照する基準となるものです。 | +| <a href="https://www.section508.gov/" target="_blank" rel="noopener noreferrer">第 508 条 (改訂版)</a> | 米国 | 連邦政府の調達。改訂版第 508 条標準 (2017 年公開、2018 年 1 月適用開始) 以降は WCAG 2.0 Level AA を参照により組み込んでいるため、同じ対応で満たされます。 | +| <a href="https://www.etsi.org/deliver/etsi_en/301500_301599/301549/" target="_blank" rel="noopener noreferrer">EN 301 549</a> | 欧州 | ICT のアクセシビリティについて参照される、WCAG を基盤とした欧州標準。これを基盤とする欧州アクセシビリティ法は、2025 年 6 月 28 日から適用されます。 | -<DocsAside type="warning" title="警告"> -上記のテーブルは、Ignite UI for {Platform} テーマ ライブラリのデフォルト テーマにのみ関連しています。カスタム テーマ、タイポグラフィ、およびアニメーションと色に関連する視覚的な変更に関しては、チェックリストへの準拠が異なる場合があります。 +<DocsAside type="note"> +第 508 条には、以前は §1194.22 に基づく独自の 16 の規則が定義されていました。これらは、WCAG を直接採用する改訂版標準に置き換えられました。したがって、WCAG 2.1 Level AA を対象とすることで、上記の 3 つのフレームワークすべてに対応できます。 </DocsAside> -### 法令遵守情報 - -- **a** - あらゆる非テキスト要素に対してテキスト相当物を提供するものとします(つまり、「alt」、「longdesc」を介して、または要素コンテンツで)。 -- **b** - マルチメディア プレゼンテーションに相当する代替物をプレゼンテーションと同期するものとします。 -- **c** - 色によって伝達されるすべての情報が色を使用しなくても理解できるように (たとえば、コンテキストやマークアップ) Web ページを設計するものとします。 -- **d** - ドキュメントは、関連付けられたスタイル シートがなくても読めるように構成されます。 -- **e** - サーバー側の画像マップのアクティブな領域ごとに冗長なテキスト リンクが提供されます。 -- **f** - その領域を使用可能な幾何学的形状で定義できない場合を除いて、サーバー側の画像マップの代わりにクライアント側の画像マップが提供されます。 -- **g** - 行ヘッダーと列ヘッダーは、データ テーブル用に識別される必要があります。 -- **h** - マークアップは、行または列のヘッダーの 2 つ以上の論理レベルを有するデータ テーブル用にデータ セルとヘッダー セルを関連づけるために使用します。 -- **i** - フレームには、フレームの識別とナビゲーションを簡略化するテキストでタイトルが付けられます。 -- **j** - ページは、2 Hz より大きく、55 Hz を下回る周波数で画面がちらつかないように設計するものとします。 -- **k** - その他のいかなる方法でも規定に準拠できない時に、Web サイトがこの部分の規定に準拠するように、相当する情報または機能を含むテキストのみのページを提供するものとします。主要なページが変更するとテキストのみのページのコンテンツは必ず更新されるものとします。 -- **l** - ページがスクリプト言語を利用してコンテンツを表示、またはインターフェイス要素を作成する場合、スクリプトによって提供される情報は支援技術が読み取ることのできる関数テキストで識別されるものとします。 -- **m** - ページのコンテンツを解釈するためにアプレット、プラグインまたはその他のアプリケーションがクライアント システムに存在することを Web ページが必要とする時には、ページは §1194.21(a) から (l) に準拠するプラグインまたはアプレットへのリンクを提供する必要があります。 -- **n** - オンラインですべての項目に記入するように電子的フォームが設計されている場合には、そのフォームによって、補助技術を使用するユーザーは、すべての指示と手掛かりを含めた、フォームの完成と提出に必要な情報、フィールド要素、および機能にアクセスすることができます。 -- **o** - ユーザーが反復するナビゲーション リンクをスキップすることができる方法を提供します。 -- **p** - 一定の時間内での応答が要求される場合、ユーザーは警告を受け、追加時間が必要な旨を伝える十分な時間が与えられます。 - - -## WCAG の準拠 -[WCAG](https://www.w3.org/WAI/WCAG21/quickref/?showtechniques=111) は、アクセシブルな Web コンテンツを開発する方法に関する正式なガイドラインのセットです。これらの規格は、508 規格に同一または非常に類似していますが、より高いレベルのアクセシビリティを表しています。WCAG は主に HTML のアクセシビリティに焦点を当てます。 - -|**コンポーネント/ガイドライン**|<a title="代替テキスト - テキスト以外のコンテンツの代替テキストを提供して、大きな活字、点字、音声、記号、より単純な言語など、他の形式に変更できるようにします。">1.1</a><br/>|<a title="時間ベースのメディア - 時間ベースのメディアの代替物を提供します。">1.2</a><br/>|<a title="適応可能 - 情報や構造を失うことなく、さまざまな方法 (たとえば、よりシンプルなレイアウト) で提示できるコンテンツを作成します。">1.3 </a><br/>|<a title="識別可能 - 前景を背景から分離するなど、ユーザーがコンテンツをより簡単に視聴できるようにします。">1.4</a><br/>|<a title="キーボードでアクセス可能 - すべての機能をキーボードで使用できるようにします。">2.1</a><br/>|<a title="十分な時間 - ユーザーがコンテンツを読んで使用するのに十分な時間を提供します。">2.2</a><br/>|<a title="発作と身体的な反応 - 発作または身体的な反応を引き起こすことが知られている方法でコンテンツをデザインしないでください。">2.3</a><br/>|<a title="ナビゲート可能 - ユーザーがナビゲートし、コンテンツを見つけ、そしてどこにいるかを判別するのに役立つ方法を提供します。">2.4</a><br/>|<a title="入力モダリティ - ユーザーがキーボード以外のさまざまな入力を介して機能を簡単に操作できるようにします。<br/>">2.5</a><br/>|<a title="可読 - テキスト コンテンツを読みやすく、理解しやすくします。">3.1</a><br/>|<a title="予測可能 - Web ページを予測可能な方法で表示して動作させる。">3.2</a><br/>|<a title="入力支援 - ユーザーが間違いを回避して修正できるようにします。">3.3</a><br/>|<a title="互換性 - 支援技術を含む現在および将来のユーザー エージェントとの互換性を最大化します。">4.1 </a><br/>| -|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--| -|_グリッド_|||||||||||||| -| - Grid|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />| -| - HierarchicalGrid|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />| -| - TreeGrid|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />| -|_その他_|||||||<span class="greenCheck" />*||||||| -| - Avatar|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Badge|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Banner|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Bottom navigation||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Button||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Button group||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Calendar|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||<span class="greenCheck" />| -| - Card|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Carousel|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Checkbox|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*||| -| - Chip||||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Circular progress|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*|||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Combo|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />| -| - Date time editor||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|| -| - Date picker||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|| -| - Divider|<span class="greenCheck" />||||||||||<span class="greenCheck" />*||| -| - Dialog|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Drop down|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Expansion panel|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Icon||||<span class="greenCheck" />||<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Input|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|| -| - Input group|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|| -| - Label|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Linear progress|<span class="greenCheck" />|||<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*|||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - List|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||||<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Month picker||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />| -| - Navbar|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Navigation drawer|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Radio group|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Radio|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Select|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Slider||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Snackbar|||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Switch|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Tabs|<span class="greenCheck" />|||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Time picker||||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*|<span class="greenCheck" />|<span class="greenCheck" />| -| - Toast|||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="greenCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| -| - Tooltip|<span class="greenCheck" />||<span class="greenCheck" />|<span class="greenCheck" />||<span class="greenCheck" />*|<span class="greenCheck" />*||<span class="redCheck" />|<span class="greenCheck" />|<span class="greenCheck" />*||| - - -**凡例** - -|||| +### UI コンポーネントに適用される達成基準 + +WCAG への適合は、より広範なガイドラインに対してではなく、個々の**達成基準**に対して主張されます。UI コンポーネント ライブラリが影響を与えることができる基準は次のとおりです: + +| 基準 | レベル | コンポーネントにとっての意味 | +|---|:--:|---| +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html" target="_blank" rel="noopener noreferrer">1.1.1 非テキスト コンテンツ</a> | A | アイコンと画像にテキストによる代替を提供します。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html" target="_blank" rel="noopener noreferrer">1.3.1 情報及び関係性</a> | A | 視覚的に伝えられる構造がマークアップでも伝えられます。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/meaningful-sequence.html" target="_blank" rel="noopener noreferrer">1.3.2 意味のある順序</a> | A | 読み上げ順序が視覚的な順序と一致します。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html" target="_blank" rel="noopener noreferrer">1.4.3 コントラスト (最低限)</a> | AA | テキストと背景のコントラスト比が 4.5:1 を満たします。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/resize-text.html" target="_blank" rel="noopener noreferrer">1.4.4 テキストのサイズ変更</a> | AA | コンテンツを失うことなくテキストを 200% まで拡大できます。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html" target="_blank" rel="noopener noreferrer">1.4.11 非テキストのコントラスト</a> | AA | コントロールの境界と状態のコントラスト比が 3:1 を満たします。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html" target="_blank" rel="noopener noreferrer">1.4.13 ホバー又はフォーカスで表示されるコンテンツ</a> | AA | ツールチップとポップオーバーは閉じることができ、表示が維持されます。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/keyboard.html" target="_blank" rel="noopener noreferrer">2.1.1 キーボード</a> | A | すべての機能にキーボードで到達できます。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/no-keyboard-trap.html" target="_blank" rel="noopener noreferrer">2.1.2 キーボード トラップなし</a> | A | フォーカスを常に外に戻すことができます。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html" target="_blank" rel="noopener noreferrer">2.4.3 フォーカス順序</a> | A | タブ順序が意味のある順序に従います。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html" target="_blank" rel="noopener noreferrer">2.4.7 フォーカスの可視化</a> | AA | フォーカスされたコントロールが視覚的に示されます。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/label-in-name.html" target="_blank" rel="noopener noreferrer">2.5.3 ラベルを含む名前</a> | A | アクセシブル名に表示ラベルが含まれます。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/on-focus.html" target="_blank" rel="noopener noreferrer">3.2.1 フォーカス時</a> | A | フォーカスだけではコンテキストの変化が発生しません。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/on-input.html" target="_blank" rel="noopener noreferrer">3.2.2 入力時</a> | A | 値の変更だけではコンテキストの変化が発生しません。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/labels-or-instructions.html" target="_blank" rel="noopener noreferrer">3.3.2 ラベル又は説明</a> | A | 入力にラベルまたは説明が付いています。 | +| <a href="https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html" target="_blank" rel="noopener noreferrer">4.1.2 名前、役割、値</a> | A | すべてのコントロールが名前、役割、および現在の状態を公開します。 | + +## アクセシビリティの提供方法 + +| レイヤー | 担当する範囲 | ドキュメントの場所 | |---|---|---| -|<span class="greenCheck" />|コントロール/コンポーネントは、この特定の領域でユーザー補助に完全に対応しています。|| -|<span class="greenCheck" />*|コントロール/コンポーネントは、この特定の領域で特定の構成を実装した後にアクセスできます。|例 1: ガイドライン 2.2. 特定のコンポーネントでは、追加のアクションと時間パラメーターを設定する必要があります。例 2: ガイドライン 2.3. **NoopAnimationsModule**ユーティリティ モジュールを使用してアニメーションの無効化を許可します。| -|<span class="redCheck" />|コントロール/コンポーネント: 一部の種類のアクションを実行しない限り、完全にはユーザー補助に対応しません。|| -|'空白'|この特定の規則はコントロールに適用されません。|| +| **コンポーネント ライブラリ** (Angular では `igniteui-angular`) | キーボード操作、フォーカスの移動、ARIA のロールと状態、スクリーン リーダーの読み上げ。 | 以下の索引、および各コンポーネントのトピック。 | +| **テーマ設定エンジン** (`igniteui-theming`) | カラー コントラスト、テキスト サイズ、チャートのカラー パレット、カスタム コントロール向けのスタイル設定ユーティリティ。 | [テーマ設定のアクセシビリティ](../themes/accessibility.mdx) | + +## コンポーネントのサポート状況 + +この索引には、各コンポーネントのドキュメントが現在カバーしている内容を記録しています。**未ドキュメント化**は、そのコンポーネント自身のドキュメントにこの動作の説明がないことを意味します。これはドキュメントについての記述であり、コンポーネントについての記述ではありません。 + +| ステータス | 意味 | +|---|---| +| **ドキュメント化済み** | 動作は、行内でリンクされているコンポーネント自身のドキュメントで説明されています。 | +| **構成が必要** | [必要な構成](#必要な構成)に記載されている設定を適用すると利用できます。 | +| **未ドキュメント化** | コンポーネントのドキュメントでは、この動作はまだ説明されていません。 | + +<PlatformBlock for="Angular"> + +| コンポーネント | キーボード操作 | スクリーン リーダー / ARIA | リファレンス | +|---|---|---|---| +| [Grid](../grid/grid.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../grid/keyboard-navigation.mdx) | +| [Hierarchical Grid](../hierarchicalgrid/hierarchical-grid.mdx) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../hierarchicalgrid/keyboard-navigation.mdx) | +| [Tree Grid](../treegrid/tree-grid.mdx) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../treegrid/keyboard-navigation.mdx) | +| [Avatar](../layouts/avatar.mdx#アクセシビリティ) | ドキュメント化済み | ドキュメント化済み | [アクセシビリティ](../layouts/avatar.mdx#アクセシビリティ) | +| [Badge](../inputs/badge.mdx#アクセシビリティ) | ドキュメント化済み | ドキュメント化済み | [アクセシビリティ](../inputs/badge.mdx#アクセシビリティ) | +| [Banner](../banner.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Bottom Navigation](../tabs.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Button](../inputs/button.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Button Group](../inputs/button-group.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Calendar](../calendar.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../calendar.mdx#キーボード-ナビゲーション) | +| [Card](../card.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Carousel](../carousel.mdx) | ドキュメント化済み | ドキュメント化済み | [アクセシビリティ](../carousel.mdx#ユーザー補助) | +| [Checkbox](../checkbox.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Chip](../chip.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../chip.mdx#キーボード-ナビゲーション) | +| [Circular Progress](../circular-progress.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Combo](../combo.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../combo.mdx#キーボード-ナビゲーション) | +| [Date Time Editor](../date-time-editor.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../date-time-editor.mdx#キーボード-ナビゲーション) | +| [Date Picker](../date-picker.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../date-picker.mdx#キーボード-ナビゲーション) | +| [Dialog](../dialog.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Divider](../divider.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Drop Down](../drop-down.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Expansion Panel](../expansion-panel.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Icon](../icon.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Input Group](../input-group.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Label](../label-input.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Linear Progress](../linear-progress.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [List](../list.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Month Picker](../month-picker.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../month-picker.mdx#キーボード-ナビゲーション) | +| [Navbar](../navbar.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Navigation Drawer](../navdrawer.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Radio](../radio-button.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Select](../select.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../select.mdx#キーボード-ナビゲーション) | +| [Slider](../slider/slider.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Snackbar](../snackbar.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Switch](../switch.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Tabs](../tabs.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Time Picker](../time-picker.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../time-picker.mdx#キーボード-ナビゲーション) | +| [Toast](../toast.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Tooltip](../tooltip.mdx) | ドキュメント化済み | 未ドキュメント化 | [アクセシビリティ](../tooltip.mdx#ユーザー補助) | + +</PlatformBlock> + +<PlatformBlock for="React, WebComponents, Blazor"> + +| コンポーネント | キーボード操作 | スクリーン リーダー / ARIA | リファレンス | +|---|---|---|---| +| [Grid](../grids/data-grid.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../grids/data-grid.mdx#キーボード-ナビゲーション) | +| [Hierarchical Grid](../grids/hierarchical-grid/overview.mdx) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../grids/data-grid.mdx#キーボード-ナビゲーション) | +| [Tree Grid](../grids/tree-grid/overview.mdx) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../grids/data-grid.mdx#キーボード-ナビゲーション) | +| [Tree](../grids/tree.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../grids/tree.mdx#キーボード-ナビゲーション) | +| [List](../grids/list.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Avatar](../layouts/avatar.mdx#アクセシビリティ) | ドキュメント化済み | ドキュメント化済み | [アクセシビリティ](../layouts/avatar.mdx#アクセシビリティ) | +| [Badge](../inputs/badge.mdx#アクセシビリティ) | ドキュメント化済み | ドキュメント化済み | [アクセシビリティ](../inputs/badge.mdx#アクセシビリティ) | +| [Banner](../notifications/banner.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Button](../inputs/button.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Button Group](../inputs/button-group.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Calendar](../scheduling/calendar.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../scheduling/calendar.mdx#キーボード-ナビゲーション) | +| [Card](../layouts/card.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Carousel](../layouts/carousel.mdx) | ドキュメント化済み | ドキュメント化済み | [アクセシビリティ](../layouts/carousel.mdx#ユーザー補助) | +| [Checkbox](../inputs/checkbox.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Chip](../inputs/chip.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Circular Progress](../inputs/circular-progress.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Combo](../inputs/combo/overview.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../inputs/combo/overview.mdx#キーボード-ナビゲーション) | +| [Date Time Input](../inputs/date-time-input.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../inputs/date-time-input.mdx#キーボード-ナビゲーション) | +| [Date Picker](../scheduling/date-picker.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../scheduling/date-picker.mdx#キーボード-ナビゲーション) | +| [Dialog](../notifications/dialog.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Divider](../layouts/divider.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Dock Manager](../layouts/dock-manager.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../layouts/dock-manager.mdx#キーボード-ナビゲーション) | +| [Dropdown](../inputs/dropdown.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Expansion Panel](../layouts/expansion-panel.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../layouts/expansion-panel.mdx#キーボード-ナビゲーション) | +<PlatformBlock for="WebComponents">| [File Input](../inputs/file-input.mdx#アクセシビリティと-aria-サポート) | ドキュメント化済み | ドキュメント化済み | [アクセシビリティ](../inputs/file-input.mdx#アクセシビリティと-aria-サポート) | +</PlatformBlock>| [Icon](../layouts/icon.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Icon Button](../inputs/icon-button.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Input](../inputs/input.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Linear Progress](../inputs/linear-progress.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Navbar](../menus/navbar.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Navigation Drawer](../menus/navigation-drawer.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Radio](../inputs/radio.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Rating](../inputs/rating.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Select](../inputs/select.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../inputs/select.mdx#キーボード-ナビゲーション) | +| [Slider](../inputs/slider.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Snackbar](../notifications/snackbar.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Stepper](../layouts/stepper.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../layouts/stepper.mdx#キーボード-ナビゲーション) | +| [Switch](../inputs/switch.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Tabs](../layouts/tabs.mdx#キーボード-ナビゲーション) | ドキュメント化済み | 未ドキュメント化 | [キーボード ナビゲーション](../layouts/tabs.mdx#キーボード-ナビゲーション) | +| [Text Area](../inputs/text-area.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Toast](../notifications/toast.mdx) | 未ドキュメント化 | 未ドキュメント化 | — | +| [Tooltip](../inputs/tooltip.mdx#アクセシビリティと-aria-サポート) | ドキュメント化済み | ドキュメント化済み | [アクセシビリティ](../inputs/tooltip.mdx#アクセシビリティと-aria-サポート) | + +</PlatformBlock> + +<DocsAside type="warning"> +**未ドキュメント化**とマークされている行は、このドキュメントのギャップであり、既知の欠陥ではありません。次のレビュー サイクルより前に特定のコンポーネントの適合に関する回答が必要な場合は、[Issue を作成](#アクセシビリティの問題の報告)してお問い合わせください。 +</DocsAside> + +## 必要な構成 + +アクセシビリティの結果の一部は、コンポーネント単体ではなく、アプリケーションの構成方法に依存します。 + +<PlatformBlock for="Angular"> + +| 懸念事項 | 基準 | 構成する内容 | +|---|---|---| +| アニメーションと動き | <a href="https://www.w3.org/WAI/WCAG21/Understanding/three-flashes-or-below-threshold.html" target="_blank" rel="noopener noreferrer">2.3.1 3 回の閃光、又は閾値以下</a> | Angular のアニメーションをアプリケーション全体で無効にするには、`BrowserAnimationsModule` の代わりに `@angular/platform-browser/animations` の `NoopAnimationsModule` を提供します。 | + +</PlatformBlock> + +<PlatformBlock for="React, WebComponents, Blazor"> + +| 懸念事項 | 基準 | 構成する内容 | +|---|---|---| +| アニメーションと動き | <a href="https://www.w3.org/WAI/WCAG21/Understanding/three-flashes-or-below-threshold.html" target="_blank" rel="noopener noreferrer">2.3.1 3 回の閃光、又は閾値以下</a> | 構成は必要ありません。アニメーション プレーヤーはオペレーティング システムの `prefers-reduced-motion: reduce` 設定を読み取り、設定されている場合はアニメーションを継続時間 `0` で再生します。 | + +</PlatformBlock> -<DocsAside type="warning" title="警告"> -上記のテーブルは、Ignite UI for {Platform} テーマ ライブラリのデフォルト テーマにのみ関連しています。カスタム テーマ、タイポグラフィ、およびアニメーションと色に関連する視覚的な変更に関しては、チェックリストへの準拠が異なる場合があります。 +残りの項目は、すべてのプラットフォームに適用されます。 + +| 懸念事項 | 基準 | 構成する内容 | +|---|---|---| +| 一時的なメッセージの時間制限 | <a href="https://www.w3.org/WAI/WCAG21/Understanding/timing-adjustable.html" target="_blank" rel="noopener noreferrer">2.2.1 タイミング調整可能</a> | Snackbar や Toast など、自動的に閉じるコンポーネントは表示時間の設定を公開しています。ユーザーがメッセージを読む時間を確保できるように、表示時間を延長するか、自動的に閉じる動作を無効にしてください。 | +| テーマ設定後のカラー コントラスト | <a href="https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html" target="_blank" rel="noopener noreferrer">1.4.3 コントラスト (最低限)</a> | 前景色は固定値ではなく、`contrast-color()` または `adaptive-contrast()` で設定してください。[テーマ設定のアクセシビリティ](../themes/accessibility.mdx)を参照してください。 | +| アイコンのみのコントロールのアクセシブル名 | <a href="https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html" target="_blank" rel="noopener noreferrer">4.1.2 名前、役割、値</a> | 独自のマークアップでアクセシブル名を指定してください。アイコンのみを表示するコントロールには、名前を付けるまで名前がありません。 | + +## 正式な適合ドキュメント + +このページはドキュメントの索引であり、適合の主張ではありません。弊社のドキュメントがカバーしている内容を記録したものであり、いずれかの標準に対してコンポーネントを認証するものではありません。 + +調達、契約、または監査の目的で、追跡可能な基準ごとの適合宣言が必要な場合は、アカウント マネージャーまたはインフラジスティックスのサポートを通じて、最新のアクセシビリティ適合レポート (VPAT) をリクエストしてください。製品、バージョン、およびレポートが対象とすべき標準 (WCAG 2.1 Level AA、第 508 条、または EN 301 549) を明記してください。 + +<DocsAside type="note"> +このページの以前の版には、コンポーネントごとの適合マトリックスが掲載されていました。それらの表は、追跡可能な基準ごとの評価に裏付けられていない適合レベルを主張していたため、書き直すのではなく削除されました。適合レポートがその情報の正式な情報源です。 </DocsAside> -### 法令遵守情報 - -- **原則 1 - 知覚可能** - 情報およびユーザー インターフェイス コンポーネントは、ユーザーが知覚できるように提示されなければなりません。 - - ガイドライン 1.1 – **代替テキスト** - テキスト以外のコンテンツの代替テキストを提供して、大きな活字、点字、音声、記号、より単純な言語など、他の形式に変更できるようにします。 - - ガイドライン 1.2 – **時間ベースのメディア** - 時間ベースのメディアの代替物を提供します。 - - ガイドライン 1.3 – **適応可能** - 情報や構造を失うことなく、さまざまな方法 (たとえば、よりシンプルなレイアウト) で提示できるコンテンツを作成します。 - - ガイドライン 1.4 – **識別可能** - 前景を背景から分離するなど、ユーザーがコンテンツをより簡単に視聴できるようにします。 -- **原則 2 – 操作可能** - ユーザー インターフェイス コンポーネントとナビゲーションは操作可能でなければなりません。 - - ガイドライン 2.1 – **キーボードでアクセス可能** - すべての機能をキーボードで使用できるようにします。 - - ガイドライン 2.2 – **十分な時間** - ユーザーがコンテンツを読んで使用するのに十分な時間を提供します。 - - ガイドライン 2.3 – **発作と身体的な反応** - 発作または身体的な反応を引き起こすことが知られている方法でコンテンツをデザインしないでください。 - - ガイドライン 2.4 – **ナビゲート可能** - ユーザーがナビゲートし、コンテンツを見つけ、そしてどこにいるかを判別するのに役立つ方法を提供します。 - - ガイドライン 2.5 – **入力モダリティ** - ユーザーがキーボード以外のさまざまな入力を介して機能を簡単に操作できるようにします。 -- **原則 3 – 理解可能** - ユーザー インターフェイスの情報と操作は理解可能でなければなりません。 - - ガイドライン 3.1 – **可読** - テキスト コンテンツを読みやすく、理解しやすくします。 - - ガイドライン 3.2 – **予測可能** - Web ページを予測可能な方法で表示して動作させる。 - - ガイドライン 3.3 – **入力支援** - ユーザーが間違いを回避して修正できるようにします。 -- **原則 4 – 堅牢** - コンテンツは、支援技術を含むさまざまなユーザー エージェントが解釈できるほど堅牢でなければなりません。 - - ガイドライン 4.1 – **互換性** - 支援技術を含む現在および将来のユーザー エージェントとの互換性を最大化します。 - - -## WAI-ARIA サポート -2014 年に W3C は [WAI-ARIA 仕様](http://www.w3.org/TR/wai-aria/)を完成しました。障害を持つユーザーに Web コンテンツおよび Web アプリケーションへのアクセシビリティを提供するデザインを定義したものです。 +## アクセシビリティの問題の報告 + +コンポーネントにアクセシビリティの問題を見つけた場合は、<a href="{GithubLink}/issues" target="_blank" rel="noopener noreferrer">{ProductName} の Issue トラッカー</a>で報告してください。 + +コンポーネント、使用した支援技術とブラウザー、期待される動作、および影響を受けると思われる WCAG の達成基準を含めてください。アクセシビリティに関する報告は、上記の基準に照らしてトリアージされます。 + +## その他のリソース + +- [テーマ設定のアクセシビリティ](../themes/accessibility.mdx) — コントラスト、テキストのスケーリング、およびチャート パレット。 +- <a href="https://www.w3.org/WAI/WCAG21/quickref/" target="_blank" rel="noopener noreferrer">WCAG 2.1 クイック リファレンス</a> — すべての達成基準と達成方法。 +- <a href="https://www.w3.org/WAI/ARIA/apg/patterns/" target="_blank" rel="noopener noreferrer">WAI-ARIA オーサリング プラクティス</a> — インタラクション パターンごとに期待されるキーボードおよび ARIA の動作。 +- <a href="https://www.section508.gov/" target="_blank" rel="noopener noreferrer">第 508 条</a> — 米国連邦政府の調達要件。 +- [正式な適合ドキュメント](#正式な適合ドキュメント) — 調達用の適合レポート (VPAT) のリクエスト方法。 + +## FAQ + +<Faq> + <FaqItem question="{ProductName} は WCAG に準拠していますか?" indicatorPosition="end"> + 適合は、コンポーネント ライブラリ単体ではなく、完成したアプリケーションの特性です。{ProductName} は WCAG 2.1 Level AA を対象とし、コンポーネントごとの動作を上記の索引にドキュメント化していますが、結果を決定するのは、ユーザーが追加するマークアップ、コンテンツ、および構成です。上記の索引を使用して依存しているコンポーネントを確認し、ドキュメントどおりに動作しないものがあれば報告してください。 + </FaqItem> + + <FaqItem question="一部のコンポーネントが「未ドキュメント化」となっているのはなぜですか?" indicatorPosition="end"> + このステータスは、コンポーネント自身のドキュメントでその動作がまだ説明されていないことを意味します。コンポーネントが基準を満たしていないという記述ではありません。ドキュメント化されている動作とそうでない動作を区別できるように、ドキュメントがカバーしている内容を記録したものです。 + </FaqItem> + + <FaqItem question="第 508 条には、現在も独自の個別の規則がありますか?" indicatorPosition="end"> + いいえ。改訂版第 508 条標準 (2017 年公開、2018 年 1 月適用開始) は以前の §1194.22 の規則を置き換え、WCAG Level AA を参照により採用しているため、WCAG を満たすことで第 508 条にも対応できます。 + </FaqItem> + + <FaqItem question="準拠情報はカスタム テーマにも適用されますか?" indicatorPosition="end"> + 一部適用されます。キーボードと ARIA の動作はテーマ設定の影響を受けません。カラー コントラストは影響を受けます。色をオーバーライドすると、テキストが必要な比率を下回る可能性があります。テーマ設定のアクセシビリティで説明されているとおりに、カスタム パレットを検証してください。 + </FaqItem> + + <FaqItem question="コンポーネントのキーボード ショートカットはどこで確認できますか?" indicatorPosition="end"> + 上記のリファレンス列からリンクされている、コンポーネント自身のトピックで確認できます。グリッド ファミリは専用のキーボード ナビゲーション トピックを共有しています。 + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/jp/components/interactivity/chat.mdx b/docs/xplat/src/content/jp/components/interactivity/chat.mdx index 480c538d71..5a876cd492 100644 --- a/docs/xplat/src/content/jp/components/interactivity/chat.mdx +++ b/docs/xplat/src/content/jp/components/interactivity/chat.mdx @@ -227,12 +227,12 @@ const ChatExample = () => { } ``` -その後、`messageCreated` イベントにフックして、作成されたメッセージをコレクションに追加することで、クライアントから送信されたメッセージを同期できます。 +`Messages` コレクションは、ユーザーがメッセージを送信すると自動的に更新されます。`MessageCreated` イベントを処理して、メッセージを永続化したり、その他の副作用を実行したりできます。イベントの詳細を `Messages` に再度追加しないでください: ```cs public void OnMessageCreated(IgbChatMessageEventArgs e) { - Messages = Messages.Append(e.Detail).ToArray(); + Console.WriteLine($"Message created: {e.Detail.Text}"); } ``` @@ -243,15 +243,57 @@ public void OnMessageCreated(IgbChatMessageEventArgs e) ### プロパティ <ApiLink type="Chat" /> コンポーネントは、その状態と構成を制御できるいくつかの重要なプロパティを公開します。 -| 名前 | 説明 | -| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `messages` | チャットに表示されるメッセージの配列 (<ApiLink type="ChatMessage" />[])。表示するメッセージを制御するためにバインド可能。 | -| `draftMessage` | 未送信メッセージ。`text` とオプションの `attachments` を含むオブジェクト。メッセージ下書きの保存や復元に便利。 | -| `options` | 現在のユーザー ID、入力プレースホルダー、許可されるファイル タイプ、クイック リプライサジェスト、入力遅延、カスタム レンダラーなどのチャット設定 (<ApiLink type="ChatOptions" />)。 | -| `resourceStrings` | ラベル、ヘッダー、システム テキストのローカライズ文字列。多言語対応に使用。 | +| 名前 | 説明 | +| --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| <PlatformBlock for="Blazor">`Messages`</PlatformBlock><PlatformBlock for="WebComponents,React">`messages`</PlatformBlock> | チャットに表示される双方向のメッセージの配列 (<ApiLink type="ChatMessage" />[])。ユーザーがメッセージを送信すると、Chat は渡されたコレクションを更新します。 | +| <PlatformBlock for="Blazor">`DraftMessage`</PlatformBlock><PlatformBlock for="WebComponents,React">`draftMessage`</PlatformBlock> | 未送信メッセージ。`text` とオプションの `attachments` を含むオブジェクト。メッセージ下書きの保存や復元に便利。 | +| <PlatformBlock for="Blazor">`Options`</PlatformBlock><PlatformBlock for="WebComponents,React">`options`</PlatformBlock> | 現在のユーザー ID、入力プレースホルダー、許可されるファイル タイプ、クイック リプライサジェスト、入力遅延、カスタム レンダラーなどのチャット設定 (<ApiLink type="ChatOptions" />)。 | +| <PlatformBlock for="Blazor">`ResourceStrings`</PlatformBlock><PlatformBlock for="WebComponents,React">`resourceStrings`</PlatformBlock> | ラベル、ヘッダー、システム テキストのローカライズ文字列。多言語対応に使用。 | 上記のプロパティを使用することで、Chat の UI をアプリケーションの状態やバックエンドと簡単に同期させることができます。 +#### 双方向のメッセージ コレクション + +<PlatformBlock for="WebComponents,React">`messages`</PlatformBlock><PlatformBlock for="Blazor">`Messages`</PlatformBlock> コレクションは双方向です。アプリケーションが表示するメッセージを提供し、会話が進むにつれて Chat が元のコレクションを更新します。ユーザーがメッセージを送信すると、そのコレクションへの参照を保持しているコードから、新しく作成されたメッセージにアクセスできます。 + +<PlatformBlock for="WebComponents">`igcMessageCreated`</PlatformBlock><PlatformBlock for="React">`onMessageCreated`</PlatformBlock><PlatformBlock for="Blazor">`MessageCreated`</PlatformBlock> イベントは、永続化やその他の副作用のための通知です。作成されたメッセージをコレクションに再度追加しないでください。 + +元のコレクションを変更せずに残す必要がある場合は、シャロー コピーを Chat に渡します。既存のメッセージ オブジェクトは引き続き共有されます。これらのオブジェクトも独立させる必要がある場合は、コピーしたコレクションを構築する際に、各メッセージの新しいインスタンスを作成してください。 + +<PlatformBlock for="WebComponents"> + + +```ts +const chatMessages = [...originalMessages]; +chat.messages = chatMessages; +``` + +</PlatformBlock> + +<PlatformBlock for="React"> + + +```tsx +const chatMessages = [...originalMessages]; + +return <IgrChat messages={chatMessages} options={options} />; +``` + +</PlatformBlock> + +<PlatformBlock for="Blazor"> + + +```cs +IgbChatMessage[] chatMessages = originalMessages.ToArray(); +``` + +```razor +<IgbChat Messages="chatMessages" Options="Options"></IgbChat> +``` + +</PlatformBlock> + <PlatformBlock for="WebComponents, React"> ### 添付 diff --git a/docs/xplat/src/content/jp/components/layouts/virtual-scroll.mdx b/docs/xplat/src/content/jp/components/layouts/virtual-scroll.mdx new file mode 100644 index 0000000000..b5dbdd5708 --- /dev/null +++ b/docs/xplat/src/content/jp/components/layouts/virtual-scroll.mdx @@ -0,0 +1,710 @@ +--- +title: "Virtual Scroll" +description: "Virtual Scroll は、ビューポート内のアイテムと少量のバッファーのみをレンダリングするコンポーネントであり、大量のリストでもスムーズにスクロールできます。" +keywords: "{Platform} Virtual Scroll, virtualization, virtual list, large lists, infinite scroll, remote data, {ProductName}" +last_updated: "2026-09-17" +license: MIT +mentionedTypes: ["VirtualScroll"] +relatedComponents: ["List", "Card"] +_language: ja +llms: + description: "{ProductName} Virtual Scroll は、ビューポート内のアイテムと設定可能なバッファーのみを DOM 内に保持することで、大量のリストをレンダリングするコンポーネントです。" +--- +import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; +import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; +import Sample from 'igniteui-astro-components/components/mdx/Sample.astro'; +import ApiLink from 'igniteui-astro-components/components/mdx/ApiLink.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; + +# Virtual Scroll コンポーネント + +{ProductName} Virtual Scroll は、ビューポート内のアイテムと設定可能なバッファーのみを DOM 内に保持することで、大量のリストをレンダリングするコンポーネントです。スクロールバーはコレクション全体に及ぶため、10 万件のアイテムを持つ仮想リストでも通常のリストと同じようにスクロールできます。 + +## ライブ デモ + +<PlatformBlock for="Angular"> + +<Sample src="/data-display/virtual-scroll-overview" height={560} alt="Angular Virtual Scroll with 100,000 employees" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +<Sample src="/layouts/virtual-scroll/overview" height={560} alt="{Platform} Virtual Scroll with 100,000 employees" /> + +</PlatformBlock> + +## 構造 + +{Platform} Virtual Scroll は、表示されているアイテムと設定可能なバッファーをレンダリングし、そのトラックはコレクション全体のスクロール範囲を保持します。 + +{/*TODO: add the Virtual Scroll anatomy image and render it with the <Anatomy> component.*/} + +<PlatformBlock for="Angular"> + +```text +igx-virtual-scroll — scrollable viewport (role="list") +└── .igx-virtual-scroll__track — provides the collection's scroll range + └── .igx-virtual-scroll__content — positions the rendered window + └── .igx-virtual-item — one wrapper per rendered item (data-index); hosts the item template +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```text +igc-virtual-scroll — scrollable viewport +└── [part="virtualization-track"] — provides the collection's scroll range + └── [part="virtualization-content"] — positions the rendered window + └── div[data-vs-index] — one wrapper per rendered item; hosts the item template +``` + +</PlatformBlock> + +## 作業の開始 + +<PlatformBlock for="Angular"> + +[作業の開始](../general/getting-started.mdx) のトピックに従って {ProductName} をセットアップし、<ApiLink type="VirtualScroll" /> と、アイテム テンプレートをマークする `IgxVirtualItemDirective` をインポートします。 + +```ts +import { Component } from '@angular/core'; +import { IgxVirtualItemDirective, IgxVirtualScrollComponent } from 'igniteui-angular/virtual-scroll'; + +@Component({ + selector: 'app-employees', + imports: [IgxVirtualScrollComponent, IgxVirtualItemDirective], + templateUrl: './employees.component.html' +}) +export class EmployeesComponent { + public items = Array.from({ length: 100_000 }, (_, i) => ({ name: `Item ${i}` })); +} +``` + +```html +<igx-virtual-scroll [data]="items" style="height: 400px"> + <ng-template igxVirtualItem let-item let-index="index"> + <div class="row">{{ index }}: {{ item.name }}</div> + </ng-template> +</igx-virtual-scroll> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +[作業の開始](../general-getting-started.mdx) のトピックに従って {ProductName} をセットアップし、<ApiLink type="VirtualScroll" /> を登録して、アイテム テンプレートとデータを指定します。 + +```ts +import { defineComponents, IgcVirtualScrollComponent } from 'igniteui-webcomponents'; +import type { VirtualScrollItemContext } from 'igniteui-webcomponents'; +import { html } from 'lit'; + +defineComponents(IgcVirtualScrollComponent); + +const virtualScroll = document.querySelector('igc-virtual-scroll') as IgcVirtualScrollComponent<Item>; +virtualScroll.itemTemplate = (ctx: VirtualScrollItemContext<Item>) => + html`<div class="row">${ctx.index}: ${ctx.value.name}</div>`; +virtualScroll.data = Array.from({ length: 100_000 }, (_, i) => ({ name: `Item ${i}` })); +``` + +```html +<igc-virtual-scroll style="height: 400px"></igc-virtual-scroll> +``` + +</PlatformBlock> + +Virtual Scroll のホストには、垂直スクロールの場合は固定の高さ、水平スクロールの場合は固定の幅が必要です。コンテンツに合わせてサイズが拡大するホストには、埋めるべきビューポートがありません。 + +### 前提条件とバージョン互換性 + +<PlatformBlock for="Angular"> + +| 要件 | 値 | +| --- | --- | +| パッケージ | `igniteui-angular` (MIT) | +| エントリ ポイント | `igniteui-angular/virtual-scroll` | +| コンポーネントが最初にリリースされたバージョン | 22.2.0 | + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +| 要件 | 値 | +| --- | --- | +| パッケージ | `igniteui-webcomponents` (MIT) | +| コンポーネントが最初にリリースされたバージョン | 7.3.0 | +| アイテム テンプレート | Lit の `html` タグ。`lit` は `igniteui-webcomponents` の依存関係ですが、直接インポートする場合は自身の依存関係にも追加してください。 | + +</PlatformBlock> + +## 使用方法 + +### アイテム テンプレート + +Virtual Scroll のアイテム テンプレートは、アイテムとコレクション全体におけるその位置を受け取ります。位置に依存するコンテンツ(交互のスタイルや `aria-posinset`、`aria-setsize` など)には、インデックスと合計件数を使用します。 + +<PlatformBlock for="Angular"> + +`ng-template` に `igxVirtualItem` を付与するか、<ApiLink type="VirtualScroll" member="itemTemplate" label="itemTemplate" /> を通じて他の場所で定義されたテンプレートを渡します(こちらが優先されます)。テンプレートのコンテキストは `$implicit`(アイテム)、`index`、`count`、`first`、`last`、`even`、`odd` を提供します。 + +```html +<igx-list> + <igx-virtual-scroll [data]="employees" [estimatedItemSize]="64" style="height: 480px"> + <ng-template igxVirtualItem let-employee let-index="index" let-count="count"> + <igx-list-item [attr.aria-posinset]="index + 1" [attr.aria-setsize]="count"> + <igx-avatar igxListThumbnail shape="circle" [initials]="employee.initials"></igx-avatar> + <span igxListLineTitle>{{ employee.name }}</span> + <span igxListLineSubTitle>{{ employee.email }}</span> + </igx-list-item> + </ng-template> + </igx-virtual-scroll> +</igx-list> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +<ApiLink type="VirtualScroll" member="itemTemplate" label="itemTemplate" /> に、Lit テンプレートを返す関数を設定します。この関数は、`value`(アイテム)、`index`、`count`、`isFirst`、`isLast` を持つ `VirtualScrollItemContext` を受け取ります。アイテム テンプレートがない場合、コンポーネントは何もレンダリングしません。 + +```ts +virtualScroll.itemTemplate = (ctx: VirtualScrollItemContext<Employee>) => html` + <igc-list-item aria-posinset=${ctx.index + 1} aria-setsize=${ctx.count}> + <igc-avatar slot="start" shape="circle" initials=${ctx.value.initials}></igc-avatar> + <span slot="title">${ctx.value.name}</span> + <span slot="subtitle">${ctx.value.email}</span> + </igc-list-item> +`; +``` + +</PlatformBlock> + +### データ + +Virtual Scroll の <ApiLink type="VirtualScroll" member="data" label="data" /> コレクションは参照によって比較されます。リストを更新するには新しい配列を割り当てる必要があります。`push` などでバインドされた配列をその場で変更しても更新されません。 + +<PlatformBlock for="Angular"> + +```ts +this.employees = [...this.employees, newEmployee]; +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```ts +virtualScroll.data = [...virtualScroll.data, newEmployee]; +``` + +</PlatformBlock> + +`data` が変更されると、コンポーネントは最初に変更されたインデックスより前のアイテムの測定済みサイズを保持し、それ以降のアイテムはレンダリング時に再度測定します。追加操作ではすべての既存の測定値が保持されますが、置換、フィルタリング、並べ替えでは最初に変更されたアイテム以降の測定値が破棄されます。 + +### 推定アイテム サイズ + +Virtual Scroll の <ApiLink type="VirtualScroll" member="estimatedItemSize" label="estimatedItemSize" /> は、アイテムがレンダリングされて測定されるまでのピクセル単位のサイズです(デフォルトは `50`)。アイテムは異なるサイズを持つことができ、測定されたサイズがそれぞれ推定値を置き換えます。アイテムが測定される前にスクロールバーと `scrollToIndex` を正確に保つため、推定値はアイテムの平均サイズに近い値に設定してください。 + +<PlatformBlock for="Angular"> + +```html +<igx-virtual-scroll [data]="employees" [estimatedItemSize]="80" style="height: 480px">...</igx-virtual-scroll> +``` + +<Sample src="/data-display/virtual-scroll-variable-size" height={560} alt="Angular Virtual Scroll with variable item heights" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-virtual-scroll estimated-item-size="80" style="height: 480px"></igc-virtual-scroll> +``` + +<Sample src="/layouts/virtual-scroll/variable-size" height={560} alt="{Platform} Virtual Scroll with variable item heights" /> + +</PlatformBlock> + +アイテムはボーダー ボックスで測定されるため、マージンはアイテムのサイズに含まれません。マージンの代わりに、パディング、またはアイテム内の `gap` を使用してアイテム間の間隔を設定してください。 + +### 方向 + +Virtual Scroll の <ApiLink type="VirtualScroll" member="orientation" label="orientation" /> は、スクロール軸を `vertical`(デフォルト)または `horizontal` に設定します。水平リストでは、各アイテムに幅を、ホストに高さを設定してください。右から左のコンテキストでは、水平スクロールとアイテムの配置が反転します。 + +<PlatformBlock for="Angular"> + +```html +<igx-virtual-scroll orientation="horizontal" [data]="employees" [estimatedItemSize]="220" style="height: 200px"> + <ng-template igxVirtualItem let-employee> + <div style="width: 220px">...</div> + </ng-template> +</igx-virtual-scroll> +``` + +<Sample src="/data-display/virtual-scroll-horizontal" height={260} alt="Angular Virtual Scroll with horizontal cards" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-virtual-scroll orientation="horizontal" estimated-item-size="220" style="height: 200px"></igc-virtual-scroll> +``` + +<Sample src="/layouts/virtual-scroll/horizontal" height={260} alt="{Platform} Virtual Scroll with horizontal cards" /> + +</PlatformBlock> + +### オーバー スキャン + +Virtual Scroll の <ApiLink type="VirtualScroll" member="overScan" label="overScan" /> は、ビューポートの各端を超えてレンダリングされる追加アイテムの数です(デフォルトは `2`)。値を大きくすると、高速スクロール中の空白領域が減りますが、レンダリングする要素が増えます。 + +<PlatformBlock for="Angular"> + +```html +<igx-virtual-scroll [data]="items" [overScan]="6" style="height: 400px">...</igx-virtual-scroll> +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```html +<igc-virtual-scroll over-scan="6" style="height: 400px"></igc-virtual-scroll> +``` + +</PlatformBlock> + +### インデックスへのスクロール + +Virtual Scroll の <ApiLink type="VirtualScroll" member="scrollToIndex" label="scrollToIndex" /> メソッドは、アイテムが表示される位置までスクロールします。オプションはネイティブの `scrollIntoView` と同じで、`block`(`start`、`center`、`end`、または `nearest`)、水平リスト用の `inline`、`behavior`(`auto` または `smooth`)を指定できます。まだレンダリングされていないアイテムには推定サイズしかないため、コンポーネントは到達した位置のアイテムを測定して位置を補正します。返されるプロミスは最終的な位置が確定すると解決されます。 + +<PlatformBlock for="Angular"> + +```ts +private readonly virtualScroll = viewChild.required(IgxVirtualScrollComponent); + +public async goTo(index: number): Promise<void> { + await this.virtualScroll().scrollToIndex(index, { block: 'center' }); +} +``` + +<Sample src="/data-display/virtual-scroll-scroll-to-index" height={620} alt="Angular Virtual Scroll scrolling to an index" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```ts +await virtualScroll.scrollToIndex(index, { block: 'center' }); +``` + +<Sample src="/layouts/virtual-scroll/scroll-to-index" height={620} alt="{Platform} Virtual Scroll scrolling to an index" /> + +</PlatformBlock> + +`block: 'nearest'` を指定した場合、アイテムがすでに完全に表示されているときは位置が変更されません。コレクションの範囲外のインデックスは、最初または最後のアイテムにクランプされます。 + +### 無限スクロール + +<PlatformBlock for="Angular"> + +Virtual Scroll の <ApiLink type="VirtualScroll" member="dataRequest" label="dataRequest" /> 出力は、リモート データからの追加専用の読み込みをサポートします。これは、レンダリングされたウィンドウが `data` の末尾に近づいたときや、読み込まれたアイテムが最初のレンダリングでビューポートを満たさない場合に発行されます。要求されたアイテムを新しい配列として追加します。 + +```html +<igx-virtual-scroll [data]="employees()" [estimatedItemSize]="64" (dataRequest)="loadMore($event)" style="height: 440px"> + <ng-template igxVirtualItem let-employee>...</ng-template> +</igx-virtual-scroll> +``` + +```ts +public readonly employees = signal<Employee[]>(firstPage); + +public loadMore(request: VirtualScrollDataRequest): void { + this.service.fetch(request.startIndex, request.count).subscribe(page => { + this.employees.update(current => [...current, ...page]); + }); +} +``` + +<Sample src="/data-display/virtual-scroll-infinite-scroll" height={560} alt="Angular Virtual Scroll loading more items while scrolling" /> + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +Virtual Scroll の `igcDataRequest` イベントは、リモート データからの追加専用の読み込みをサポートします。これは、レンダリングされたウィンドウが `data` の末尾に近づいたときや、読み込まれたアイテムが最初のレンダリングでビューポートを満たさない場合に発行されます。要求されたアイテムを新しい配列として追加します。 + +```ts +virtualScroll.addEventListener('igcDataRequest', (event: CustomEvent<VirtualScrollDataRequest>) => { + const { startIndex, count } = event.detail; + fetchEmployees(startIndex, count).then(page => { + virtualScroll.data = [...virtualScroll.data, ...page]; + }); +}); +``` + +<Sample src="/layouts/virtual-scroll/infinite-scroll" height={560} alt="{Platform} Virtual Scroll loading more items while scrolling" /> + +</PlatformBlock> + +一度に保留できるデータ要求は 1 つだけで、次の要求は `data` が次に変更された後に発行されます。`data` が空の場合は要求が発行されないため、最初のページは自分で読み込む必要があります。ソースにこれ以上アイテムがない場合は追加を停止してください。コンポーネントは同じ開始インデックスを再度要求することはありません。 + +<PlatformBlock for="Angular"> + +### ページ分割されたデータ + +Angular Virtual Scroll の <ApiLink type="VirtualScroll" member="dataWindow" label="dataWindow" /> 入力は、`data` の代わりに大きなコレクションの 1 ページをバインドします。リストは `totalCount` と同じ長さになるため、ページのみがメモリ上にある間もスクロールバーはコレクション全体に及び、ページがカバーしていないインデックスは何もレンダリングしません。 + +```ts +interface VirtualDataWindow<T> { + readonly items: readonly T[]; // the loaded page + readonly startIndex: number; // the index of items[0] in the whole collection + readonly totalCount: number; // the size of the whole collection +} +``` + +<ApiLink type="VirtualScroll" member="stateChange" label="stateChange" /> が報告する範囲から次のページを読み込みます。遅い応答が新しいページを上書きしないように、前の要求をキャンセルします。 + +```html +<igx-virtual-scroll [dataWindow]="page()" [estimatedItemSize]="64" (stateChange)="onStateChange($event)" style="height: 440px"> + <ng-template igxVirtualItem let-employee>...</ng-template> +</igx-virtual-scroll> +``` + +```ts +public readonly page = signal<VirtualDataWindow<Employee>>({ items: [], startIndex: 0, totalCount: 100_000 }); +private pending?: Subscription; + +public onStateChange(state: VirtualScrollState): void { + const page = this.page(); + if (state.startIndex >= page.startIndex && state.endIndex < page.startIndex + page.items.length) { + return; // The loaded page already covers the range. + } + + const startIndex = Math.max(0, state.startIndex - 30); + const count = state.endIndex + 30 - startIndex + 1; + + this.pending?.unsubscribe(); + this.pending = this.service.fetch(startIndex, count).subscribe(result => { + this.page.set({ items: result.items, startIndex, totalCount: result.total }); + }); +} +``` + +<Sample src="/data-display/virtual-scroll-paged-data" height={560} alt="Angular Virtual Scroll loading pages of a remote collection" /> + +`totalCount` が変わらない間は、インデックスごとに測定済みサイズが保持されます。フィルタリング結果のように `totalCount` が異なるページは再度測定されます。`dataWindow` がバインドされている間は `dataRequest` は発行されません。コンポーネントはインデックスごとに 1 つのサイズ エントリを保存するため、そのメモリは `totalCount` に応じて増加します。100 万件のアイテムでおおよそ 17 MB です。 + +</PlatformBlock> + +### レイアウト完了 + +Virtual Scroll の <ApiLink type="VirtualScroll" member="layoutComplete" label="layoutComplete" /> プロパティは、現在のレンダリング、それによってトリガーされる測定、そしてそれらがスケジュールするレンダリングが完了したときに解決されるプロミスです。`data` の変更、スクロール、リサイズの後にレンダリングされたアイテムを読み取る前に、これを待機してください。 + +<PlatformBlock for="Angular"> + +```ts +this.employees = await firstValueFrom(this.service.fetchAll()); +await this.virtualScroll().layoutComplete; +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +```ts +virtualScroll.data = await fetchEmployees(); +await virtualScroll.layoutComplete; +``` + +</PlatformBlock> + +### 使用すべき場合と使用すべきでない場合 + +{/*TODO: add the Virtual Scroll Do/Don't guidance image from Indigo.Design when it is available.*/} + +<PlatformBlock for="Angular"> + +**使用すべき場合:** ディレクトリ、フィード、ログ、カードのストリップなど、一度にレンダリングするには大きすぎる長いリストに対して Virtual Scroll を使用します。これには、スクロール中にリモート データを読み込むリストも含まれます。 + +**使用すべきでない場合:** 短いリストは [List](../list.mdx) と `@for` で直接レンダリングします。列、並べ替え、フィルタリングを伴う表形式のデータには [Grid](../grid/grid.mdx) を使用します。仮想化を行わずにリッチなアイテムの少量のセットを表示するには [Card](../card.mdx) を使用します。 + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +**使用すべき場合:** ディレクトリ、フィード、ログ、カードのストリップなど、一度にレンダリングするには大きすぎる長いリストに対して Virtual Scroll を使用します。これには、スクロール中にリモート データを読み込むリストも含まれます。 + +**使用すべきでない場合:** 短いリストは [List](../grids/list.mdx) で直接レンダリングします。仮想化を行わずにリッチなアイテムの少量のセットを表示するには [Card](./card.mdx) を使用します。 + +</PlatformBlock> + +| 推奨 | 非推奨 | +| --- | --- | +| ホストに固定の高さ(垂直)または幅(水平)を指定する。 | ホストのサイズをコンテンツに合わせて拡大させる。 | +| `estimatedItemSize` をアイテムの平均サイズに近い値に設定する。 | はるかに大きい、または小さいアイテムに対してデフォルトの 50px を維持する。 | +| コレクションが変更されたときに新しい配列を割り当てる。 | バインドされた配列をその場で変更する。 | +| パディングまたは `gap` でアイテム間の間隔を設定する。 | マージンでアイテム間の間隔を設定する。 | + +## プロパティ + +<PlatformBlock for="Angular"> + +| 名前 | 型 | デフォルト | 説明 | +| --- | --- | --- | --- | +| <ApiLink type="VirtualScroll" member="data" label="data" /> | `T[]` | `[]` | 仮想化するコレクション。参照によって比較されます。 | +| <ApiLink type="VirtualScroll" member="dataWindow" label="dataWindow" /> | `VirtualDataWindow<T> \| null` | `null` | 設定されている間、`data` の代わりに使用される、より大きなコレクションの 1 ページ。 | +| <ApiLink type="VirtualScroll" member="orientation" label="orientation" /> | `'vertical' \| 'horizontal'` | `'vertical'` | スクロール軸。 | +| <ApiLink type="VirtualScroll" member="overScan" label="overScan" /> | `number` | `2` | ビューポートの各端を超えてレンダリングされる追加アイテムの数。 | +| <ApiLink type="VirtualScroll" member="estimatedItemSize" label="estimatedItemSize" /> | `number` | `50` | アイテムが測定されるまでのピクセル単位のサイズ。0 以下の値の場合は `50` が使用されます。 | +| <ApiLink type="VirtualScroll" member="itemTemplate" label="itemTemplate" /> | `TemplateRef<IgxVsItemContext<T>> \| null` | `null` | アイテム テンプレート。投影された `ng-template[igxVirtualItem]` より優先されます。 | +| <ApiLink type="VirtualScroll" member="layoutComplete" label="layoutComplete" /> | `Promise<void>`(読み取り専用) | — | レンダリングとアイテムの測定が落ち着くと解決されます。 | + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +| 名前 | 型 | デフォルト | 説明 | +| --- | --- | --- | --- | +| <ApiLink type="VirtualScroll" member="data" label="data" /> | `T[]` | `[]` | 仮想化するコレクション。参照によって比較されます。プロパティのみ。 | +| <ApiLink type="VirtualScroll" member="orientation" label="orientation" /> | `'vertical' \| 'horizontal'` | `'vertical'` | スクロール軸。属性: `orientation`。 | +| <ApiLink type="VirtualScroll" member="overScan" label="overScan" /> | `number` | `2` | ビューポートの各端を超えてレンダリングされる追加アイテムの数。属性: `over-scan`。 | +| <ApiLink type="VirtualScroll" member="estimatedItemSize" label="estimatedItemSize" /> | `number` | `50` | アイテムが測定されるまでのピクセル単位のサイズ。0 以下の値の場合は `50` が使用されます。属性: `estimated-item-size`。 | +| <ApiLink type="VirtualScroll" member="itemTemplate" label="itemTemplate" /> | `VirtualScrollItemTemplate<T> \| null` | `null` | 各アイテムをレンダリングする関数。プロパティのみ。 | +| <ApiLink type="VirtualScroll" member="layoutComplete" label="layoutComplete" /> | `Promise<void>`(読み取り専用) | — | レンダリングとアイテムの測定が落ち着くと解決されます。 | + +</PlatformBlock> + +## メソッド + +| 名前 | 戻り値 | 説明 | +| --- | --- | --- | +| <ApiLink type="VirtualScroll" member="scrollToIndex" label="scrollToIndex(index: number, options?: ScrollIntoViewOptions)" /> | `Promise<void>` | `index` のアイテムをビューにスクロールし、最終的なスクロール位置が確定すると完了します。 | + +## イベント + +<PlatformBlock for="Angular"> + +| 名前 | ペイロード | 説明 | +| --- | --- | --- | +| <ApiLink type="VirtualScroll" member="stateChange" label="stateChange" /> | `VirtualScrollState` | レンダリングされたウィンドウが変更されたときに発行されます: `startIndex`、`endIndex`、`viewportSize`、`totalSize`。 | +| <ApiLink type="VirtualScroll" member="dataRequest" label="dataRequest" /> | `VirtualScrollDataRequest` | レンダリングされたウィンドウが `data` の末尾に近づいたときに発行されます: `startIndex`、`count`。`dataWindow` がバインドされている間は発行されません。 | + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +| 名前 | 詳細 | 説明 | +| --- | --- | --- | +| `igcStateChange` | `VirtualScrollState` | レンダリングされたウィンドウが変更されたときに発行されます: `startIndex`、`endIndex`、`viewportSize`、`totalSize`。 | +| `igcDataRequest` | `VirtualScrollDataRequest` | レンダリングされたウィンドウが `data` の末尾に近づいたときに発行されます: `startIndex`、`count`。 | + +</PlatformBlock> + +## スタイル設定 + +{Platform} Virtual Scroll には独自のテーマはありません。ビューポートのレイアウトのみを行い、レンダリングされたアイテムはアイテム テンプレート内の要素やコンポーネントからスタイルを継承します。 + +<PlatformBlock for="Angular"> + +ホストのサイズを設定し、[構造](#構造) のクラスを使用してレンダリングされたアイテムを対象にします。 + +```scss +.employees igx-virtual-scroll { + block-size: 480px; +} + +.employees .igx-virtual-item:nth-child(even) { + background: var(--ig-gray-100); +} +``` + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +コンポーネントはライト DOM 内にレンダリングされるため、通常のセレクターでレンダリングされたアイテムに到達できます。デフォルトのスタイルはホストに `18.75rem` の高さを与えます。ビューポートのサイズを変更するには、この高さを上書きしてください。 + +```css +igc-virtual-scroll.employees { + height: 480px; +} + +igc-virtual-scroll.employees [data-vs-index]:nth-child(even) { + background: var(--ig-gray-100); +} +``` + +</PlatformBlock> + +## アクセシビリティ + +{Platform} Virtual Scroll は、レンダリングされたウィンドウのみを DOM に保持するため、アイテム テンプレートはコレクション全体の中での各アイテムの位置を公開する必要があります。 + +### キーボード インタラクション + +{Platform} Virtual Scroll はキー ハンドラーを追加しません。ホストはネイティブのスクロール コンテナーであり、フォーカスされたスクロール コンテナーはブラウザーのキーでスクロールします。 + +| キー | アクション | +| --- | --- | +| 上矢印 / 下矢印 | 垂直リストをスクロールします。 | +| 左矢印 / 右矢印 | 水平リストをスクロールします。 | +| Page Up / Page Down | ビューポート 1 つ分ほどスクロールします。 | +| Home / End | コレクションの先頭または末尾にスクロールします。 | + +ホストには `tabindex` がありません。フォーカス可能なコンテンツがないスクロール コンテナーがフォーカスを受け取れるかどうかはブラウザーによって異なるため、アイテムにフォーカス可能な要素が含まれない場合は、ホストに `tabindex="0"` を設定してください。ビューから外れてスクロールされたアイテムは DOM から削除されるため、削除されたアイテム内のフォーカスは失われます。 + +### スクリーン リーダー / ARIA + +<PlatformBlock for="Angular"> + +- ホストには `role="list"` が設定されています。トラック、コンテンツ要素、アイテム ラッパーには `role="presentation"` が設定されています。`igx-list-item` のように `role="listitem"` をレンダリングするアイテムは、そのリストのアイテムとして公開されます。 +- `index` と `count` のテンプレート変数を `aria-posinset` と `aria-setsize` にマップします。 +- フォーカス可能なホストには、`aria-label` または `aria-labelledby` でアクセシブルな名前を付けてください。 + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +- トラック、コンテンツ要素、アイテム ラッパーには `role="presentation"` が設定されています。ホストにはロールがありません。`igc-list` のようにリストのロールを持つ要素の中に配置するか、アイテムが `role="listitem"` をレンダリングする場合はホストに `role="list"` を設定してください。 +- `index` と `count` のコンテキスト プロパティを `aria-posinset` と `aria-setsize` にマップします。 +- フォーカス可能なホストには、`role="list"` のようにアクセシブルな名前をサポートするロールを設定し、`aria-label` または `aria-labelledby` で名前を付けてください。 + +</PlatformBlock> + +### アクセシビリティ準拠 + +Infragistics は、{ProductName} が対象とするアクセシビリティ標準を [アクセシビリティ準拠](../interactivity/accessibility-compliance.mdx) トピックで文書化しています。このトピックは Virtual Scroll に対する準拠の主張を行うものではありません。表にはコンポーネントが提供する内容が記載されており、その後のリストにはアプリケーションが追加する必要がある内容が記載されています。 + +| 基準 | コンポーネントが要件をサポートする方法 | +| --- | --- | +| [1.3.1 情報及び関係性](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships) | ラッパーは表示専用であるため、リスト構造はホストとアイテム テンプレートから提供され、`aria-posinset` と `aria-setsize` で各アイテムの位置を公開できます。 | +| [2.1.1 キーボード](https://www.w3.org/WAI/WCAG21/Understanding/keyboard) | ホストはネイティブのスクロール コンテナーであり、フォーカスを得るとキーボードでスクロールできます。キーボードでホストに到達できるかどうかはアプリケーションに依存します。以下のリストを参照してください。 | + +ユーザー側の責任: + +- アイテムにフォーカス可能な要素が含まれない場合は、`tabindex="0"` を設定してホストをキーボードで到達可能にし、アクセシブルな名前を付けてください。 +- アイテム テンプレートから `aria-posinset` と `aria-setsize` でアイテムの位置を公開してください。 +- アイテム テンプレートに適したリスト セマンティクスを提供してください([スクリーン リーダー / ARIA](#スクリーン-リーダー--aria) を参照)。 +- 選択などのアプリケーションの状態は、レンダリングされたアイテム要素ではなくデータ内に保持してください。 + +## トラブルシューティング + +### Virtual Scroll がアイテムをレンダリングしないのはなぜですか? + +ホストにスクロール軸方向のサイズがない、アイテム テンプレートがない、または `data` が空です。ホストに固定の高さ(垂直)または幅(水平)を設定し、アイテム テンプレートを設定して、バインドされたコレクションを確認してください。 + +### アイテムを追加してもリストが更新されないのはなぜですか? + +Virtual Scroll は `data` を参照によって比較するため、その場での変更は検出されません。`[...items, newItem]` のように新しい配列を割り当ててください。 + +### スクロール中にスクロールバーのサイズが変わるのはなぜですか? + +まだレンダリングされていないアイテムは `estimatedItemSize` を使用しており、アイテムが測定されるにつれて合計サイズが補正されます。`estimatedItemSize` をアイテムの平均サイズに近い値に設定してください。 + +### リストの下の方でアイテムの位置がずれるのはなぜですか? + +マージンはアイテムの測定済みサイズに含まれません。アイテムのマージンをパディングまたはアイテム内の `gap` に置き換えてください。 + +<PlatformBlock for="Angular"> + +### ドロップダウンやダイアログの中のリストのアイテムが 1 フレーム遅れて表示されるのはなぜですか? + +開くまで非表示になっているコンテナーは、それを表示する変更検出パスの時点ではサイズを持たないため、ホストはそのレンダリングの後に測定され、アイテムは次のフレームでレンダリングされます。レンダリングされたアイテムを読み取るのは `layoutComplete` の解決後に行ってください。 + +### igxForOf リストを Virtual Scroll に置き換えるにはどうすればよいですか? + +Virtual Scroll は実行時にアイテムを測定し、独自のスクロール コンテナーを作成するため、`igxForOf` のコンテナー サイズおよびスクロール コンテナーの入力には相当するものがありません。`igxForOf` ディレクティブは非推奨となり、代わりに Virtual Scroll の使用が推奨されます。既存のリストは引き続き動作しますが、単一の軸を仮想化する新しいリストには Virtual Scroll を使用してください。 + +| igxForOf | Virtual Scroll | +| --- | --- | +| `*igxFor="let item of data"` | `ng-template igxVirtualItem` を伴う `[data]="data"` | +| `igxForScrollOrientation` | `orientation` | +| `igxForContainerSize` | CSS で設定するホストの高さまたは幅 | +| `igxForItemSize` | `estimatedItemSize`(開始時の推定値。アイテムは測定されます) | +| `igxForScrollContainer` | 不要: ホストがスクロール コンテナーです | +| `scrollTo(index)` | プロミスを返す `scrollToIndex(index, options)` | +| `chunkLoad`、`chunkPreload` | `stateChange` | +| `totalItemCount` を伴う `igxForRemote` | `totalCount` を伴う `dataWindow`、または追加専用の読み込み向けに `dataRequest` を伴う `data` | +| `index`、`count`、`first`、`last`、`even`、`odd` | 同じテンプレート変数 | + +グリッドは独自の行と列の仮想化を維持します。[グリッドの仮想化](../grid/virtualization.mdx) を参照してください。 + +</PlatformBlock> + +## 既知の制限 + +- {Platform} Virtual Scroll は単一の軸を仮想化します。行と列の両方を仮想化するにはグリッドが必要です。 +- ビューから外れてスクロールされたアイテムは、フォーカスと内部状態とともに DOM から削除されます。 + +<PlatformBlock for="Angular"> + +- `dataWindow` を使用する場合、`totalCount` は維持されるが同じインデックスに異なるレコードが配置されるページでは、それらの行が再度レンダリングされるまで以前のレコードの測定済みサイズが保持されます。 + +</PlatformBlock> + +## API リファレンス + +- <ApiLink type="VirtualScroll" /> + +## 依存関係 + +<PlatformBlock for="Angular"> + +Angular Virtual Scroll は、他のコンポーネントへの依存関係を持ちません。`igniteui-angular/virtual-scroll` から `IgxVirtualScrollComponent` と `IgxVirtualItemDirective` をインポートしてください。構造スタイルはコンポーネントに同梱されています。 + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +{Platform} Virtual Scroll は他のコンポーネントへの依存関係を持たず、独自のテーマも必要としません。アイテム テンプレートのレンダリングには `lit` を使用し、アイテム テンプレート内のコンポーネントにはテーマ スタイルシートが必要です。 + +</PlatformBlock> + +## その他のリソース + +- [{ProductName} **フォーラム (英語)**]({ForumsLink}) +- [{ProductName} **GitHub**]({GithubLink}) + +## 関連コンポーネント + +<PlatformBlock for="Angular"> + +- [List](../list.mdx) - 短いリストや、仮想化されたリストのコンテナーとして List を使用します。 +- [Card](../card.mdx) - リッチなアイテムの少量のセット、または水平の Virtual Scroll のアイテムとしてカードを使用します。 +- [Virtual ForOf ディレクティブ](../for-of.mdx) - 既存のリストで使用されるディレクティブ ベースの仮想化。 + +</PlatformBlock> + +<PlatformBlock for="WebComponents"> + +- [List](../grids/list.mdx) - 短いリストや、仮想化されたリストのコンテナーとして List を使用します。 +- [Card](./card.mdx) - リッチなアイテムの少量のセット、または水平の Virtual Scroll のアイテムとしてカードを使用します。 + +</PlatformBlock> + +## FAQ + +<Faq> + <FaqItem question="Virtual Scroll はどれくらいの数のアイテムを処理できますか?" indicatorPosition="end"> + {Platform} Virtual Scroll は、ビューポート内のアイテムとオーバー スキャン バッファーのみを DOM に保持するため、コレクションのサイズによってレンダリングされる要素の数は変わりません。コレクションの合計サイズがブラウザーのスクロール制限を超える場合、Virtual Scroll はコレクションをブラウザーがサポートするスクロール範囲にマッピングします。 + </FaqItem> + <FaqItem question="Virtual Scroll のアイテムは同じサイズである必要がありますか?" indicatorPosition="end"> + {Platform} Virtual Scroll のアイテムは、レンダリングされた時点でそれぞれが測定されるため、異なるサイズにすることができます。アイテムが測定される前にスクロールバーを正確に保つため、`estimatedItemSize` をアイテムの平均サイズに近い値に設定してください。 + </FaqItem> + <FaqItem question="Virtual Scroll を特定のアイテムまでスクロールするにはどうすればよいですか?" indicatorPosition="end"> + {Platform} Virtual Scroll の `scrollToIndex` メソッドを、アイテムのインデックスと、省略可能な `block` および `behavior` オプションを指定して呼び出します。このメソッドは、補正された位置が安定すると解決されるプロミスを返します。 + </FaqItem> + <FaqItem question="ユーザーがスクロールしている間に Virtual Scroll にリモート データを読み込むにはどうすればよいですか?" indicatorPosition="end"> + <PlatformBlock for="Angular"> + Angular Virtual Scroll は 2 つのモデルをサポートします。追加専用の読み込みでは `dataRequest` を処理し、要求されたアイテムを含む新しい配列を割り当てます。コレクションを一度に 1 ページずつ読み込む場合は、`dataWindow` をバインドし、`stateChange` が報告する範囲を読み込みます。 + </PlatformBlock> + <PlatformBlock for="WebComponents"> + {Platform} Virtual Scroll は、`igcDataRequest` イベントを通じて追加専用の読み込みをサポートします。イベントを処理し、要求されたアイテムを含む新しい配列を `data` に割り当てます。 + </PlatformBlock> + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/jp/components/themes/accessibility.mdx b/docs/xplat/src/content/jp/components/themes/accessibility.mdx new file mode 100644 index 0000000000..1beef1b022 --- /dev/null +++ b/docs/xplat/src/content/jp/components/themes/accessibility.mdx @@ -0,0 +1,290 @@ +--- +title: "{Platform} スタイル設定およびテーマ | {Platform} アクセシビリティ | インフラジスティックス" +description: "{ProductName} のテーマ設定エンジンがアクセシビリティをどのようにサポートするか - テキスト コントラストの自動計算、相対的なテキストのスケーリング、および色覚異常に対応したチャート パレット。" +keywords: "{ProductName}, Infragistics, Accessibility, Contrast, WCAG, Styling, Themes, インフラジスティックス, アクセシビリティ, コントラスト, スタイル設定, テーマ" +license: MIT +last_updated: "2026-08-31" +mentionedTypes: [] +_language: ja +llms: + description: "{ProductName} は、実行時に WCAG のコントラストしきい値に照らしてテキスト カラーを計算し、すべてのタイプ スケールを相対値に保ち、オプトインの色覚異常対応チャート パレットを提供します。" +--- + +{/*This topic serves Angular, React, Web Components and Blazor. Angular-specific content sits in Angular-only platform blocks; everything else is shared. The Angular doc set still carries its own copy at docs/angular/src/content/en/components/themes/accessibility.mdx because this page is excluded for Angular in src/content/en/toc.json; keep the two in sync until that exclude is lifted. Never write a literal PlatformBlock tag in prose or a comment - the generator strips blocks with a regex that does not skip comments, and an unpaired tag swallows the rest of the page.*/} + +import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro'; +import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBlock.astro'; +import Faq from 'igniteui-astro-components/components/mdx/Faq.astro'; +import FaqItem from 'igniteui-astro-components/components/mdx/FaqItem.astro'; + +# {ProductName} のアクセシビリティ + +{ProductName} のテーマ設定エンジンは、スタイル設定レイヤーにアクセシビリティを組み込んでいます。任意の背景色に対するテキスト カラーを実行時に計算して WCAG のコントラストしきい値に照らして測定し、すべてのタイプ スケールを相対単位で表現してユーザーの設定に合わせてテキストをスケーリングし、色覚異常のある読者向けのオプトインのカラー パレットを提供します。 + +## 概要 + +{ProductName} のアクセシビリティは、それぞれ独立して構成する 2 つのレイヤーによって提供されます。 + +| レイヤー | 担当する範囲 | ドキュメントの場所 | +|---|---|---| +| **テーマ設定エンジン** (`igniteui-theming`) | カラー コントラスト、テキスト サイズ、チャートのカラー パレット、およびカスタム コントロールを支援技術から到達可能に保つスタイル設定ユーティリティ。 | このページ。 | +| **コンポーネント ライブラリ** (`{PackageCommon}`) | キーボード操作、フォーカスの移動、ARIA のロールと状態、およびスクリーン リーダーの読み上げ。 | [アクセシビリティ準拠](../interactivity/accessibility-compliance.mdx) および各コンポーネントのトピック。 | + +このページでは 1 つ目のレイヤーを扱います。テーマ設定エンジンでスタイル設定するすべてのコンポーネント (エンジンの上に独自に構築するコンポーネントを含む) に適用される機能について説明します。 + +以下の表は、アプリケーションを最終的に使用する人に対してテーマ設定エンジンが行うことをまとめたものです。各行はアプリケーションの基盤となる入力であり、適合の結果ではありません。カラーを指定するのはユーザー自身であり、エンジンは WCAG のしきい値に照らして測定した組み合わせを生成しますが、完成した製品が適合しているかどうかの検証は引き続きユーザーの責任です。 + +| ユーザーの状況 | テーマ設定エンジンが提供するもの | +|---|---| +| 色付きのボタン、チップ、バッジ上で読みやすいテキストを必要としている | 生成されるすべてのパレット カラー (指定したブランド カラーを含む) について前景色がブラウザーで計算され、構成した WCAG コントラスト レベル (デフォルトは AA) に照らして測定されます。 | +| ブラウザーのデフォルトのフォント サイズを拡大している | すべてのタイプ スケールが相対単位で表現され、ライブラリがページのフォント サイズを固定することはありません。 | +| 色覚異常があり、チャートを読む | 一般的な色覚異常の形態でも区別しやすいように選ばれた、オプトインのチャート パレット。 | +| 光に敏感なため、ダーク インターフェイスを好む | 提供される 4 つのテーマそれぞれに対する完全なダーク パレット。 | +| カスタム スタイルのフォーム コントロールでスクリーン リーダーを使用している | ネイティブ入力を視覚的に非表示にしながら、アクセシビリティ ツリーには残すスタイル設定ユーティリティ。 | + +## はじめる前に + +このページの内容のうち何に依存できるかは、3 つの前提によって決まります。 + +**テーマ設定エンジンはスタイルを設定するものであり、セマンティクスを追加するものではありません。** ARIA ロール、キーボード処理、およびフォーカス管理は、テーマではなくコンポーネント ライブラリから提供されます。テーマを適用するだけでは、カスタム コントロールはアクセシブルになりません。 + +**コントラストの計算は、生成されたパレット カラーに適用されます。** エンジンは、`palette()` ジェネレーターによって生成されたパレットの前景色を計算します。個々のコンポーネント テーマでは、特定の前景トークンと特定の背景トークンを手動で組み合わせている場合もあります。それらの組み合わせはテーマごとに設定されており、以下で説明するコントラストの計算によって生成されるものではありません。コンポーネント トークンを直接オーバーライドする場合は、[`contrast()`](#コントラスト比を自分で確認する) で結果を検証してください。 + +**完成した製品の適合性はユーザー自身が検証する必要があります。** エンジンが制御するのは、パレット、計算された組み合わせ、タイプ スケールといった入力であり、アプリケーションがそれらをどのように使用するかではありません。ブランド カラーから構築したパレットは完全な適合に達することができますが、エンジンがその結果を保証することはできません。適合を表明する前に、レンダリングされた結果を確認してください。 + +<DocsAside type="note"> +このページの機能は、テーマ設定エンジンの動作を説明するものです。製品としての {ProductName} の適合宣言ではありません。コンポーネントごとの適合情報については、[アクセシビリティ準拠](../interactivity/accessibility-compliance.mdx) を参照してください。 +</DocsAside> + +## 次のステップ + +- パレット カラーの上にテキストを配置する場合は、前景色をハードコーディングする代わりに、[`contrast-color()`](#ブランド-カラーでテキストを読みやすく保つ) を使用します。 +- アプリケーションでチャートをレンダリングする場合は、[色覚異常に対応したチャート パレット](#色覚異常に対応したチャート-パレットを有効にする) を有効にします。 +- 独自に導入するカスタムのカラーの組み合わせは、リリース前に [`contrast()`](#コントラスト比を自分で確認する) で確認します。 +- [Theming MCP サーバー](../ai/theming-mcp.mdx) でパレットを生成する場合、サーバーはパレットの構築時にサーフェスとグレーのコントラストを WCAG のしきい値に照らして確認します。 + +## 利用可能なツール + +テーマ設定エンジンは、このページで説明するアクセシビリティの動作のために、以下の Sass 関数とミックスインを公開しています。 + +<DocsAside type="note"> +これらは Sass API です。<PlatformBlock for="Angular">[Sass を使用したテーマ設定](sass/index.mdx)</PlatformBlock><PlatformBlock for="React, WebComponents, Blazor">[Sass によるカスタマイズ](overview.mdx#sass-によるカスタマイズ)</PlatformBlock> で説明されているように、ロード パスから `igniteui-theming` を解決できる Sass ビルドが必要です。代わりにビルド済みのテーマ CSS を使用する場合でも、計算されたコントラスト カラーは利用できます。各パレット カラーを対応する `-contrast` 変数 (例: `var(--ig-primary-500-contrast)`) と組み合わせ、`--ig-contrast-level` でしきい値を設定してください。チャート パレット、`hide-default()`、および `contrast()` と `luminance()` 関数には、CSS のみの同等機能はありません。 +</DocsAside> + +| ツール | シグネチャ | 機能 | +|---|---|---| +| `contrast-color()` | `contrast-color($palette: null, $color: primary, $variant: 500, $opacity: null)` | パレット カラーに対して読みやすい前景色を返します。すべての引数は省略可能です。`$palette` を省略すると、シェードは対応する CSS 変数を通じて解決されます。 | +| `adaptive-contrast()` | `adaptive-contrast($color)` | CSS 変数に格納されたカラーを含め、渡された任意のカラーに対して読みやすい前景色を返します。 | +| `contrast()` | `contrast($background, $foreground)` | 2 つのカラー間の WCAG コントラスト比を返します。 | +| `luminance()` | `luminance($color)` | カラーの相対輝度を `0` (黒) から `1` (白) の範囲で返します。 | +| `configure-colors()` | `configure-colors($enhanced-accessibility: null)` | チャート テーマを色覚異常に対応したパレットに切り替えます。 | +| `hide-default()` | `@include hide-default()` | ネイティブ入力を視覚的に非表示にしながら、アクセシビリティ ツリーには残します。 | + +## 一般的なワークフロー + +### ブランド カラーでテキストを読みやすく保つ + +パレットから取得したすべての背景には、ハードコーディングした `black` や `white` ではなく、`contrast-color()` を組み合わせます。 + +```scss +.my-component { + background: color($color: 'primary', $variant: 500); + color: contrast-color($color: 'primary', $variant: 500); +} +``` + +テーマが既に出力している変数を使用した、プレーン CSS での同じ組み合わせ: + +```css +.my-component { + background: var(--ig-primary-500); + color: var(--ig-primary-500-contrast); +} +``` + +パレット由来ではないカラー (テナント カラー、ユーザー設定、実行時に設定される値など) には、`adaptive-contrast()` を使用します。 + +```scss +.my-component { + --bg: #09f; + + background: var(--bg); + color: adaptive-contrast(var(--bg)); +} +``` + +`adaptive-contrast()` は相対カラー式の薄いラッパーであるため、Sass を使用しなくても同じ結果を得られます。`--y-contrast` はテーマによって定義されます。 + +```css +.my-component { + --bg: #09f; + + background: var(--bg); + color: hsla(from color(from var(--bg) var(--y-contrast)) h 0 l / 1); +} +``` + +計算はビルド時ではなくブラウザーで行われます。スタイルシートのコンパイル後に背景色が変わると、前景色もそれに合わせて再計算されるため、実行時のテーマ切り替えやテナントごとのブランディングでも組み合わせが維持されます。 + +<DocsAside type="note"> +`adaptive-contrast()` は黒と白のどちらかを選択します。選択できる結果がこの 2 つであるため、中間色の背景に対してこの仕組みで達成できる比率は最大でも約 4.6:1 に制限されます。これは、通常のテキストに対する WCAG AA のしきい値 4.5:1 を満たしており、エンジンがデフォルトで構成されているレベルです。7:1 の AAA しきい値に達するために、この仕組みだけに頼らないでください。AAA に達するには、それを可能にする十分に明るい、または十分に暗い背景色を選択する必要があります。 +</DocsAside> + +### コントラスト レベルを設定する + +計算された前景色は、`--ig-contrast-level` CSS 変数に保持されている WCAG のしきい値に照らして測定されます。この変数のデフォルトは `var(--ig-wcag-aa)` です。`a`、`aa`、`aaa` の 3 つのレベルが事前定義されています。 + +パレットを生成する際に、アプリケーション全体のレベルを設定します。 + +```scss +@include palette($palette, $contrast-level: 'aaa'); +``` + +ページの一部だけレベルを引き上げるには、そのスコープで変数をオーバーライドします。 + +```css +.high-contrast-panel { + --ig-contrast-level: var(--ig-wcag-aaa); +} +``` + +コントラスト レベルは、計算された前景色が黒と白の間で切り替わる輝度のしきい値を移動させるものであり、選択できる 2 つのカラーを変更するものではありません。また、`aaa` を設定するだけで組み合わせが適合するわけではなく、それは選択した背景色によって決まります。[`contrast()`](#コントラスト比を自分で確認する) で検証してください。生成されるコントラスト変数については、[パレット](palettes.mdx) を参照してください。 + +### ユーザーのブラウザー設定に合わせてテキストをスケーリングする + +構成は必要ありません。提供される 4 つのテーマのすべてのタイプ スケールは、`font-size`、`line-height`、`letter-spacing`、およびマージンを `rem()` 関数で表現しているため、出力されるすべての値はルートのフォント サイズに対する相対値になります。 + +ライブラリは、基準サイズを読み取り可能な値として記録します。 + +```css +--ig-base-font-size: 16px; +``` + +ライブラリが `html { font-size: … }` ルールを出力することはありません。このルールを記述することは、テーマ設定システムがデフォルトのテキストを拡大しているユーザーの設定を上書きしてしまう最も一般的な原因であるため、これは重要です。ライブラリは基準サイズを読み取るだけなので、ブラウザーでより大きなデフォルト サイズを設定しているユーザーには、{ProductName} のテキストもより大きく表示されます。 + +これは、スタイル設定レイヤーにおいて WCAG 2.1 <a href="https://www.w3.org/WAI/WCAG21/Understanding/resize-text.html" target="_blank" rel="noopener noreferrer">1.4.4 テキストのサイズ変更</a> (レベル AA) に対応するものです。 + +### コントラストのしきい値を上下させる + +計算された前景色が黒から白に切り替わるレベルは CSS 変数に保持されているため、Sass を使用せずに変更できます。デフォルトは AA です。 + +```css +:root { + --ig-contrast-level: var(--ig-wcag-aaa); +} +``` + +Sass では、`palette()` および `adaptive-contrast()` ミックスインが `a`、`aa`、または `aaa` を直接受け取ります。 + +### 色覚異常に対応したチャート パレットを有効にする + +チャートは一般に色相のみでシリーズを区別しますが、これは色覚異常のある読者には機能しません。テーマ設定エンジンには、一般的な色覚異常の形態でも区別しやすいカラーで構成された 2 つ目のチャート パレットが用意されています。 + +このパレットは**デフォルトでは無効**です。`configure-colors()` で有効にします。 + +```scss +// Include at the top level, before your theme includes. +@include configure-colors($enhanced-accessibility: true); +``` + +これにより、すべてのチャート テーマがアクセシブルなカラー セットを使用するようになります。チャートのブラシはテーマの生成時に設定されるため、この機能には Sass が必要です。ビルド済みのテーマ CSS には、ブラシ用の変数は公開されていません。 + +<PlatformBlock for="Angular"> + +{ProductName} では、同じスイッチをセットアップ時にも利用できます。 + +```scss +@include core($enhanced-accessibility: true); +``` + +</PlatformBlock> + +<DocsAside type="note"> +チャートが意味を伝える手段は、色だけであってはなりません。グレースケールでもチャートが機能するように、このパレットを直接ラベル、区別しやすいマーカー、または破線パターンと組み合わせてください。 +</DocsAside> + +### コントラスト比を自分で確認する + +エンジンは WCAG の相対輝度の計算式を実装して公開しているため、ライブラリが使用しているものと同じ実装で独自のカラーの選択を確認できます。 + +```scss +$ratio: contrast(#09f, #000); // 7 +$lum: luminance(#09f); // 0.3 +``` + +コンポーネント トークンを直接オーバーライドする場合や、パレット ジェネレーターが生成していないカラーの組み合わせを導入する場合には、常にこれを使用してください。これら 2 つはコンパイル時に実行されるため、CSS に同等の機能はありません。スタイルシートで比率を計算することはできません。 + +### スクリーン リーダーから隠さずに入力を非表示にする + +カスタム スタイルのチェックボックス、ラジオ、スイッチは、通常、セマンティクスとキーボード動作のために、その下にネイティブ入力を保持しています。これは `hide-default()` で非表示にします。 + +```scss +.my-checkbox input { + @include hide-default(); +} +``` + +このミックスインは固定された宣言のセットに展開されるため、CSS に直接記述することもできます。 + +```css +.my-checkbox input { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + border: none; + clip: rect(0, 0, 0, 0); + outline: 0; + pointer-events: none; + overflow: hidden; + appearance: none; +} +``` + +このミックスインは、入力をアクセシビリティ ツリーに残したまま画面外に移動させるため、入力のロール、キーボード動作、およびスクリーン リーダーの読み上げは維持されます。代わりに `display: none` や `visibility: hidden` を使用すると、コントロールは支援技術から完全に取り除かれ、視覚に頼らずに操作するすべての人にとってコンポーネントが機能しなくなります。 + +### ダーク テーマを使用する + +提供される 4 つのテーマ (Material、Bootstrap、Fluent、Indigo) にはそれぞれ、ライト パレットと並んで完全なダーク パレットが用意されています。ダーク表示は、光に敏感な人を含む一部のユーザーにとってアクセシビリティ上の必要性であるため、見た目の好みではなく、サポート対象の構成として扱ってください。選択方法については、[パレット](palettes.mdx) を参照してください。 + +## トラブルシューティング + +**スタイルを変更したコンポーネントのテキストが読みにくい。** 背景トークンを置き換えたものの、それと組になる前景トークンを置き換えていない可能性があります。前景色は固定値ではなく `contrast-color()` または `adaptive-contrast()` で設定し、`contrast()` で結果を確認してください。 + +**`$contrast-level: 'aaa'` を設定したが、カラーがあまり変わらない。** コントラスト レベルは、計算された前景色が黒と白の間で切り替わる輝度のしきい値を移動させるものです。前景色に色味を付けるものではないため、達成可能な比率を前述の上限を超えて引き上げることはできません。AAA に達するには、背景色そのものを変更してください。 + +**アクセシブルなパレットを有効にしたが、チャートのカラーが変わらない。** `configure-colors()` は、チャート テーマが生成される前にインクルードする必要があります。インクルードをテーマのインクルードより上に移動してください。 + +**ブラウザーのフォント サイズを大きくしてもテキストが大きくならない。** アプリケーション自身のスタイルに `html { font-size: … }` ルールや `px` 単位の `font-size` 値がないか確認してください。テーマ設定エンジンはどちらも出力しません。 + +## その他のリソース + +- [パレット](palettes.mdx) — パレット カラーと、それに対応するコントラスト カラーがどのように生成されるか。 +- [タイポグラフィ](typography.mdx) — タイプ スケールとそのカスタマイズ方法。 +- [アクセシビリティ準拠](../interactivity/accessibility-compliance.mdx) — コンポーネントごとの適合情報。 +- <a href="https://www.w3.org/WAI/WCAG21/quickref/" target="_blank" rel="noopener noreferrer">WCAG 2.1 クイック リファレンス</a> — このページで参照している達成基準。 +- <a href="https://www.w3.org/WAI/ARIA/apg/patterns/" target="_blank" rel="noopener noreferrer">WAI-ARIA オーサリング プラクティス</a> — インタラクション パターンごとに期待されるキーボードおよび ARIA の動作。 + +## FAQ + +<Faq> + <FaqItem question="Ignite UI のテーマを適用すると、アプリケーションはアクセシブルになりますか?" indicatorPosition="end"> + いいえ。テーマ設定エンジンが担当するのは、カラー コントラスト、テキスト サイズ、およびチャート パレットです。キーボード操作、ARIA セマンティクス、およびスクリーン リーダーのサポートは、コンポーネント ライブラリと独自のマークアップから提供されます。 + </FaqItem> + + <FaqItem question="独自のブランド カラーを指定した場合でも、読みやすいテキストになりますか?" indicatorPosition="end"> + はい。パレットを通じて使用されるカラーについては、構成したレベル (デフォルトは AA) に照らして測定されます。前景色は、実行時を含め、背景が変わるたびにブラウザーで再計算されます。手動で設定した組み合わせは計算の対象外なので、<code>contrast()</code> で検証してください。 + </FaqItem> + + <FaqItem question="コントラスト レベルの設定は、実際には何を変更しますか?" indicatorPosition="end"> + 計算された前景色が黒から白に切り替わる輝度のしきい値を移動させます。選択できる 2 つのカラーは変わらないため、この仕組みで達成できる最大の比率が上がることはありません。 + </FaqItem> + + <FaqItem question="色覚異常に対応したチャート パレットは、デフォルトで有効ですか?" indicatorPosition="end"> + いいえ。<code>configure-colors($enhanced-accessibility: true)</code><PlatformBlock for="Angular">、またはセットアップ時に <code>core($enhanced-accessibility: true)</code></PlatformBlock> で有効にします。 + </FaqItem> + + <FaqItem question="テキストのスケーリングのために何か構成する必要はありますか?" indicatorPosition="end"> + いいえ。すべてのタイプ スケールは既に相対値であり、ライブラリがページのフォント サイズを設定することはありません。テキストがスケーリングされない場合は、アプリケーション自身のスタイルを確認してください。 + </FaqItem> +</Faq> diff --git a/docs/xplat/src/content/jp/components/themes/overview.mdx b/docs/xplat/src/content/jp/components/themes/overview.mdx index 835b80fbda..609335f810 100644 --- a/docs/xplat/src/content/jp/components/themes/overview.mdx +++ b/docs/xplat/src/content/jp/components/themes/overview.mdx @@ -74,13 +74,16 @@ import PlatformBlock from 'igniteui-astro-components/components/mdx/PlatformBloc {ProductName} を使用すると、ライブラリによってエクスポートされた `ConfigureTheme` 関数を使用して、実行時にコンポーネントのテーマを切り替えることができます。 -それを呼び出して、4 つの有効なテーマ (`bootstrap`、`material`、`fluent`、または `indigo`) のいずれかを文字列として渡すと、読み込まれたコンポーネントのスタイルが変更されます。 +この関数は、最初の引数としてテーマ (`bootstrap`、`material`、`fluent`、または `indigo`) を、2 番目の引数としてオプションのバリアント (`light` または `dark`) を受け取ります。現在アクティブなバリアントを維持するには、バリアントを省略します。 ```ts import { configureTheme } from "igniteui-webcomponents"; // Sets material as the theme to be used by all components configureTheme("material"); + +// Sets material and switches to its dark variant +configureTheme("material", "dark"); ``` <DocsAside type="info" title="情報"> @@ -88,6 +91,25 @@ configureTheme("material"); </DocsAside> </PlatformBlock> +## Sass によるカスタマイズ + +上記のテーマ ファイルはビルド済みの CSS であり、このセクションのトピックでは CSS 変数をオーバーライドしてカスタマイズします。[パレット](palettes.mdx)、[タイポグラフィ](typography.mdx)、[エレベーション](elevations.mdx)、および[構成](configuration.mdx)を参照してください。この方法ではビルド構成は不要で、ほとんどのカスタマイズに対応できます。 + +一部の機能は、変数を通じてではなくコンパイル時に実行されるため、Sass からのみ利用できます。[アクセシビリティ](accessibility.mdx)トピックのコントラスト関数とチャート パレット関数が主な例です。これらを使用するには、`igniteui-theming` をインストールしてインポートします: + +```scss +@use 'igniteui-theming' as *; + +// Required for $material-type-scale, $indigo-type-scale, and similar preset variables +@use 'igniteui-theming/sass/typography/presets' as *; + +// Required for $material-elevations and $indigo-elevations +@use 'igniteui-theming/sass/elevations/presets' as *; +``` + +<DocsAside type="note"> +`@use 'igniteui-theming' as *;` が解決されない場合は、Sass コンパイラーのロード パスに `node_modules` が含まれていません。Vite では `css.preprocessorOptions.scss.loadPaths` を、Next.js では `sassOptions.loadPaths` を設定してください。 +</DocsAside> <PlatformBlock for="React, WebComponents"> diff --git a/docs/xplat/src/content/jp/components/themes/palettes.mdx b/docs/xplat/src/content/jp/components/themes/palettes.mdx index 954d03b7fc..f65a20de95 100644 --- a/docs/xplat/src/content/jp/components/themes/palettes.mdx +++ b/docs/xplat/src/content/jp/components/themes/palettes.mdx @@ -60,34 +60,45 @@ import DocsAside from 'igniteui-astro-components/components/mdx/DocsAside.astro' 上記のカラーに加えて、各カラー バリエーションに **Level AA** [WCAG](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html) 準拠の `contrast` カラーも含まれています。つまり、対応する `contrast` カラー バリエーションをベースカラー バリエーションの前景カラーとして安全に使用できます。 <DocsAside type="info" title="情報"> -コントラスト カラーはビルド時に生成されるため、CSS 変数をオーバーライドしても、対応するコントラスト カラーは更新されません。 +コントラスト カラーは、対応するシェード カラーから実行時に計算される CSS 相対カラーであるため、ベース カラー バリエーションをオーバーライドすると、そのコントラスト カラーも一緒に更新されます。 </DocsAside> -以下は、Light Bootstrap パレットで宣言された `primary` カラーの抜粋です。 +以下は、Light Material パレットで宣言された `primary` カラーの抜粋です。 ```css :root { //... --ig-primary-500: #09f; - --ig-primary-500-contrast: black; + --ig-primary-500-contrast: hsla(from color(from var(--ig-primary-500) var(--y-contrast)) h 0 l / 1); + --ig-primary-seed: #09f; --ig-primary-600: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-primary-600-contrast: black; + --ig-primary-600-contrast: hsla(from color(from var(--ig-primary-600) var(--y-contrast)) h 0 l / 1); --ig-primary-700: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.81)); //... --ig-secondary-400: hsl(from var(--ig-secondary-500) h calc(s * 0.875) calc(l * 1.08)); - --ig-secondary-400-contrast: black; + --ig-secondary-400-contrast: hsla(from color(from var(--ig-secondary-400) var(--y-contrast)) h 0 l / 1); --ig-secondary-500: #df1b74; - --ig-secondary-500-contrast: white; + --ig-secondary-500-contrast: hsla(from color(from var(--ig-secondary-500) var(--y-contrast)) h 0 l / 1); --ig-secondary-600: hsl(from var(--ig-secondary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-secondary-600-contrast: white; + --ig-secondary-600-contrast: hsla(from color(from var(--ig-secondary-600) var(--y-contrast)) h 0 l / 1); //... + --ig-wcag-a: 0.31; + --ig-wcag-aa: 0.185; + --ig-wcag-aaa: 0.178; + --ig-contrast-level: var(--ig-wcag-aa); + --y: clamp(0, (y / var(--ig-contrast-level) - 1) * -infinity, 1); + --y-contrast: xyz-d65 var(--y) var(--y) var(--y); } ``` すべてのプライマリ カラー バリエーションは、1 つの基本変数カラー バリエーション `--ig-primary-500` から派生します。他のカラー変数 (`--ig-secondary-500`、`--ig-surface-500` など) にも同様のことが当てはまります。他のバリエーションは、メイン変数カラー バリエーション `500` を受け取り、割り当てられた変数バリエーション (`600`、`700` など) に応じて `saturation` と `lightness` を変更する相対カラー関数 `hsl()` によって生成されます。`primary`、`secondary`、`surface`、またはその他のカラーのすべてのバリエーションを実行時に変更できるため、この方法を使用することにしました。 -<DocsAside type="warning" title="警告"> -コントラスト カラーは他の部分のように CSS 実行時に生成されないため、メイン カラー バリエーション (`500`) を変更しても、コントラスト カラーは更新されません。手動で変更する必要があります。この動作は今後のリリースで改善され、コントラスト カラーも CSS 実行時に計算されるようになります。 +番号付きのバリエーションに加えて、各カラーは、パレットの生成元となったベース カラーを変更せずに保持する `seed` 変数を公開します。`primary`、`secondary`、およびその他の有彩色では、seed は `500` バリエーションと一致します。`gray` では一致しません。`--ig-gray-seed` はグレースケールの派生元となったカラー (サーフェス カラーの輝度から選択された黒または白) を記録し、`--ig-gray-500` は生成された中間トーンです。 + +コントラスト カラーは、ベース カラーの輝度と選択されたコントラスト レベルから CSS 実行時に計算され、黒と白のうち読みやすい方が選択されます。この計算はカスケードの一部であるため、メイン カラー バリエーション (`500`) を変更すると、そのコントラスト カラーも一緒に更新されます。手動での操作は必要ありません。 + +<DocsAside type="info" title="情報"> +しきい値は `--ig-contrast-level` に保持されており、デフォルトは `var(--ig-wcag-aa)` です。任意のスコープでオーバーライドして、`var(--ig-wcag-a)` または `var(--ig-wcag-aaa)` に切り替えることができます。ビルド済みの CSS を使用する代わりに Sass からテーマをコンパイルする場合、`palette` および `adaptive-contrast` ミックスインは `a`、`aa`、または `aaa` を直接受け取ります。[アクセシビリティ](accessibility.mdx)を参照してください。 </DocsAside> ## パレットの定義 diff --git a/docs/xplat/src/content/jp/toc.json b/docs/xplat/src/content/jp/toc.json index ffb8e7231c..6db78e12f5 100644 --- a/docs/xplat/src/content/jp/toc.json +++ b/docs/xplat/src/content/jp/toc.json @@ -2221,11 +2221,9 @@ "href": "layouts/accordion.mdx" }, { - "exclude": [ - "Angular" - ], "name": "アバター", - "href": "layouts/avatar.mdx" + "href": "layouts/avatar.mdx", + "updated": true }, { "exclude": [ @@ -2437,11 +2435,9 @@ "updated": true }, { - "exclude": [ - "Angular" - ], "name": "ボタン", - "href": "inputs/button.mdx" + "href": "inputs/button.mdx", + "updated": true }, { "name": "ボタン グループ", @@ -2513,16 +2509,10 @@ "href": "inputs/dropdown.mdx" }, { - "exclude": [ - "Angular" - ], "name": "アイコン", "href": "layouts/icon.mdx" }, { - "exclude": [ - "Angular" - ], "name": "アイコン ボタン", "href": "inputs/icon-button.mdx" }, @@ -2588,11 +2578,9 @@ "href": "inputs/rating.mdx" }, { - "exclude": [ - "Angular" - ], "name": "スイッチ", - "href": "inputs/switch.mdx" + "href": "inputs/switch.mdx", + "updated": true }, { "exclude": [ @@ -2608,6 +2596,15 @@ "name": "ハイライト", "href": "inputs/highlight.mdx" }, + { + "exclude": [ + "React", + "Blazor" + ], + "name": "仮想スクロール", + "href": "layouts/virtual-scroll.mdx", + "new": true + }, { "name": "インタラクション", "header": true @@ -2765,6 +2762,11 @@ "name": "スタイル", "href": "themes/styles.mdx" }, + { + "name": "アクセシビリティ", + "href": "themes/accessibility.mdx", + "new": true + }, { "name": "カスタム Tailwind クラス", "href": "themes/tailwind.mdx", diff --git a/package-lock.json b/package-lock.json index dc86737fb6..595a39a371 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,25 +12,24 @@ "docs/xplat" ], "dependencies": { - "@astrojs/markdown-satteri": "^0.3.5", + "@astrojs/markdown-satteri": "^0.4.2", "astro-seo-schema": "^7.0.0", "gray-matter": "^4.0.3", - "igniteui-astro-components": "1.0.2", + "igniteui-astro-components": "1.3.0", "igniteui-theming": "^26.0.1", "igniteui-webcomponents": "^7.3.0-beta.1", "js-yaml": "^4.1.1", "jsdom": "^29.0.1", "pagefind": "^1.5.2", - "satteri": "^0.9.5", - "sharp": "0.35.3", + "satteri": "^0.10.5", "turndown": "^7.2.4", "turndown-plugin-gfm": "^1.0.2" }, "devDependencies": { - "@astrojs/mdx": "^7.0.5", - "@astrojs/ts-plugin": "^1.10.7", + "@astrojs/mdx": "^8.0.2", + "@astrojs/ts-plugin": "^1.10.12", "@types/jsdom": "^28.0.1", - "astro": "^7.2.2", + "astro": "^7.3.4", "cross-env": "^10.1.0", "cspell": "^9.2.2", "markdownlint-cli": "^0.49.1", @@ -49,10 +48,9 @@ "name": "angular-docs", "version": "1.0.0", "dependencies": { - "astro": "^7.2.2", + "astro": "^7.3.4", "docs-template": "file:../../", - "igniteui-astro-components": "1.0.2", - "sharp": "^0.35.3" + "igniteui-astro-components": "1.3.0" }, "devDependencies": { "cross-env": "^7.0.3", @@ -84,10 +82,9 @@ "name": "xplat-docs", "version": "0.0.1", "dependencies": { - "astro": "^7.2.2", + "astro": "^7.3.4", "docs-template": "file:../../", - "igniteui-astro-components": "1.0.2", - "sharp": "^0.35.3" + "igniteui-astro-components": "1.3.0" }, "devDependencies": { "cross-env": "^10.1.0", @@ -152,248 +149,185 @@ "dev": true, "license": "MIT" }, - "node_modules/@astrojs/compiler-binding": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.4.0.tgz", - "integrity": "sha512-x2RjDUuWfwLNtc3mjAdSRInwqh/rqbLar9cm/5FOMbHvmYZB7yfKewzSclAxWjIZsypJDXv1lhaP2WG+P8TK3g==", - "license": "MIT", - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@astrojs/compiler-binding-darwin-arm64": "0.4.0", - "@astrojs/compiler-binding-darwin-x64": "0.4.0", - "@astrojs/compiler-binding-linux-arm64-gnu": "0.4.0", - "@astrojs/compiler-binding-linux-arm64-musl": "0.4.0", - "@astrojs/compiler-binding-linux-x64-gnu": "0.4.0", - "@astrojs/compiler-binding-linux-x64-musl": "0.4.0", - "@astrojs/compiler-binding-wasm32-wasi": "0.4.0", - "@astrojs/compiler-binding-win32-arm64-msvc": "0.4.0", - "@astrojs/compiler-binding-win32-x64-msvc": "0.4.0" - } - }, - "node_modules/@astrojs/compiler-binding-darwin-arm64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.4.0.tgz", - "integrity": "sha512-ZVUwHundaQyFNjE6uoa0usaC0WOCitDCLS/4mdb4rOiJXwVUuKJBMxI5WMzXLWmamsXtK/Z//ifLXvV5Yeh4Hw==", - "cpu": [ - "arm64" - ], + "node_modules/@astrojs/markdown-satteri": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.4.2.tgz", + "integrity": "sha512-g4QehXnB/MzxQWnSf17NciFInMqEJy9948p8cc7zGg/r7995m0Ln5PMr3Xlnj24iey1LchaoZ3SzTOa3D4P/3w==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "dependencies": { + "@astrojs/internal-helpers": "0.11.0", + "@astrojs/prism": "4.0.2", + "github-slugger": "^2.0.0", + "satteri": "^0.10.3" } }, - "node_modules/@astrojs/compiler-binding-darwin-x64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.4.0.tgz", - "integrity": "sha512-FI6G8AY8u6fR1SI/QRR5yGMwtvZwP34CDmZpZ5HwJGa50UM1VISTLhqkhV4a476pmgd25X1Aur2dqw6hUnrlKA==", - "cpu": [ - "x64" - ], + "node_modules/@astrojs/markdown-satteri/node_modules/@astrojs/internal-helpers": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.11.0.tgz", + "integrity": "sha512-3rzxJ+xbo0+8YyqOzLziIN32wmsHdCjEVz2sGOpRxJ+Ben/KiLph4ItxBy1abEL+E8fkRzqjg0rfXmaHJGw9JA==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "dependencies": { + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "js-yaml": "^4.3.0", + "picomatch": "^4.0.4", + "retext-smartypants": "^6.2.0", + "shiki": "^4.0.2", + "smol-toml": "^1.6.0", + "unified": "^11.0.5" } }, - "node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.4.0.tgz", - "integrity": "sha512-lB9gLFJK7m82EnjaU8nlRBEfcwGNeHidW3sSjODTUjMNaoewVuUz9fwwdY5M4jiSXIqWLH3yl6TX8FTDKA74Sw==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], + "node_modules/@astrojs/mdx": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-8.0.2.tgz", + "integrity": "sha512-WedIVP2Bu8fXSzxb3ZYZ8xDrWWjf2SRKCneh52Llhoa+O3lcpHPhoZVP3FerlivUaH/0LJz2yVaCNvMdg0u8Bw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@astrojs/internal-helpers": "0.11.0", + "@astrojs/markdown-satteri": "0.4.2", + "es-module-lexer": "^2.0.0" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=22.12.0" + }, + "peerDependencies": { + "@astrojs/markdown-remark": "^7.3.0", + "@astrojs/markdown-satteri": "^0.4.0", + "astro": "^7.2.10" + }, + "peerDependenciesMeta": { + "@astrojs/markdown-remark": { + "optional": true + } } }, - "node_modules/@astrojs/compiler-binding-linux-arm64-musl": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.4.0.tgz", - "integrity": "sha512-HPbvWqbxFxyaoQJhLxCaSjtYBx9KBo7JGVzEFZCmMl968a2PsSH0UfiODYgYPXofTOIsIH2aoCcrHXML0IA3ig==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], + "node_modules/@astrojs/mdx/node_modules/@astrojs/internal-helpers": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.11.0.tgz", + "integrity": "sha512-3rzxJ+xbo0+8YyqOzLziIN32wmsHdCjEVz2sGOpRxJ+Ben/KiLph4ItxBy1abEL+E8fkRzqjg0rfXmaHJGw9JA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "dependencies": { + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "js-yaml": "^4.3.0", + "picomatch": "^4.0.4", + "retext-smartypants": "^6.2.0", + "shiki": "^4.0.2", + "smol-toml": "^1.6.0", + "unified": "^11.0.5" } }, - "node_modules/@astrojs/compiler-binding-linux-x64-gnu": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.4.0.tgz", - "integrity": "sha512-tQKolMxoJ/+0AmLWm1PmJ/i+z3i10ZU1bNuVjEDulCf48azEMtUNjTZgHJ5MPtpYRNc7dlETr8QujUfduzoC7Q==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], + "node_modules/@astrojs/prism": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.2.tgz", + "integrity": "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "prismjs": "^1.30.0" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=22.12.0" } }, - "node_modules/@astrojs/compiler-binding-linux-x64-musl": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.4.0.tgz", - "integrity": "sha512-5v5YymudsxMHp3NBLCS8BUlu5CRqeLtWD9cKS/4nIhIEHCbpz9okmVV6I0HWqmBAPhWYcDa3vw/vltYPrOQCTA==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], + "node_modules/@astrojs/telemetry": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.3.tgz", + "integrity": "sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "ci-info": "^4.4.0", + "dset": "^3.1.4", + "is-docker": "^4.0.0", + "package-manager-detector": "^1.6.0" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "18.20.8 || ^20.3.0 || >=22.0.0" } }, - "node_modules/@astrojs/compiler-binding-wasm32-wasi": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.4.0.tgz", - "integrity": "sha512-m/phuH3x3PREvv1OnkM44NoPh4MatUadix1fB1u5SvMLCyDTUZykDJbKnWf1cjnYmHdlB8HcjTjl6JrCqAIXcw==", - "cpu": [ - "wasm32" - ], + "node_modules/@astrojs/ts-plugin": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@astrojs/ts-plugin/-/ts-plugin-1.10.12.tgz", + "integrity": "sha512-EOT4VUYPGJTTHRcbWjAq7ABS79Q8X6sNq9k4a8sWoQmo8cLlrjCoUOO4LTxIbfsssNPmq68HHyk8rmh8+TdJTQ==", + "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.2.2" - }, - "engines": { - "node": ">=14.0.0" + "@astrojs/compiler": "^2.13.1", + "@astrojs/yaml2ts": "^0.2.4", + "@jridgewell/sourcemap-codec": "^1.5.5", + "@volar/language-core": "~2.4.28", + "@volar/typescript": "~2.4.28", + "vscode-languageserver-textdocument": "^1.0.12" } }, - "node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.4.0.tgz", - "integrity": "sha512-B9zYf3okEY83kM8gydlpH2BHP00w4ifxPqlYlWrgTwuD6wnkrJDCwBlgy1q31cERjCJRXN1lrE2VmkLvFjv/6g==", - "cpu": [ - "arm64" - ], + "node_modules/@astrojs/yaml2ts": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.4.tgz", + "integrity": "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "dependencies": { + "yaml": "^2.8.3" } }, - "node_modules/@astrojs/compiler-binding-win32-x64-msvc": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.4.0.tgz", - "integrity": "sha512-zB0Nrv0dGc0zZWPGDRmmETTPhDRqyZjAjk+gWMlVrJX5U89obpB3VUUE1ZiHxOCN5LQojeLK6O8L/dnoHolvNQ==", - "cpu": [ - "x64" - ], + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=6.9.0" } }, - "node_modules/@astrojs/compiler-rs": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.4.0.tgz", - "integrity": "sha512-koVikeon1kreEy+/JzLQRy3vzHHQVOjycs4degg4vFufKApZOwMZvSSAEztYNhmcQVfNVsVZZI4cEge3cexAbQ==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", - "dependencies": { - "@astrojs/compiler-binding": "0.4.0" - }, "engines": { - "node": ">=22.12.0" + "node": ">=6.9.0" } }, - "node_modules/@astrojs/internal-helpers": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.4.tgz", - "integrity": "sha512-nozZSy/mKYLqe4YrqbKtdOszedAfXYCtw3wZ0d+CAjz4GqQ4L9rl1ltIL5BlgwmYVinJg/RZ0MgGuWOdlyRZlA==", + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "license": "MIT", "dependencies": { - "@types/hast": "^3.0.4", - "@types/mdast": "^4.0.4", - "js-yaml": "^4.3.0", - "picomatch": "^4.0.4", - "retext-smartypants": "^6.2.0", - "shiki": "^4.0.2", - "smol-toml": "^1.6.0", - "unified": "^11.0.5" + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@astrojs/markdown-remark": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.2.4.tgz", - "integrity": "sha512-MvspGMynWKAjTe4/lTUdmBPHIFKNVLTCF6UlyWGogTGzNrTvjD+D4n48k7h8swxsEPKHK2TwxkZO7uoaCv1Pow==", + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.10.4", - "@astrojs/prism": "4.0.2", - "github-slugger": "^2.0.0", - "hast-util-from-html": "^2.0.3", - "hast-util-to-text": "^4.0.2", - "mdast-util-definitions": "^6.0.0", - "rehype-raw": "^7.0.0", - "rehype-stringify": "^10.0.1", - "remark-gfm": "^4.0.1", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.1.2", - "remark-smartypants": "^3.0.2", - "unified": "^11.0.5", - "unist-util-remove-position": "^5.0.0", - "unist-util-visit": "^5.1.0", - "unist-util-visit-parents": "^6.0.2", - "vfile": "^6.0.3" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@astrojs/markdown-satteri": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.3.8.tgz", - "integrity": "sha512-n8ItpFTCmlDsVR5+rwDmehSf+jFCYLWmZiisZNGuF7xILqYhsVeBfcha4qgS2Seq3fAc9Tm58ZVrvqFQ6RQgRQ==", + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.10.4", - "@astrojs/prism": "4.0.2", - "github-slugger": "^2.0.0", - "satteri": "^0.10.3" + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" } }, - "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-darwin-arm64": { + "node_modules/@bruits/satteri-darwin-arm64": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.10.5.tgz", "integrity": "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==", @@ -406,7 +340,7 @@ "darwin" ] }, - "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-darwin-x64": { + "node_modules/@bruits/satteri-darwin-x64": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.10.5.tgz", "integrity": "sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==", @@ -419,7 +353,7 @@ "darwin" ] }, - "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-linux-arm64-gnu": { + "node_modules/@bruits/satteri-linux-arm64-gnu": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.10.5.tgz", "integrity": "sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==", @@ -435,7 +369,7 @@ "linux" ] }, - "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-linux-arm64-musl": { + "node_modules/@bruits/satteri-linux-arm64-musl": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.10.5.tgz", "integrity": "sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==", @@ -451,7 +385,7 @@ "linux" ] }, - "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-linux-x64-gnu": { + "node_modules/@bruits/satteri-linux-x64-gnu": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.10.5.tgz", "integrity": "sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==", @@ -467,7 +401,7 @@ "linux" ] }, - "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-linux-x64-musl": { + "node_modules/@bruits/satteri-linux-x64-musl": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.10.5.tgz", "integrity": "sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==", @@ -483,7 +417,7 @@ "linux" ] }, - "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-wasm32-wasi": { + "node_modules/@bruits/satteri-wasm32-wasi": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.10.5.tgz", "integrity": "sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==", @@ -501,44 +435,18 @@ "node": ">=14.0.0" } }, - "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-win32-arm64-msvc": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.10.5.tgz", - "integrity": "sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==", - "cpu": [ - "arm64" - ], + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } }, - "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-win32-x64-msvc": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.10.5.tgz", - "integrity": "sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@astrojs/markdown-satteri/node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@astrojs/markdown-satteri/node_modules/@emnapi/runtime": { + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/runtime": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", @@ -548,7 +456,7 @@ "tslib": "^2.4.0" } }, - "node_modules/@astrojs/markdown-satteri/node_modules/@emnapi/wasi-threads": { + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", @@ -558,612 +466,305 @@ "tslib": "^2.4.0" } }, - "node_modules/@astrojs/markdown-satteri/node_modules/satteri": { + "node_modules/@bruits/satteri-win32-arm64-msvc": { "version": "0.10.5", - "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.10.5.tgz", - "integrity": "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.10.5.tgz", + "integrity": "sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.5", - "@types/hast": "^3.0.5", - "@types/mdast": "^4.0.4", - "@types/unist": "^3.0.3" - }, - "optionalDependencies": { - "@bruits/satteri-darwin-arm64": "0.10.5", - "@bruits/satteri-darwin-x64": "0.10.5", - "@bruits/satteri-linux-arm64-gnu": "0.10.5", - "@bruits/satteri-linux-arm64-musl": "0.10.5", - "@bruits/satteri-linux-x64-gnu": "0.10.5", - "@bruits/satteri-linux-x64-musl": "0.10.5", - "@bruits/satteri-wasm32-wasi": "0.10.5", - "@bruits/satteri-win32-arm64-msvc": "0.10.5", - "@bruits/satteri-win32-x64-msvc": "0.10.5" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@astrojs/mdx": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-7.0.8.tgz", - "integrity": "sha512-RNuwq2ccTSi7NX9YqlR0noaWoVdOrZuJvdfWXotAzdhMVB0b0zEMLnNU+xar7le0GwTMlTObD/QAu8jeHA/3nA==", + "node_modules/@bruits/satteri-win32-x64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.10.5.tgz", + "integrity": "sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.14.0.tgz", + "integrity": "sha512-C3UGsiCwSprE2NKIIFA3hCDlpXTMCAXRZuEVp88L1GY36Y41+rYL5fryE+nOFhp4p4JPQvdV8PQ4DWgHgeTE+w==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@capsizecss/unpack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.1.tgz", + "integrity": "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.10.4", - "@astrojs/markdown-remark": "7.2.4", - "@mdx-js/mdx": "^3.1.1", - "acorn": "^8.16.0", - "es-module-lexer": "^2.0.0", - "estree-util-visit": "^2.0.0", - "hast-util-to-html": "^9.0.5", - "piccolore": "^0.1.3", - "rehype-raw": "^7.0.0", - "remark-gfm": "^4.0.1", - "remark-smartypants": "^3.0.2", - "source-map": "^0.7.6", - "unist-util-visit": "^5.1.0", - "vfile": "^6.0.3" + "fontkitten": "^1.0.3" }, "engines": { - "node": ">=22.12.0" - }, - "peerDependencies": { - "@astrojs/markdown-satteri": "^0.3.1", - "astro": "^7.0.0" - }, - "peerDependenciesMeta": { - "@astrojs/markdown-satteri": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@astrojs/prism": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.2.tgz", - "integrity": "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==", + "node_modules/@clack/core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz", + "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", "license": "MIT", "dependencies": { - "prismjs": "^1.30.0" + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">=22.12.0" + "node": ">= 20.12.0" } }, - "node_modules/@astrojs/telemetry": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.3.tgz", - "integrity": "sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==", + "node_modules/@clack/prompts": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.7.0.tgz", + "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", "license": "MIT", "dependencies": { - "ci-info": "^4.4.0", - "dset": "^3.1.4", - "is-docker": "^4.0.0", - "package-manager-detector": "^1.6.0" + "@clack/core": "1.4.3", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" }, "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0" + "node": ">= 20.12.0" } }, - "node_modules/@astrojs/ts-plugin": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@astrojs/ts-plugin/-/ts-plugin-1.10.11.tgz", - "integrity": "sha512-W7Fmbaw81mcecFgJWgfY8FX7G7nCiooiakgd8ZAVprglEo81W2HzXh2I+okmAorCZLICl4PeEELkpGzrEXze4g==", + "node_modules/@cspell/cspell-bundled-dicts": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-9.8.0.tgz", + "integrity": "sha512-MpXFpVyBPfJQ1YuVotljqUaGf6lWuf+fuWBBgs0PHFYTSjRPWuIxviAaCDnup/CJLLH60xQL4IlcQe4TOjzljw==", "dev": true, "license": "MIT", "dependencies": { - "@astrojs/compiler": "^2.13.1", - "@astrojs/yaml2ts": "^0.2.4", - "@jridgewell/sourcemap-codec": "^1.5.5", - "@volar/language-core": "~2.4.28", - "@volar/typescript": "~2.4.28", - "semver": "^7.7.4", - "vscode-languageserver-textdocument": "^1.0.12" + "@cspell/dict-ada": "^4.1.1", + "@cspell/dict-al": "^1.1.1", + "@cspell/dict-aws": "^4.0.17", + "@cspell/dict-bash": "^4.2.2", + "@cspell/dict-companies": "^3.2.11", + "@cspell/dict-cpp": "^7.0.2", + "@cspell/dict-cryptocurrencies": "^5.0.5", + "@cspell/dict-csharp": "^4.0.8", + "@cspell/dict-css": "^4.1.1", + "@cspell/dict-dart": "^2.3.2", + "@cspell/dict-data-science": "^2.0.13", + "@cspell/dict-django": "^4.1.6", + "@cspell/dict-docker": "^1.1.17", + "@cspell/dict-dotnet": "^5.0.13", + "@cspell/dict-elixir": "^4.0.8", + "@cspell/dict-en_us": "^4.4.33", + "@cspell/dict-en-common-misspellings": "^2.1.12", + "@cspell/dict-en-gb-mit": "^3.1.22", + "@cspell/dict-filetypes": "^3.0.18", + "@cspell/dict-flutter": "^1.1.1", + "@cspell/dict-fonts": "^4.0.6", + "@cspell/dict-fsharp": "^1.1.1", + "@cspell/dict-fullstack": "^3.2.9", + "@cspell/dict-gaming-terms": "^1.1.2", + "@cspell/dict-git": "^3.1.0", + "@cspell/dict-golang": "^6.0.26", + "@cspell/dict-google": "^1.0.9", + "@cspell/dict-haskell": "^4.0.6", + "@cspell/dict-html": "^4.0.15", + "@cspell/dict-html-symbol-entities": "^4.0.5", + "@cspell/dict-java": "^5.0.12", + "@cspell/dict-julia": "^1.1.1", + "@cspell/dict-k8s": "^1.0.12", + "@cspell/dict-kotlin": "^1.1.1", + "@cspell/dict-latex": "^5.1.0", + "@cspell/dict-lorem-ipsum": "^4.0.5", + "@cspell/dict-lua": "^4.0.8", + "@cspell/dict-makefile": "^1.0.5", + "@cspell/dict-markdown": "^2.0.16", + "@cspell/dict-monkeyc": "^1.0.12", + "@cspell/dict-node": "^5.0.9", + "@cspell/dict-npm": "^5.2.38", + "@cspell/dict-php": "^4.1.1", + "@cspell/dict-powershell": "^5.0.15", + "@cspell/dict-public-licenses": "^2.0.16", + "@cspell/dict-python": "^4.2.26", + "@cspell/dict-r": "^2.1.1", + "@cspell/dict-ruby": "^5.1.1", + "@cspell/dict-rust": "^4.1.2", + "@cspell/dict-scala": "^5.0.9", + "@cspell/dict-shell": "^1.1.2", + "@cspell/dict-software-terms": "^5.2.2", + "@cspell/dict-sql": "^2.2.1", + "@cspell/dict-svelte": "^1.0.7", + "@cspell/dict-swift": "^2.0.6", + "@cspell/dict-terraform": "^1.1.3", + "@cspell/dict-typescript": "^3.2.3", + "@cspell/dict-vue": "^3.0.5", + "@cspell/dict-zig": "^1.0.0" + }, + "engines": { + "node": ">=20" } }, - "node_modules/@astrojs/yaml2ts": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.4.tgz", - "integrity": "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==", + "node_modules/@cspell/cspell-json-reporter": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-9.8.0.tgz", + "integrity": "sha512-nqUaSo9T7l8KrE22gc7ZIs+zvP7ak1i7JqGdRs8sGvh2Ijqj43qYQLePgb1b/vm8a1bavnc51m+vf05hpd3g3Q==", "dev": true, "license": "MIT", "dependencies": { - "yaml": "^2.8.3" + "@cspell/cspell-types": "9.8.0" + }, + "engines": { + "node": ">=20" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "node_modules/@cspell/cspell-performance-monitor": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-performance-monitor/-/cspell-performance-monitor-9.8.0.tgz", + "integrity": "sha512-IsrXYzn23yJICIQ915ACdf+2lNEcFNTu5BIQt3khHOsGVvZ9/AZYpu9Dk825vUyZG7RHg2Oi6dYNiJtULG4ouQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=20.18" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "node_modules/@cspell/cspell-pipe": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-9.8.0.tgz", + "integrity": "sha512-ISEUD8PHYkd2Ktafc6hFfIXdGKYUvthA09NbwwZsWmOqYyk4wWKHZKqyyxD+BcrFwOyMOJcD8OEvIjkRQp2SJw==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=20" } }, - "node_modules/@babel/parser": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", - "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "node_modules/@cspell/cspell-resolver": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-9.8.0.tgz", + "integrity": "sha512-PZJj56BZpKfMxOzWkyt7b+aIXObe+8Ku/zLI4xDXPSuQPENbHBFHfPIZx68CyGEkanKxZ1ewKVx/FT1FUy+wDA==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.8" - }, - "bin": { - "parser": "bin/babel-parser.js" + "global-directory": "^5.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=20" } }, - "node_modules/@babel/types": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", - "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "node_modules/@cspell/cspell-service-bus": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-9.8.0.tgz", + "integrity": "sha512-P45sd2nqwcqhulBBbQnZB/JNcobecTrP4Ky3vmEq0cprsvavc+ZoHF9U2Ql5ghMSUzjrF2n1aNzZ8cH4IlsnKg==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, "engines": { - "node": ">=6.9.0" + "node": ">=20" } }, - "node_modules/@bramus/specificity": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", - "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "node_modules/@cspell/cspell-types": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-9.8.0.tgz", + "integrity": "sha512-7Ge4UD6SCA49Tcc3+GTlz3Xn4cqVUAXtDO0u9IeHvJgkN3Me2Rw2GB/CtGmhKST3YeEeZMX7ww09TdHMUJlehw==", + "dev": true, "license": "MIT", - "dependencies": { - "css-tree": "^3.0.0" - }, - "bin": { - "specificity": "bin/cli.js" + "engines": { + "node": ">=20" } }, - "node_modules/@bruits/satteri-darwin-arm64": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.9.5.tgz", - "integrity": "sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@bruits/satteri-darwin-x64": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.9.5.tgz", - "integrity": "sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@bruits/satteri-linux-arm64-gnu": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.9.5.tgz", - "integrity": "sha512-u51id17uJwNEMK9nBlICsq6U31c+XVqQueVBkwRIzZG+gMpS8TOJctt5h5Wz33Z8xnMdTd+adtACVz0yHgGuOA==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@bruits/satteri-linux-arm64-musl": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.9.5.tgz", - "integrity": "sha512-v39HxiwGC5Rqm01HksP6+5Y+xKLPlsuVFgIgpEAo+SiQ22c+mJVhS3u7Z6ePAKdhL5NJoK1xq70kLz3L13AhpQ==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@bruits/satteri-linux-x64-gnu": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.9.5.tgz", - "integrity": "sha512-F3uO8uFp3pAP5ZGXttwvh57GS7s0lL953tnNdyI2gRyP4kOOkp6pyGojNJzCjkDvWI2Cvb9iNrKok3aqQPauAw==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@bruits/satteri-linux-x64-musl": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.9.5.tgz", - "integrity": "sha512-bicEqglLlz++mWyADaZoP0JY20s4vDfLjaPYgQqC+NI4zZLTOOg1T4GB8aqtc822Pqji8SQBmSrTb7CrP8i08Q==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@bruits/satteri-wasm32-wasi": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.9.5.tgz", - "integrity": "sha512-zauAuMwfPnKPUkd4AFixRFpXdgKwP2mKgxrIIo2gJzW0/ZneF9dbHnLkojSpaBnCCp7VUL1hIi5WWZvB1CqmAQ==", - "cpu": [ - "wasm32" - ], + "node_modules/@cspell/cspell-worker": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-worker/-/cspell-worker-9.8.0.tgz", + "integrity": "sha512-W8FLdE3MXPLbWtAXciILQhk9CHd6Mt+HRjZHM8m+dwE1Bc2TAjUai8kIxsdhHUq58p7gYY2ekr5sg1uYOUgTAA==", + "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/core": "1.11.1", - "@emnapi/runtime": "1.11.1", - "@napi-rs/wasm-runtime": "^1.1.6" + "cspell-lib": "9.8.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.18" } }, - "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } + "node_modules/@cspell/dict-ada": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.1.tgz", + "integrity": "sha512-E+0YW9RhZod/9Qy2gxfNZiHJjCYFlCdI69br1eviQQWB8yOTJX0JHXLs79kOYhSW0kINPVUdvddEBe6Lu6CjGQ==", + "dev": true, + "license": "MIT" }, - "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } + "node_modules/@cspell/dict-al": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.1.tgz", + "integrity": "sha512-sD8GCaZetgQL4+MaJLXqbzWcRjfKVp8x+px3HuCaaiATAAtvjwUQ5/Iubiqwfd1boIh2Y1/3EgM3TLQ7Q8e0wQ==", + "dev": true, + "license": "MIT" }, - "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "node_modules/@cspell/dict-aws": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.17.tgz", + "integrity": "sha512-ORcblTWcdlGjIbWrgKF+8CNEBQiLVKdUOFoTn0KPNkAYnFcdPP0muT4892h7H4Xafh3j72wqB4/loQ6Nti9E/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-bash": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.3.tgz", + "integrity": "sha512-ljUZoKHbDqw5Sx0qpL2qTUlmkmr+vhZH/sCNrNaBZKTbdgiswErSnIF1jRbGmEitJNxHRHWsuZyVgnTGfVO1Yw==", + "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@cspell/dict-shell": "1.2.0" } }, - "node_modules/@bruits/satteri-win32-arm64-msvc": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.9.5.tgz", - "integrity": "sha512-SrfE7NEsgZjBvU3c+RR6oQRu0ToXY5uVJEbieXEF0YTctIV2zAVlbaMjWLts074QCgh3a+XHWkR/lWh2VH2LUg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "node_modules/@cspell/dict-companies": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.2.12.tgz", + "integrity": "sha512-mjiz/N3zWOCsz5VfwMUydSl7uW0OU9H2PnbCNc3RV44Vj6Q59CSp6EYGSGZQxrXU1gpsuZUrwr6QCjNjFOOg5A==", + "dev": true, + "license": "MIT" }, - "node_modules/@bruits/satteri-win32-x64-msvc": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.9.5.tgz", - "integrity": "sha512-5Kw9ZAtTGS8WHizyn+CJhjjfIQrw+7jcZodpmpXJjefnO15M8UexIi6JR2E5thyvsmHyhL6ZDDMUNR4bKJPd4g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "node_modules/@cspell/dict-cpp": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-7.1.0.tgz", + "integrity": "sha512-rcjycobioQUd9Jm/Y1n8U+sq6ytpZ0iV8AYIo+vyEFfutC5x7g6hL6Fh3bCdh6IporGHRqfEutGK/4sfopD2ZA==", + "dev": true, + "license": "MIT" }, - "node_modules/@bufbuild/protobuf": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.14.0.tgz", - "integrity": "sha512-C3UGsiCwSprE2NKIIFA3hCDlpXTMCAXRZuEVp88L1GY36Y41+rYL5fryE+nOFhp4p4JPQvdV8PQ4DWgHgeTE+w==", - "license": "(Apache-2.0 AND BSD-3-Clause)" + "node_modules/@cspell/dict-cryptocurrencies": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.5.tgz", + "integrity": "sha512-R68hYYF/rtlE6T/dsObStzN5QZw+0aQBinAXuWCVqwdS7YZo0X33vGMfChkHaiCo3Z2+bkegqHlqxZF4TD3rUA==", + "dev": true, + "license": "MIT" }, - "node_modules/@capsizecss/unpack": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.1.tgz", - "integrity": "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==", - "license": "MIT", - "dependencies": { - "fontkitten": "^1.0.3" - }, - "engines": { - "node": ">=18" - } + "node_modules/@cspell/dict-csharp": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.8.tgz", + "integrity": "sha512-qmk45pKFHSxckl5mSlbHxmDitSsGMlk/XzFgt7emeTJWLNSTUK//MbYAkBNRtfzB4uD7pAFiKgpKgtJrTMRnrQ==", + "dev": true, + "license": "MIT" }, - "node_modules/@clack/core": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz", - "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", - "license": "MIT", - "dependencies": { - "fast-wrap-ansi": "^0.2.0", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 20.12.0" - } + "node_modules/@cspell/dict-css": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.1.2.tgz", + "integrity": "sha512-+ylGoKdwZ2sVOCOnU2Eq5wDZx+RaVX3HoKyNHGGsFvhSw6IidQ6tH/mAPKBDofViHJoWCPNlklE0lTr6MDG3QA==", + "dev": true, + "license": "MIT" }, - "node_modules/@clack/prompts": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.7.0.tgz", - "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", - "license": "MIT", - "dependencies": { - "@clack/core": "1.4.3", - "fast-string-width": "^3.0.2", - "fast-wrap-ansi": "^0.2.0", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 20.12.0" - } + "node_modules/@cspell/dict-dart": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.2.tgz", + "integrity": "sha512-sUiLW56t9gfZcu8iR/5EUg+KYyRD83Cjl3yjDEA2ApVuJvK1HhX+vn4e4k4YfjpUQMag8XO2AaRhARE09+/rqw==", + "dev": true, + "license": "MIT" }, - "node_modules/@cspell/cspell-bundled-dicts": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-9.8.0.tgz", - "integrity": "sha512-MpXFpVyBPfJQ1YuVotljqUaGf6lWuf+fuWBBgs0PHFYTSjRPWuIxviAaCDnup/CJLLH60xQL4IlcQe4TOjzljw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-ada": "^4.1.1", - "@cspell/dict-al": "^1.1.1", - "@cspell/dict-aws": "^4.0.17", - "@cspell/dict-bash": "^4.2.2", - "@cspell/dict-companies": "^3.2.11", - "@cspell/dict-cpp": "^7.0.2", - "@cspell/dict-cryptocurrencies": "^5.0.5", - "@cspell/dict-csharp": "^4.0.8", - "@cspell/dict-css": "^4.1.1", - "@cspell/dict-dart": "^2.3.2", - "@cspell/dict-data-science": "^2.0.13", - "@cspell/dict-django": "^4.1.6", - "@cspell/dict-docker": "^1.1.17", - "@cspell/dict-dotnet": "^5.0.13", - "@cspell/dict-elixir": "^4.0.8", - "@cspell/dict-en_us": "^4.4.33", - "@cspell/dict-en-common-misspellings": "^2.1.12", - "@cspell/dict-en-gb-mit": "^3.1.22", - "@cspell/dict-filetypes": "^3.0.18", - "@cspell/dict-flutter": "^1.1.1", - "@cspell/dict-fonts": "^4.0.6", - "@cspell/dict-fsharp": "^1.1.1", - "@cspell/dict-fullstack": "^3.2.9", - "@cspell/dict-gaming-terms": "^1.1.2", - "@cspell/dict-git": "^3.1.0", - "@cspell/dict-golang": "^6.0.26", - "@cspell/dict-google": "^1.0.9", - "@cspell/dict-haskell": "^4.0.6", - "@cspell/dict-html": "^4.0.15", - "@cspell/dict-html-symbol-entities": "^4.0.5", - "@cspell/dict-java": "^5.0.12", - "@cspell/dict-julia": "^1.1.1", - "@cspell/dict-k8s": "^1.0.12", - "@cspell/dict-kotlin": "^1.1.1", - "@cspell/dict-latex": "^5.1.0", - "@cspell/dict-lorem-ipsum": "^4.0.5", - "@cspell/dict-lua": "^4.0.8", - "@cspell/dict-makefile": "^1.0.5", - "@cspell/dict-markdown": "^2.0.16", - "@cspell/dict-monkeyc": "^1.0.12", - "@cspell/dict-node": "^5.0.9", - "@cspell/dict-npm": "^5.2.38", - "@cspell/dict-php": "^4.1.1", - "@cspell/dict-powershell": "^5.0.15", - "@cspell/dict-public-licenses": "^2.0.16", - "@cspell/dict-python": "^4.2.26", - "@cspell/dict-r": "^2.1.1", - "@cspell/dict-ruby": "^5.1.1", - "@cspell/dict-rust": "^4.1.2", - "@cspell/dict-scala": "^5.0.9", - "@cspell/dict-shell": "^1.1.2", - "@cspell/dict-software-terms": "^5.2.2", - "@cspell/dict-sql": "^2.2.1", - "@cspell/dict-svelte": "^1.0.7", - "@cspell/dict-swift": "^2.0.6", - "@cspell/dict-terraform": "^1.1.3", - "@cspell/dict-typescript": "^3.2.3", - "@cspell/dict-vue": "^3.0.5", - "@cspell/dict-zig": "^1.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@cspell/cspell-json-reporter": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-9.8.0.tgz", - "integrity": "sha512-nqUaSo9T7l8KrE22gc7ZIs+zvP7ak1i7JqGdRs8sGvh2Ijqj43qYQLePgb1b/vm8a1bavnc51m+vf05hpd3g3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-types": "9.8.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@cspell/cspell-performance-monitor": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-performance-monitor/-/cspell-performance-monitor-9.8.0.tgz", - "integrity": "sha512-IsrXYzn23yJICIQ915ACdf+2lNEcFNTu5BIQt3khHOsGVvZ9/AZYpu9Dk825vUyZG7RHg2Oi6dYNiJtULG4ouQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18" - } - }, - "node_modules/@cspell/cspell-pipe": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-9.8.0.tgz", - "integrity": "sha512-ISEUD8PHYkd2Ktafc6hFfIXdGKYUvthA09NbwwZsWmOqYyk4wWKHZKqyyxD+BcrFwOyMOJcD8OEvIjkRQp2SJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/@cspell/cspell-resolver": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-9.8.0.tgz", - "integrity": "sha512-PZJj56BZpKfMxOzWkyt7b+aIXObe+8Ku/zLI4xDXPSuQPENbHBFHfPIZx68CyGEkanKxZ1ewKVx/FT1FUy+wDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "global-directory": "^5.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@cspell/cspell-service-bus": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-9.8.0.tgz", - "integrity": "sha512-P45sd2nqwcqhulBBbQnZB/JNcobecTrP4Ky3vmEq0cprsvavc+ZoHF9U2Ql5ghMSUzjrF2n1aNzZ8cH4IlsnKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/@cspell/cspell-types": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-9.8.0.tgz", - "integrity": "sha512-7Ge4UD6SCA49Tcc3+GTlz3Xn4cqVUAXtDO0u9IeHvJgkN3Me2Rw2GB/CtGmhKST3YeEeZMX7ww09TdHMUJlehw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/@cspell/cspell-worker": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-worker/-/cspell-worker-9.8.0.tgz", - "integrity": "sha512-W8FLdE3MXPLbWtAXciILQhk9CHd6Mt+HRjZHM8m+dwE1Bc2TAjUai8kIxsdhHUq58p7gYY2ekr5sg1uYOUgTAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cspell-lib": "9.8.0" - }, - "engines": { - "node": ">=20.18" - } - }, - "node_modules/@cspell/dict-ada": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.1.tgz", - "integrity": "sha512-E+0YW9RhZod/9Qy2gxfNZiHJjCYFlCdI69br1eviQQWB8yOTJX0JHXLs79kOYhSW0kINPVUdvddEBe6Lu6CjGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-al": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.1.tgz", - "integrity": "sha512-sD8GCaZetgQL4+MaJLXqbzWcRjfKVp8x+px3HuCaaiATAAtvjwUQ5/Iubiqwfd1boIh2Y1/3EgM3TLQ7Q8e0wQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-aws": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.17.tgz", - "integrity": "sha512-ORcblTWcdlGjIbWrgKF+8CNEBQiLVKdUOFoTn0KPNkAYnFcdPP0muT4892h7H4Xafh3j72wqB4/loQ6Nti9E/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-bash": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.3.tgz", - "integrity": "sha512-ljUZoKHbDqw5Sx0qpL2qTUlmkmr+vhZH/sCNrNaBZKTbdgiswErSnIF1jRbGmEitJNxHRHWsuZyVgnTGfVO1Yw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-shell": "1.2.0" - } - }, - "node_modules/@cspell/dict-companies": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.2.12.tgz", - "integrity": "sha512-mjiz/N3zWOCsz5VfwMUydSl7uW0OU9H2PnbCNc3RV44Vj6Q59CSp6EYGSGZQxrXU1gpsuZUrwr6QCjNjFOOg5A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-cpp": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-7.1.0.tgz", - "integrity": "sha512-rcjycobioQUd9Jm/Y1n8U+sq6ytpZ0iV8AYIo+vyEFfutC5x7g6hL6Fh3bCdh6IporGHRqfEutGK/4sfopD2ZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-cryptocurrencies": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.5.tgz", - "integrity": "sha512-R68hYYF/rtlE6T/dsObStzN5QZw+0aQBinAXuWCVqwdS7YZo0X33vGMfChkHaiCo3Z2+bkegqHlqxZF4TD3rUA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-csharp": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.8.tgz", - "integrity": "sha512-qmk45pKFHSxckl5mSlbHxmDitSsGMlk/XzFgt7emeTJWLNSTUK//MbYAkBNRtfzB4uD7pAFiKgpKgtJrTMRnrQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-css": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.1.2.tgz", - "integrity": "sha512-+ylGoKdwZ2sVOCOnU2Eq5wDZx+RaVX3HoKyNHGGsFvhSw6IidQ6tH/mAPKBDofViHJoWCPNlklE0lTr6MDG3QA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-dart": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.2.tgz", - "integrity": "sha512-sUiLW56t9gfZcu8iR/5EUg+KYyRD83Cjl3yjDEA2ApVuJvK1HhX+vn4e4k4YfjpUQMag8XO2AaRhARE09+/rqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-data-science": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.16.tgz", - "integrity": "sha512-M72mxv5asuAnORurz4iXRJ+Tw9XBq6eu7D2Ne7biP0Z1RciKGNxXWu9JycA/KlVvK1hAlKj/fANlXhuEWpXKFg==", + "node_modules/@cspell/dict-data-science": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.16.tgz", + "integrity": "sha512-M72mxv5asuAnORurz4iXRJ+Tw9XBq6eu7D2Ne7biP0Z1RciKGNxXWu9JycA/KlVvK1hAlKj/fANlXhuEWpXKFg==", "dev": true, "license": "MIT" }, @@ -2242,56 +1843,66 @@ "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", "license": "MIT", + "optional": true, "engines": { "node": ">=18" } }, - "node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", - "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.4.tgz", + "integrity": "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==", + "cpu": [ + "arm64" + ], "license": "Apache-2.0", "optional": true, "os": [ - "freebsd" + "darwin" ], - "dependencies": { - "@img/sharp-wasm32": "0.35.3" - }, "engines": { "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.3" } }, - "node_modules/@img/sharp-freebsd-wasm32/node_modules/@img/sharp-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", - "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.4.tgz", + "integrity": "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.11.1" - }, + "os": [ + "darwin" + ], "engines": { "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.3" } }, - "node_modules/@img/sharp-webcontainers-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", - "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", - "cpu": [ - "wasm32" - ], + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.4.tgz", + "integrity": "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==", "license": "Apache-2.0", "optional": true, + "os": [ + "freebsd" + ], "dependencies": { - "@img/sharp-wasm32": "0.35.3" + "@img/sharp-wasm32": "0.35.4" }, "engines": { "node": ">=20.9.0" @@ -2300,591 +1911,598 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-webcontainers-wasm32/node_modules/@img/sharp-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", - "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.11.1" - }, - "engines": { - "node": ">=20.9.0" - }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.3.tgz", + "integrity": "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], "funding": { "url": "https://opencollective.com/libvips" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@lit-labs/ssr-dom-shim": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.6.0.tgz", - "integrity": "sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@lit/context": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.6.tgz", - "integrity": "sha512-M26qDE6UkQbZA2mQ3RjJ3Gzd8TxP+/0obMgE5HfkfLhEEyYE3Bui4A5XHiGPjy0MUGAyxB3QgVuw2ciS0kHn6A==", - "license": "BSD-3-Clause", - "dependencies": { - "@lit/reactive-element": "^1.6.2 || ^2.1.0" - } - }, - "node_modules/@lit/reactive-element": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.2.tgz", - "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", - "license": "BSD-3-Clause", - "dependencies": { - "@lit-labs/ssr-dom-shim": "^1.5.0" - } - }, - "node_modules/@mdx-js/mdx": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", - "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdx": "^2.0.0", - "acorn": "^8.0.0", - "collapse-white-space": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "estree-util-scope": "^1.0.0", - "estree-walker": "^3.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "markdown-extensions": "^2.0.0", - "recma-build-jsx": "^1.0.0", - "recma-jsx": "^1.0.0", - "recma-stringify": "^1.0.0", - "rehype-recma": "^1.0.0", - "remark-mdx": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "source-map": "^0.7.0", - "unified": "^11.0.0", - "unist-util-position-from-estree": "^2.0.0", - "unist-util-stringify-position": "^4.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mixmark-io/domino": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", - "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", - "license": "BSD-2-Clause" - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", - "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9 || ^2.0.5", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.3.tgz", - "integrity": "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==", - "license": "MIT", + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.3.tgz", + "integrity": "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=23.5.0" - }, + "os": [ + "darwin" + ], "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", - "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oslojs/encoding": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", - "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", - "license": "MIT" - }, - "node_modules/@oxc-project/types": { - "version": "0.146.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.146.0.tgz", - "integrity": "sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==", - "license": "MIT", + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.3.tgz", + "integrity": "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@pagefind/darwin-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz", - "integrity": "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==", + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.3.tgz", + "integrity": "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==", "cpu": [ "arm64" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "darwin" - ] + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } }, - "node_modules/@pagefind/darwin-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.5.2.tgz", - "integrity": "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==", + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.3.tgz", + "integrity": "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==", "cpu": [ - "x64" + "ppc64" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "darwin" - ] + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } }, - "node_modules/@pagefind/freebsd-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.5.2.tgz", - "integrity": "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==", + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.3.tgz", + "integrity": "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==", "cpu": [ - "x64" + "riscv64" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "freebsd" - ] + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } }, - "node_modules/@pagefind/linux-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.5.2.tgz", - "integrity": "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==", + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.3.tgz", + "integrity": "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==", "cpu": [ - "arm64" + "s390x" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" - ] + ], + "funding": { + "url": "https://opencollective.com/libvips" + } }, - "node_modules/@pagefind/linux-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.5.2.tgz", - "integrity": "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==", + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.3.tgz", + "integrity": "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==", "cpu": [ "x64" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" - ] + ], + "funding": { + "url": "https://opencollective.com/libvips" + } }, - "node_modules/@pagefind/windows-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/windows-arm64/-/windows-arm64-1.5.2.tgz", - "integrity": "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==", + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.3.tgz", + "integrity": "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==", "cpu": [ "arm64" ], - "license": "MIT", + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "win32" - ] + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } }, - "node_modules/@pagefind/windows-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.5.2.tgz", - "integrity": "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==", + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.3.tgz", + "integrity": "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==", "cpu": [ "x64" ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@parcel/watcher": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", - "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.3", - "is-glob": "^4.0.3", - "node-addon-api": "^7.0.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.6.0", - "@parcel/watcher-darwin-arm64": "2.6.0", - "@parcel/watcher-darwin-x64": "2.6.0", - "@parcel/watcher-freebsd-x64": "2.6.0", - "@parcel/watcher-linux-arm-glibc": "2.6.0", - "@parcel/watcher-linux-arm-musl": "2.6.0", - "@parcel/watcher-linux-arm64-glibc": "2.6.0", - "@parcel/watcher-linux-arm64-musl": "2.6.0", - "@parcel/watcher-linux-x64-glibc": "2.6.0", - "@parcel/watcher-linux-x64-musl": "2.6.0", - "@parcel/watcher-win32-arm64": "2.6.0", - "@parcel/watcher-win32-x64": "2.6.0" - } - }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", - "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", - "cpu": [ - "arm64" + "libc": [ + "musl" ], - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "android" + "linux" ], - "engines": { - "node": ">= 10.0.0" - }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", - "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.4.tgz", + "integrity": "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==", "cpu": [ - "arm64" + "arm" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "Apache-2.0", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.3" } }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", - "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.4.tgz", + "integrity": "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==", "cpu": [ - "x64" + "arm64" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "Apache-2.0", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.3" } }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", - "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.4.tgz", + "integrity": "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==", "cpu": [ - "x64" + "ppc64" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "Apache-2.0", "optional": true, "os": [ - "freebsd" + "linux" ], "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.3" } }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", - "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.4.tgz", + "integrity": "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==", "cpu": [ - "arm" + "riscv64" ], "libc": [ "glibc" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.3" } }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", - "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.4.tgz", + "integrity": "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==", "cpu": [ - "arm" + "s390x" ], "libc": [ - "musl" + "glibc" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.3" } }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", - "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.4.tgz", + "integrity": "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==", "cpu": [ - "arm64" + "x64" ], "libc": [ "glibc" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.3" } }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", - "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.4.tgz", + "integrity": "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==", "cpu": [ "arm64" ], "libc": [ "musl" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3" } }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", - "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.4.tgz", + "integrity": "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==", "cpu": [ "x64" ], "libc": [ - "glibc" + "musl" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.3" } }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", - "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "node_modules/@img/sharp-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz", + "integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.4.tgz", + "integrity": "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==", "cpu": [ - "x64" - ], - "libc": [ - "musl" + "wasm32" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@img/sharp-wasm32": "0.35.4" + }, "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", - "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.4.tgz", + "integrity": "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==", "cpu": [ "arm64" ], - "license": "MIT", + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" ], "engines": { - "node": ">= 10.0.0" + "node": ">=20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", - "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.4.tgz", + "integrity": "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==", "cpu": [ - "x64" + "ia32" ], - "license": "MIT", + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" ], "engines": { - "node": ">= 10.0.0" + "node": "^20.9.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@rolldown/binding-android-arm-eabi": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.5.tgz", - "integrity": "sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==", + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.4.tgz", + "integrity": "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==", "cpu": [ - "arm" + "x64" ], - "license": "MIT", + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ - "android" + "win32" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.5.tgz", - "integrity": "sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==", - "cpu": [ - "arm64" - ], + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.6.0.tgz", + "integrity": "sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/context": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.6.tgz", + "integrity": "sha512-M26qDE6UkQbZA2mQ3RjJ3Gzd8TxP+/0obMgE5HfkfLhEEyYE3Bui4A5XHiGPjy0MUGAyxB3QgVuw2ciS0kHn6A==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^1.6.2 || ^2.1.0" + } + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.2.tgz", + "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0" + } + }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", + "license": "BSD-2-Clause" + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", + "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9 || ^2.0.5", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.4.tgz", + "integrity": "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==", "license": "MIT", "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.5.tgz", - "integrity": "sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==", + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT" + }, + "node_modules/@oxc-project/types": { + "version": "0.146.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.146.0.tgz", + "integrity": "sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@pagefind/darwin-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz", + "integrity": "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==", "cpu": [ "arm64" ], @@ -2892,15 +2510,12 @@ "optional": true, "os": [ "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.5.tgz", - "integrity": "sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==", + "node_modules/@pagefind/darwin-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.5.2.tgz", + "integrity": "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==", "cpu": [ "x64" ], @@ -2908,15 +2523,12 @@ "optional": true, "os": [ "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.5.tgz", - "integrity": "sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==", + "node_modules/@pagefind/freebsd-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.5.2.tgz", + "integrity": "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==", "cpu": [ "x64" ], @@ -2924,110 +2536,182 @@ "optional": true, "os": [ "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.5.tgz", - "integrity": "sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==", + "node_modules/@pagefind/linux-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.5.2.tgz", + "integrity": "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==", "cpu": [ - "arm" + "arm64" ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.5.tgz", - "integrity": "sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==", + "node_modules/@pagefind/linux-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.5.2.tgz", + "integrity": "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==", "cpu": [ - "arm64" - ], - "libc": [ - "glibc" + "x64" ], "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.5.tgz", - "integrity": "sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==", + "node_modules/@pagefind/windows-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-arm64/-/windows-arm64-1.5.2.tgz", + "integrity": "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==", "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + "win32" + ] }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.5.tgz", - "integrity": "sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==", + "node_modules/@pagefind/windows-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.5.2.tgz", + "integrity": "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==", "cpu": [ - "ppc64" - ], - "libc": [ - "glibc" + "x64" ], "license": "MIT", "optional": true, "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + "win32" + ] }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.5.tgz", - "integrity": "sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==", - "cpu": [ - "s390x" - ], - "libc": [ - "glibc" - ], + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "hasInstallScript": true, "license": "MIT", "optional": true, - "os": [ - "linux" + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.5.tgz", - "integrity": "sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==", + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", "cpu": [ "x64" ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "cpu": [ + "arm" + ], "libc": [ "glibc" ], @@ -3037,15 +2721,19 @@ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.5.tgz", - "integrity": "sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==", + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", "cpu": [ - "x64" + "arm" ], "libc": [ "musl" @@ -3056,436 +2744,742 @@ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.5.tgz", - "integrity": "sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==", + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ - "openharmony" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.5.tgz", - "integrity": "sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==", + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.5.tgz", - "integrity": "sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==", + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "license": "MIT" - }, - "node_modules/@shikijs/core": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.4.3.tgz", - "integrity": "sha512-QCR4q2ZO/ILJEuwiBMel4wdcTDb1JGwfjKTxPDF6x8ixOaluPrVqIn06C99AcRPhmYlBR56d/Fb+GN58GzExpg==", + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@shikijs/primitive": "4.4.3", - "@shikijs/types": "4.4.3", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.5", - "hast-util-to-html": "^9.0.5" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@shikijs/engine-javascript": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.4.3.tgz", - "integrity": "sha512-FbOjFJp9VLdo1Wevs10BBtVxiTWwNLqZh5Gkhjgda/ioL15YOgeSl9n+6XMa3qRlPQzfhFNe641SrynFHYG0nQ==", + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.3", - "@shikijs/vscode-textmate": "^10.0.2", - "oniguruma-to-es": "^4.3.6" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=20" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@shikijs/engine-oniguruma": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.4.3.tgz", - "integrity": "sha512-EcOQkxdxGQrc1Row/cC2c96/v1dbZqGnEVu1qTuT/MJmp6+cXCvQussowVmCv5Tqr3KuY3c7IbM6HTW3LJ1k9w==", + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.3", - "@shikijs/vscode-textmate": "^10.0.2" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=20" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@shikijs/langs": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.4.3.tgz", - "integrity": "sha512-ePic0yfAJGOF83D5wBHK/00EjK65oahBYxFk5epgq33WRv7X9UuxLEV8PtR0szC0z8dl7INIpIodB99JRFlR+A==", + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.5.tgz", + "integrity": "sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.3" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=20" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@shikijs/primitive": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.4.3.tgz", - "integrity": "sha512-m0wBeLDQDeIxRdUmrCPdQqfuUamDwRL5isCfYbguKD6NiaKpVbsv+3J81DyIKgNW5h4WAIIr8T4EkgQrBBxvaQ==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.5.tgz", + "integrity": "sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.3", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.5" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=20" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@shikijs/themes": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.4.3.tgz", - "integrity": "sha512-w8UHjeUnIR965KMWJHUPXOc2mNJUnK3vpVLYLvw5IYU2mnTTJ89E24OrJDBNiJDQ0qzb0tc4l7mrIXx5cFeIyw==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.5.tgz", + "integrity": "sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@shikijs/types": "4.4.3" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=20" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@shikijs/types": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.4.3.tgz", - "integrity": "sha512-UEJxmRR++MAGR6hugn0vgVS2W/6lWAts84FFSrnlH9sP0LNol7E5+NQ792pH8liWUhyMyjhTgSUH3k7iD7tc5g==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.5.tgz", + "integrity": "sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.5" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=20" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", - "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", - "license": "MIT" - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.5.tgz", + "integrity": "sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==", + "cpu": [ + "x64" + ], "license": "MIT", "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/debug": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.5.tgz", + "integrity": "sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@types/ms": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "license": "MIT" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.5.tgz", + "integrity": "sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@types/estree": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/hast": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", - "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.5.tgz", + "integrity": "sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@types/unist": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/jsdom": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-28.0.3.tgz", - "integrity": "sha512-/HQ2uFoetFTXuye8vzIcHw2z6Fwi7Hi/qcgC+RoS9NCyewiqxhVGqlG+ViGB6lkax481R6dmhf1I7lIGlzJStQ==", - "dev": true, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.5.tgz", + "integrity": "sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^8.0.0", - "undici-types": "^7.21.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/katex": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", - "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.5.tgz", + "integrity": "sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@types/unist": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/mdx": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.14.tgz", - "integrity": "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==", - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/nlcst": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", - "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.5.tgz", + "integrity": "sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@types/unist": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/node": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.3.0.tgz", - "integrity": "sha512-L3fgrnchriRC2ExBflb8j4uZZURHZfQsmQeyVzhjcHW4kkwVyo8/0h1B2MVzMTrYUJYu6G7EWs14hW/L9putqw==", - "devOptional": true, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.5.tgz", + "integrity": "sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "undici-types": "~8.3.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/node/node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "license": "MIT" - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.5.tgz", + "integrity": "sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", - "license": "ISC" + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.5.tgz", + "integrity": "sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@volar/language-core": { - "version": "2.4.28", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", - "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", - "dev": true, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.5.tgz", + "integrity": "sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@volar/source-map": "2.4.28" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@volar/source-map": { - "version": "2.4.28", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", - "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", - "dev": true, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "license": "MIT" }, - "node_modules/@volar/typescript": { - "version": "2.4.28", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", - "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", - "dev": true, + "node_modules/@shikijs/core": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.4.3.tgz", + "integrity": "sha512-QCR4q2ZO/ILJEuwiBMel4wdcTDb1JGwfjKTxPDF6x8ixOaluPrVqIn06C99AcRPhmYlBR56d/Fb+GN58GzExpg==", "license": "MIT", "dependencies": { - "@volar/language-core": "2.4.28", - "path-browserify": "^1.0.1", - "vscode-uri": "^3.0.8" + "@shikijs/primitive": "4.4.3", + "@shikijs/types": "4.4.3", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" } }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "node_modules/@shikijs/engine-javascript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.4.3.tgz", + "integrity": "sha512-FbOjFJp9VLdo1Wevs10BBtVxiTWwNLqZh5Gkhjgda/ioL15YOgeSl9n+6XMa3qRlPQzfhFNe641SrynFHYG0nQ==", "license": "MIT", "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" + "@shikijs/types": "4.4.3", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.6" }, "engines": { - "node": ">= 0.6" + "node": ">=20" } }, - "node_modules/acorn": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", - "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "node_modules/@shikijs/engine-oniguruma": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.4.3.tgz", + "integrity": "sha512-EcOQkxdxGQrc1Row/cC2c96/v1dbZqGnEVu1qTuT/MJmp6+cXCvQussowVmCv5Tqr3KuY3c7IbM6HTW3LJ1k9w==", "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "@shikijs/types": "4.4.3", + "@shikijs/vscode-textmate": "^10.0.2" }, "engines": { - "node": ">=0.4.0" + "node": ">=20" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/@shikijs/langs": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.4.3.tgz", + "integrity": "sha512-ePic0yfAJGOF83D5wBHK/00EjK65oahBYxFk5epgq33WRv7X9UuxLEV8PtR0szC0z8dl7INIpIodB99JRFlR+A==", "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "dependencies": { + "@shikijs/types": "4.4.3" + }, + "engines": { + "node": ">=20" } }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "node_modules/@shikijs/primitive": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.4.3.tgz", + "integrity": "sha512-m0wBeLDQDeIxRdUmrCPdQqfuUamDwRL5isCfYbguKD6NiaKpVbsv+3J81DyIKgNW5h4WAIIr8T4EkgQrBBxvaQ==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "@shikijs/types": "4.4.3", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=20" } }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "node_modules/@shikijs/themes": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.4.3.tgz", + "integrity": "sha512-w8UHjeUnIR965KMWJHUPXOc2mNJUnK3vpVLYLvw5IYU2mnTTJ89E24OrJDBNiJDQ0qzb0tc4l7mrIXx5cFeIyw==", "license": "MIT", "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" + "@shikijs/types": "4.4.3" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "engines": { + "node": ">=20" } }, - "node_modules/am-i-vibing": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.4.0.tgz", - "integrity": "sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==", + "node_modules/@shikijs/types": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.4.3.tgz", + "integrity": "sha512-UEJxmRR++MAGR6hugn0vgVS2W/6lWAts84FFSrnlH9sP0LNol7E5+NQ792pH8liWUhyMyjhTgSUH3k7iD7tc5g==", "license": "MIT", "dependencies": { - "process-ancestry": "^0.1.0" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" }, - "bin": { - "am-i-vibing": "dist/cli.mjs" + "engines": { + "node": ">=20" } }, - "node_modules/angular-docs": { - "resolved": "docs/angular", - "link": true - }, - "node_modules/ansi-regex": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", - "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/jsdom": { + "version": "28.0.3", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-28.0.3.tgz", + "integrity": "sha512-/HQ2uFoetFTXuye8vzIcHw2z6Fwi7Hi/qcgC+RoS9NCyewiqxhVGqlG+ViGB6lkax481R6dmhf1I7lIGlzJStQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^8.0.0", + "undici-types": "^7.21.0" + } + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/node": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.3.0.tgz", + "integrity": "sha512-L3fgrnchriRC2ExBflb8j4uZZURHZfQsmQeyVzhjcHW4kkwVyo8/0h1B2MVzMTrYUJYu6G7EWs14hW/L9putqw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/node/node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "license": "ISC" + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", "dev": true, "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, "engines": { - "node": ">=12" + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/am-i-vibing": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.4.0.tgz", + "integrity": "sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "process-ancestry": "^0.1.0" }, + "bin": { + "am-i-vibing": "dist/cli.mjs" + } + }, + "node_modules/angular-docs": { + "resolved": "docs/angular", + "link": true + }, + "node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/anymatch": { @@ -3528,16 +3522,6 @@ "node": ">= 0.4" } }, - "node_modules/array-iterate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", - "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/array-timsort": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", @@ -3545,24 +3529,15 @@ "dev": true, "license": "MIT" }, - "node_modules/astring": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", - "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", - "license": "MIT", - "bin": { - "astring": "bin/astring" - } - }, "node_modules/astro": { - "version": "7.2.6", - "resolved": "https://registry.npmjs.org/astro/-/astro-7.2.6.tgz", - "integrity": "sha512-qzT4tAhgHYX/6/MUGslAkF0PVkM4WNsMw2A1GrbfA9cXp68hmdqF3f7MuF5rRFvwQbjowqjOf90ao9whfgV5mw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/astro/-/astro-7.3.4.tgz", + "integrity": "sha512-9iZqfREj15mh5xYnKhjP8arO4F3Vcddri1rbfT3FseNElWHU+pl9vJY5ypKT1FhB/zyuGM/B9naSjeVQl9b5vw==", "license": "MIT", "dependencies": { "@astrojs/compiler-rs": "^0.4.0", - "@astrojs/internal-helpers": "0.10.4", - "@astrojs/markdown-satteri": "0.3.8", + "@astrojs/internal-helpers": "0.11.0", + "@astrojs/markdown-satteri": "0.4.2", "@astrojs/telemetry": "3.3.3", "@capsizecss/unpack": "^4.0.0", "@clack/prompts": "^1.1.0", @@ -3579,40 +3554,40 @@ "dset": "^3.1.4", "es-module-lexer": "^2.0.0", "esbuild": "^0.28.0", - "find-process": "^2.1.1", + "find-proc": "0.2.0", "flattie": "^1.1.1", "fontace": "~0.4.1", "get-tsconfig": "5.0.0-beta.4", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", - "js-yaml": "^4.3.0", + "js-yaml": "^4.3.2", "jsonc-parser": "^3.3.1", "magic-string": "^1.0.0", "magicast": "^0.5.2", "mrmime": "^2.0.1", "neotraverse": "^1.0.1", - "obug": "^2.1.1", + "obug": "^3.0.0", "p-limit": "^7.3.0", "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.4", - "semver": "^7.7.4", "shiki": "^4.0.2", - "smol-toml": "^1.6.0", - "svgo": "^4.0.1", - "tinyclip": "^0.1.12", + "smol-toml": "^1.8.0", + "svgo": "^4.1.0", + "tinyclip": "^1.0.1", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "ultrahtml": "^1.6.0", "unifont": "~0.7.5", "unstorage": "^1.17.5", + "verkit": "^0.4.0", "vite": "^8.0.13", "vitefu": "^1.1.2", "xxhash-wasm": "^1.1.0", "yargs-parser": "^22.0.0", - "zod": "^4.3.6" + "zod": "^4.5.4" }, "bin": { "astro": "bin/astro.mjs" @@ -3627,10 +3602,10 @@ "url": "https://opencollective.com/astrodotbuild" }, "optionalDependencies": { - "sharp": "^0.34.0 || ^0.35.0" + "sharp": "^0.35.4" }, "peerDependencies": { - "@astrojs/markdown-remark": "7.2.4" + "@astrojs/markdown-remark": "^7.3.0" }, "peerDependenciesMeta": { "@astrojs/markdown-remark": { @@ -3648,15 +3623,236 @@ "schema-dts": "^1.1.0" } }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "license": "Apache-2.0", + "node_modules/astro/node_modules/@astrojs/compiler-binding": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.4.1.tgz", + "integrity": "sha512-ZYVDW1P58OXyxqZbOMp+/2U9KA7y2esIx9r4pWdpZ/l6fCZhaw4ul+D7EgpRVxYLkyTWqzANbTTUFGPFP8zDHA==", + "license": "MIT", "engines": { - "node": ">= 0.4" - } - }, + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@astrojs/compiler-binding-android-arm64": "0.4.1", + "@astrojs/compiler-binding-darwin-arm64": "0.4.1", + "@astrojs/compiler-binding-darwin-x64": "0.4.1", + "@astrojs/compiler-binding-linux-arm64-gnu": "0.4.1", + "@astrojs/compiler-binding-linux-arm64-musl": "0.4.1", + "@astrojs/compiler-binding-linux-x64-gnu": "0.4.1", + "@astrojs/compiler-binding-linux-x64-musl": "0.4.1", + "@astrojs/compiler-binding-wasm32-wasi": "0.4.1", + "@astrojs/compiler-binding-win32-arm64-msvc": "0.4.1", + "@astrojs/compiler-binding-win32-x64-msvc": "0.4.1" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-android-arm64": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-android-arm64/-/compiler-binding-android-arm64-0.4.1.tgz", + "integrity": "sha512-Wtx2DZORuNTLASLLZ8hlrjFaJe1LUloatcCn9EPq7knBhRpjMGXeJANIJMeBZG4igvz7x+3nyAJM2iwCSW9xog==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-darwin-arm64": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.4.1.tgz", + "integrity": "sha512-7iwXcU+hB60Y1SvOfnWHNioT72gDsDQKaDipXh2Onwp/TvQMozhbvhy13wJR8Af940a0h6PbddCeJFpj791UDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-darwin-x64": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.4.1.tgz", + "integrity": "sha512-pifjICos49RXhSVKSDu5gDB0/8j0O7DmxSp1DaWW2PyLG5ekwSkcrfOZto5JqhdI7QYMZB3XOiXpsdOXpS4npA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.4.1.tgz", + "integrity": "sha512-hsZMlNWc6LqWHh9LlSwTq1/XCY7pxA5rkkKIdZRV8mgbOz9OwLvjEoe5Jry13eIZjMUQO8XnQyzk8o/Pjw2YFA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-linux-arm64-musl": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.4.1.tgz", + "integrity": "sha512-a3EW27f+Z9uf57vYmpLgUriA1y9wDhKz57PT8D8XlFZt2HZEWhUxKuxI1jvKVI9p8okYee11WXEm/FHY1G9yoQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-linux-x64-gnu": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.4.1.tgz", + "integrity": "sha512-XruPTKB/SS4DFzeAjQ1ZyM0ieHDjapHkOSnnzRApZ4FXY2YAI7UY3mETjfJiIS/acyZyrnPH5jObv1gATTdUJQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-linux-x64-musl": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.4.1.tgz", + "integrity": "sha512-E8j7lGanqNpudtkUbsFaOLJhmwFe4Ecqux7K9hkj4wULIPNZRM2bYZNcMSj8r1oWvaUiwZl8LaaNwv3+14jqhw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-wasm32-wasi": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.4.1.tgz", + "integrity": "sha512-vNLxIv41ZE+nmPFtw24cRW5ZXG+ZPcAGtgigtjCP8lvcxKI7u2GrXoMsCgEH5fMw8WCEJpwLvsVBg15rJKAkyA==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.2.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.4.1.tgz", + "integrity": "sha512-/xTDgRsFDoTh0/+KFXJ74DY4Jqn8CoSHwa8UP5RAblHfnRHkenwfSl4zYDET61O9vXKLk09UzHjjq09yP20/AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-binding-win32-x64-msvc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.4.1.tgz", + "integrity": "sha512-0x5J6iHZO0Fjo/CVzoIbXKzWnGESftDbEUQ/oXQ61HhUAFoR7+T1jfToZSNAS+gYyBXHSTpMWYC7lzarbhClcg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/compiler-rs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.4.1.tgz", + "integrity": "sha512-//NmAuRhy7eU9iP0ceI5Pymy55M+nUZ//kS6XeOyhBWdDib2KbJOyFaVJ52k7sDkJwTKVox7oPu3SpYiVnGm5A==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-binding": "0.4.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/astro/node_modules/@astrojs/internal-helpers": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.11.0.tgz", + "integrity": "sha512-3rzxJ+xbo0+8YyqOzLziIN32wmsHdCjEVz2sGOpRxJ+Ben/KiLph4ItxBy1abEL+E8fkRzqjg0rfXmaHJGw9JA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "js-yaml": "^4.3.0", + "picomatch": "^4.0.4", + "retext-smartypants": "^6.2.0", + "shiki": "^4.0.2", + "smol-toml": "^1.6.0", + "unified": "^11.0.5" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -3839,6 +4035,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, "license": "MIT", "funding": { "type": "github", @@ -3869,6 +4066,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, "license": "MIT", "funding": { "type": "github", @@ -3931,34 +4129,6 @@ "node": ">=6" } }, - "node_modules/collapse-white-space": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", - "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, "node_modules/colorjs.io": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.7.1.tgz", @@ -3984,6 +4154,7 @@ "version": "14.0.3", "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -4419,6 +4590,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "dev": true, "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -4666,38 +4838,6 @@ "node": ">= 0.4" } }, - "node_modules/esast-util-from-estree": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", - "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "devlop": "^1.0.0", - "estree-util-visit": "^2.0.0", - "unist-util-position-from-estree": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/esast-util-from-js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", - "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "acorn": "^8.0.0", - "esast-util-from-estree": "^2.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/esbuild": { "version": "0.28.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", @@ -4745,18 +4885,6 @@ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, - "node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -4770,122 +4898,31 @@ "node": ">=4" } }, - "node_modules/estree-util-attach-comments": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", - "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 0.6" } }, - "node_modules/estree-util-build-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", - "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "estree-walker": "^3.0.0" + "eventsource-parser": "^3.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-util-is-identifier-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-util-scope": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", - "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-util-to-js": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", - "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "astring": "^1.8.0", - "source-map": "^0.7.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-util-visit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", - "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "license": "MIT" - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" + "engines": { + "node": ">=18.0.0" } }, "node_modules/eventsource-parser": { @@ -5087,46 +5124,13 @@ "url": "https://opencollective.com/express" } }, - "node_modules/find-process": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/find-process/-/find-process-2.1.1.tgz", - "integrity": "sha512-SrQDx3QhlmHM90iqn9rdjCQcw/T+WlpOkHFsjoRgB+zTpDfltNA1VSNYeYELwhUTJy12UFxqjWhmhOrJc+o4sA==", - "license": "MIT", - "dependencies": { - "chalk": "~4.1.2", - "commander": "^14.0.3", - "loglevel": "^1.9.2" - }, - "bin": { - "find-process": "dist/cjs/bin/find-process.js" - } - }, - "node_modules/find-process/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/find-process/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/find-proc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/find-proc/-/find-proc-0.2.0.tgz", + "integrity": "sha512-a6h2nTrgB3g5Wrn4au9Ux4kMk7IJtyF6oA8uGn+mk3weLZssUtc1cp6meHIzzuW2o1srrBAxzkmXLbqjRkgB6w==", "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/flatted": { @@ -5341,9 +5345,9 @@ } }, "node_modules/gray-matter/node_modules/js-yaml": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz", - "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -5403,171 +5407,6 @@ "node": ">= 0.4" } }, - "node_modules/hast-util-from-html": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", - "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "devlop": "^1.1.0", - "hast-util-from-parse5": "^8.0.0", - "parse5": "^7.0.0", - "vfile": "^6.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-html/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/hast-util-from-html/node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/hast-util-from-parse5": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", - "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "devlop": "^1.0.0", - "hastscript": "^9.0.0", - "property-information": "^7.0.0", - "vfile": "^6.0.0", - "vfile-location": "^5.0.0", - "web-namespaces": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-is-element": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-parse-selector": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-raw": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", - "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "@ungap/structured-clone": "^1.0.0", - "hast-util-from-parse5": "^8.0.0", - "hast-util-to-parse5": "^8.0.0", - "html-void-elements": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "parse5": "^7.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-raw/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/hast-util-raw/node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/hast-util-to-estree": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", - "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-attach-comments": "^3.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/hast-util-to-html": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", @@ -5591,68 +5430,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", - "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", - "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-text": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", - "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "hast-util-is-element": "^3.0.0", - "unist-util-find-after": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", @@ -5666,27 +5443,10 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hastscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", - "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/hono": { - "version": "4.13.4", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.4.tgz", - "integrity": "sha512-AGEwKIyRMHRv1t8Wjwa3LHxQ61X5CqrdFT+4BRNTpqS5aJNnpl5WLjADb7vFlJzI/8uK7T5QLVApCMQKNa3LgQ==", + "version": "4.13.9", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.9.tgz", + "integrity": "sha512-7dMkQmZoC4E6F7AtaQSPhlWAdnBti+j7rreMZl8QB4jFiEhP9TWbGWUMi8WYzBCgmgulxuvLQupKqo+Co6Omyg==", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -5763,26 +5523,26 @@ } }, "node_modules/igniteui-astro-components": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/igniteui-astro-components/-/igniteui-astro-components-1.0.2.tgz", - "integrity": "sha512-5GXQPl+94na8d+RdKicfWtDyNrbGrIGYN8RQijTpgPKCb9sXs3RVWe+jx/ccOnCRm1CXg+Uvv0lt5dK3nUKHqg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/igniteui-astro-components/-/igniteui-astro-components-1.3.0.tgz", + "integrity": "sha512-/wf7Zf1IWiDVHGDh1D2hIqxiPpodw0byhhGFB6YhILoN+vu575qZjtcnB+7Kv+u2P6fjxFsMQiW1x+YgJHCQlQ==", "license": "MIT", "dependencies": { - "@astrojs/markdown-satteri": "^0.3.5", - "@astrojs/mdx": "^7.0.7", + "@astrojs/markdown-satteri": "^0.4.2", + "@astrojs/mdx": "^8.0.2", "@fontsource-variable/instrument-sans": "^5.2.8", "@fontsource-variable/inter": "^5.2.8", "@fontsource-variable/jetbrains-mono": "^5.2.8", "github-slugger": "^2.0.0", "jsdom": "^29.0.1", - "satteri": "^0.9.5", + "satteri": "^0.10.5", "shiki": "^4.3.0" }, "engines": { "node": ">=22.12.0" }, "peerDependencies": { - "astro": "^7.0.0", + "astro": "^7.3.4", "igniteui-theming": "^26.0.1", "igniteui-webcomponents": "^7.3.0-beta.1" } @@ -6341,12 +6101,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/inline-style-parser": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", - "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", - "license": "MIT" - }, "node_modules/ip-address": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.5.0.tgz", @@ -6378,6 +6132,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, "license": "MIT", "funding": { "type": "github", @@ -6388,6 +6143,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, "license": "MIT", "dependencies": { "is-alphabetical": "^2.0.0", @@ -6402,6 +6158,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, "license": "MIT", "funding": { "type": "github", @@ -6459,6 +6216,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, "license": "MIT", "funding": { "type": "github", @@ -6518,9 +6276,9 @@ } }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "funding": [ { "type": "github", @@ -6805,3519 +6563,2215 @@ "libc": [ "musl" ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/linkify-it": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", - "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/markdown-it" - } - ], - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, - "node_modules/lit": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.3.tgz", - "integrity": "sha512-fycuvZg/hkpozL00lm1pEJH5nN/lr9ZXd6mJI2HSN4+Bzc+LDNdEApJ6HFbPkdFNHLvOplIIuJvxkS4XUxqirw==", - "license": "BSD-3-Clause", - "dependencies": { - "@lit/reactive-element": "^2.1.0", - "lit-element": "^4.2.0", - "lit-html": "^3.3.0" - } - }, - "node_modules/lit-element": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.2.tgz", - "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", - "license": "BSD-3-Clause", - "dependencies": { - "@lit-labs/ssr-dom-shim": "^1.5.0", - "@lit/reactive-element": "^2.1.0", - "lit-html": "^3.3.0" - } - }, - "node_modules/lit-html": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.3.tgz", - "integrity": "sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==", - "license": "BSD-3-Clause", - "dependencies": { - "@types/trusted-types": "^2.0.2" - } - }, - "node_modules/loglevel": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", - "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/loglevel" - } - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/magic-string": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.2.2.tgz", - "integrity": "sha512-veT/+7iXrXzT39XnEN4lOxtNl72dMgJ8Lp+5Bd6YcMSWpb0n0MjBM8Uuooi6jgJr8dhUW2swQgBmoZVMni5SVg==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/magicast": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.4.tgz", - "integrity": "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "source-map-js": "^1.2.1" - } - }, - "node_modules/markdown-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", - "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/markdown-it": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz", - "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/markdown-it" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.5.0", - "linkify-it": "^5.0.2", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/markdown-table": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/markdownlint": { - "version": "0.41.1", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.41.1.tgz", - "integrity": "sha512-qHKeU2E1bdyNAT077go2FVTNXvYcktN5IHtF6XyeD1l0PClxzSp2tUApAV14ORI8DGX4H9bNKZEzelZp4qn8IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "micromark": "4.0.2", - "micromark-core-commonmark": "2.0.3", - "micromark-extension-directive": "4.0.0", - "micromark-extension-gfm-autolink-literal": "2.1.0", - "micromark-extension-gfm-footnote": "2.1.0", - "micromark-extension-gfm-table": "2.1.1", - "micromark-extension-math": "3.1.0", - "micromark-util-types": "2.0.2", - "string-width": "8.2.1" - }, - "engines": { - "node": ">=22" - }, - "funding": { - "url": "https://github.com/sponsors/DavidAnson" - } - }, - "node_modules/markdownlint-cli": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.49.1.tgz", - "integrity": "sha512-qpYqJbSYf3jv57bdnFmCaZ/Wlu6IYHp2b6SOKrKBJ7OnPrDHIKmx4NERWH49QH9viTI6yO6raVDDn5nrf60VQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "~15.0.0", - "deep-extend": "~0.6.0", - "ignore": "~7.0.6", - "js-yaml": "~5.2.1", - "jsonc-parser": "~3.3.1", - "jsonpointer": "~5.0.1", - "markdown-it": "~14.3.0", - "markdownlint": "~0.41.1", - "minimatch": "~10.2.5", - "run-con": "~1.3.3", - "smol-toml": "~1.7.0", - "tinyglobby": "~0.2.17" - }, - "bin": { - "markdownlint": "markdownlint.js" - }, - "engines": { - "node": ">=22" - } - }, - "node_modules/markdownlint-cli/node_modules/commander": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", - "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/markdownlint-cli/node_modules/js-yaml": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.3.tgz", - "integrity": "sha512-n+mUVyUX5bVv7G/G2zyIHOhdxfuU1dY2NOFzTQUWiMUbFss8b57NFlgCCaggU78wSw5KVS9cllzeLyzyR+n5nw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.mjs" - } - }, - "node_modules/markdownlint-cli/node_modules/smol-toml": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.2.tgz", - "integrity": "sha512-pXFZ9B2WinEPzxWkMmlYE/oYx2BP+qLrE95wP8tCuK901uLSMGdCb6QSr82z+wnhXkG4+cO+OMLbZB2Cn+97zw==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 18" - }, - "funding": { - "url": "https://github.com/sponsors/cyyynthia" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mdast-util-definitions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", - "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", - "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", - "license": "MIT", - "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "ccount": "^2.0.0", - "devlop": "^1.0.0", - "mdast-util-find-and-replace": "^3.0.0", - "micromark-util-character": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", - "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", - "license": "MIT", - "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", - "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", - "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdn-data": { - "version": "2.27.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", - "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", - "license": "CC0-1.0" - }, - "node_modules/mdurl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz", - "integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==", - "dev": true, - "license": "MIT" - }, - "node_modules/media-typer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", - "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-directive": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-4.0.0.tgz", - "integrity": "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "parse-entities": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "license": "MIT", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-math": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", - "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/katex": "^0.16.0", - "devlop": "^1.0.0", - "katex": "^0.16.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdx-expression": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", - "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-mdx-expression": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-mdx-jsx": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", - "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "micromark-factory-mdx-expression": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdx-md": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", - "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdxjs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", - "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", - "license": "MIT", - "dependencies": { - "acorn": "^8.0.0", - "acorn-jsx": "^5.0.0", - "micromark-extension-mdx-expression": "^3.0.0", - "micromark-extension-mdx-jsx": "^3.0.0", - "micromark-extension-mdx-md": "^2.0.0", - "micromark-extension-mdxjs-esm": "^3.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdxjs-esm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", - "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-position-from-estree": "^2.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-mdx-expression": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", - "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-events-to-acorn": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-position-from-estree": "^2.0.0", - "vfile-message": "^4.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" ], - "license": "MIT" - }, - "node_modules/micromark-util-events-to-acorn": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", - "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "libc": [ + "glibc" ], - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/unist": "^3.0.0", - "devlop": "^1.0.0", - "estree-util-visit": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "vfile-message": "^4.0.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "libc": [ + "musl" ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" ], - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "node_modules/linkify-it": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", + "dev": true, "funding": [ { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" + "type": "github", + "url": "https://github.com/sponsors/puzrin" }, { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/markdown-it" } ], "license": "MIT", "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "uc.micro": "^2.0.0" } }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node_modules/lit": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.3.tgz", + "integrity": "sha512-fycuvZg/hkpozL00lm1pEJH5nN/lr9ZXd6mJI2HSN4+Bzc+LDNdEApJ6HFbPkdFNHLvOplIIuJvxkS4XUxqirw==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" } }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", + "node_modules/lit-element": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.2.tgz", + "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", + "license": "BSD-3-Clause", "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "@lit-labs/ssr-dom-shim": "^1.5.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" } }, - "node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dev": true, - "license": "BlueOak-1.0.0", + "node_modules/lit-html": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.3.tgz", + "integrity": "sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==", + "license": "BSD-3-Clause", "dependencies": { - "brace-expansion": "^5.0.8" - }, + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "license": "BlueOak-1.0.0", "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "20 || >=22" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, + "node_modules/magic-string": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.2.2.tgz", + "integrity": "sha512-veT/+7iXrXzT39XnEN4lOxtNl72dMgJ8Lp+5Bd6YcMSWpb0n0MjBM8Uuooi6jgJr8dhUW2swQgBmoZVMni5SVg==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "node_modules/magicast": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.4.tgz", + "integrity": "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==", "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "source-map-js": "^1.2.1" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", - "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "node_modules/markdown-it": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz", + "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==", + "dev": true, "funding": [ { "type": "github", - "url": "https://github.com/sponsors/ai" + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" } ], "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.5.0", + "linkify-it": "^5.0.2", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "bin": { + "markdown-it": "bin/markdown-it.mjs" } }, - "node_modules/negotiator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", - "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "node_modules/markdownlint": { + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.41.1.tgz", + "integrity": "sha512-qHKeU2E1bdyNAT077go2FVTNXvYcktN5IHtF6XyeD1l0PClxzSp2tUApAV14ORI8DGX4H9bNKZEzelZp4qn8IA==", + "dev": true, "license": "MIT", "dependencies": { - "content-type": "^2.1.0" - }, - "engines": { - "node": ">=18" + "micromark": "4.0.2", + "micromark-core-commonmark": "2.0.3", + "micromark-extension-directive": "4.0.0", + "micromark-extension-gfm-autolink-literal": "2.1.0", + "micromark-extension-gfm-footnote": "2.1.0", + "micromark-extension-gfm-table": "2.1.1", + "micromark-extension-math": "3.1.0", + "micromark-util-types": "2.0.2", + "string-width": "8.2.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/negotiator/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "license": "MIT", "engines": { - "node": ">=18" + "node": ">=22" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/neotraverse": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-1.0.1.tgz", - "integrity": "sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==", - "license": "MIT", - "engines": { - "node": ">= 10" + "url": "https://github.com/sponsors/DavidAnson" } }, - "node_modules/nlcst-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", - "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "node_modules/markdownlint-cli": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.49.1.tgz", + "integrity": "sha512-qpYqJbSYf3jv57bdnFmCaZ/Wlu6IYHp2b6SOKrKBJ7OnPrDHIKmx4NERWH49QH9viTI6yO6raVDDn5nrf60VQQ==", + "dev": true, "license": "MIT", "dependencies": { - "@types/nlcst": "^2.0.0" + "commander": "~15.0.0", + "deep-extend": "~0.6.0", + "ignore": "~7.0.6", + "js-yaml": "~5.2.1", + "jsonc-parser": "~3.3.1", + "jsonpointer": "~5.0.1", + "markdown-it": "~14.3.0", + "markdownlint": "~0.41.1", + "minimatch": "~10.2.5", + "run-con": "~1.3.3", + "smol-toml": "~1.7.0", + "tinyglobby": "~0.2.17" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=22" } }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "license": "MIT", - "optional": true - }, - "node_modules/node-fetch-native": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", - "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", - "license": "MIT" - }, - "node_modules/node-mock-http": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.5.tgz", - "integrity": "sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==", - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/markdownlint-cli/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=22.12.0" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "license": "BSD-2-Clause", + "node_modules/markdownlint-cli/node_modules/js-yaml": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.3.tgz", + "integrity": "sha512-n+mUVyUX5bVv7G/G2zyIHOhdxfuU1dY2NOFzTQUWiMUbFss8b57NFlgCCaggU78wSw5KVS9cllzeLyzyR+n5nw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", "dependencies": { - "boolbase": "^1.0.0" + "argparse": "^2.0.1" }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "bin": { + "js-yaml": "bin/js-yaml.mjs" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", + "node_modules/markdownlint-cli/node_modules/smol-toml": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.2.tgz", + "integrity": "sha512-pXFZ9B2WinEPzxWkMmlYE/oYx2BP+qLrE95wP8tCuK901uLSMGdCb6QSr82z+wnhXkG4+cO+OMLbZB2Cn+97zw==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.4" + "node": ">= 18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/cyyynthia" } }, - "node_modules/obug": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", - "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/ofetch": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", - "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", - "license": "MIT", - "dependencies": { - "destr": "^2.0.5", - "node-fetch-native": "^1.6.7", - "ufo": "^1.6.1" + "node": ">= 0.4" } }, - "node_modules/ohash": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.12.tgz", - "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==", - "license": "MIT" - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", "license": "MIT", "dependencies": { - "ee-first": "1.1.1" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, - "engines": { - "node": ">= 0.8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" }, - "node_modules/oniguruma-parser": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", - "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "node_modules/mdurl": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz", + "integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==", + "dev": true, "license": "MIT" }, - "node_modules/oniguruma-to-es": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", - "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", - "license": "MIT", - "dependencies": { - "oniguruma-parser": "^0.12.2", - "regex": "^6.1.0", - "regex-recursion": "^6.0.2" - } - }, - "node_modules/p-limit": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.1.tgz", - "integrity": "sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==", + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", "license": "MIT", - "dependencies": { - "yocto-queue": "^1.2.1" - }, "engines": { - "node": ">=20" + "node": ">= 0.8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/p-queue": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.3.tgz", - "integrity": "sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==", + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", - "dependencies": { - "eventemitter3": "^5.0.4", - "p-timeout": "^7.0.0" - }, "engines": { - "node": ">=20" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-timeout": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", - "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/package-manager-detector": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz", - "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", - "license": "MIT" - }, - "node_modules/pagefind": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.5.2.tgz", - "integrity": "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==", + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "bin": { - "pagefind": "lib/runner/bin.cjs" - }, - "optionalDependencies": { - "@pagefind/darwin-arm64": "1.5.2", - "@pagefind/darwin-x64": "1.5.2", - "@pagefind/freebsd-x64": "1.5.2", - "@pagefind/linux-arm64": "1.5.2", - "@pagefind/linux-x64": "1.5.2", - "@pagefind/windows-arm64": "1.5.2", - "@pagefind/windows-x64": "1.5.2" + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/parent-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", - "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", + "node_modules/micromark-extension-directive": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-4.0.0.tgz", + "integrity": "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==", "dev": true, "license": "MIT", "dependencies": { - "callsites": "^3.1.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse-entities": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "license": "MIT" - }, - "node_modules/parse-latin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", - "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, "license": "MIT", "dependencies": { - "@types/nlcst": "^2.0.0", - "@types/unist": "^3.0.0", - "nlcst-to-string": "^4.0.0", - "unist-util-modify-children": "^4.0.0", - "unist-util-visit-children": "^3.0.0", - "vfile": "^6.0.0" + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", - "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "dev": true, "license": "MIT", "dependencies": { - "entities": "^8.0.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse5/node_modules/entities": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", - "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=20.19.0" + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "dev": true, - "license": "MIT" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/path-to-regexp": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/piccolore": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", - "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", - "license": "ISC" + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=16.20.0" + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/postcss": { - "version": "8.5.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", - "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.17", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/prismjs": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/process-ancestry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/process-ancestry/-/process-ancestry-0.1.0.tgz", - "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==", + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=18.0.0" + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/property-information": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", - "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" + "micromark-util-types": "^2.0.0" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", - "license": "BSD-3-Clause", "dependencies": { - "es-define-property": "^1.0.1", - "side-channel": "^1.1.1" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/radix3": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", - "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/range-parser": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", - "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" } }, - "node_modules/raw-body": { + "node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.10" - } - }, - "node_modules/readdirp": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", - "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/recma-build-jsx": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", - "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-util-build-jsx": "^3.0.0", - "vfile": "^6.0.0" + "node": ">=18" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://opencollective.com/express" } }, - "node_modules/recma-jsx": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", - "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", - "license": "MIT", + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "acorn-jsx": "^5.0.0", - "estree-util-to-js": "^2.0.0", - "recma-parse": "^1.0.0", - "recma-stringify": "^1.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "brace-expansion": "^5.0.8" }, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/recma-parse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", - "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "esast-util-from-js": "^2.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" + "engines": { + "node": "18 || 20 || >=22" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/recma-stringify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", - "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-util-to-js": "^2.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" - }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", - "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", - "license": "MIT", - "dependencies": { - "regex-utilities": "^2.3.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regex-recursion": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", - "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "license": "MIT", - "dependencies": { - "regex-utilities": "^2.3.0" + "engines": { + "node": ">=10" } }, - "node_modules/regex-utilities": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", - "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/rehype-raw": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", - "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-raw": "^9.0.0", - "vfile": "^6.0.0" + "bin": { + "nanoid": "bin/nanoid.cjs" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/rehype-recma": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", - "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "node_modules/negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "hast-util-to-estree": "^3.0.0" + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://opencollective.com/express" } }, - "node_modules/rehype-stringify": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", - "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "node_modules/negotiator/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-to-html": "^9.0.0", - "unified": "^11.0.0" + "engines": { + "node": ">=18" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://opencollective.com/express" } }, - "node_modules/remark-gfm": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", - "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "node_modules/neotraverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-1.0.1.tgz", + "integrity": "sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==", "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-gfm": "^3.0.0", - "micromark-extension-gfm": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 10" } }, - "node_modules/remark-mdx": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", - "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", "license": "MIT", "dependencies": { - "mdast-util-mdx": "^3.0.0", - "micromark-extension-mdxjs": "^3.0.0" + "@types/nlcst": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "optional": true + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-mock-http": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.5.tgz", + "integrity": "sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==", + "license": "MIT" }, - "node_modules/remark-rehype": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", - "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" + "boolbase": "^1.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/remark-smartypants": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.3.tgz", - "integrity": "sha512-gCaK+ndZ0hYezlqFegHFCVh2CQemsi0Npdh1qVM9bxlUFknjkbP6VmojWhddOCrbK0PbbacmYLWfTULRiT1eWA==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", - "dependencies": { - "retext": "^9.0.0", - "retext-smartypants": "^6.0.0", - "unified": "^11.0.4", - "unist-util-visit": "^5.0.0" - }, "engines": { - "node": ">=16.0.0" + "node": ">=0.10.0" } }, - "node_modules/remark-stringify": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-to-markdown": "^2.0.0", - "unified": "^11.0.0" + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/obug/-/obug-3.0.0.tgz", + "integrity": "sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" } }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, + "node_modules/ohash": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.12.tgz", + "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==", + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" } }, - "node_modules/retext": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", - "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", "license": "MIT", "dependencies": { - "@types/nlcst": "^2.0.0", - "retext-latin": "^4.0.0", - "retext-stringify": "^4.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" } }, - "node_modules/retext-latin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", - "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "node_modules/p-limit": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.1.tgz", + "integrity": "sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==", "license": "MIT", "dependencies": { - "@types/nlcst": "^2.0.0", - "parse-latin": "^7.0.0", - "unified": "^11.0.0" + "yocto-queue": "^1.2.1" + }, + "engines": { + "node": ">=20" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/retext-smartypants": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", - "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "node_modules/p-queue": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.3.tgz", + "integrity": "sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==", "license": "MIT", "dependencies": { - "@types/nlcst": "^2.0.0", - "nlcst-to-string": "^4.0.0", - "unist-util-visit": "^5.0.0" + "eventemitter3": "^5.0.4", + "p-timeout": "^7.0.0" + }, + "engines": { + "node": ">=20" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/retext-stringify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", - "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "node_modules/p-timeout": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", + "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", "license": "MIT", - "dependencies": { - "@types/nlcst": "^2.0.0", - "nlcst-to-string": "^4.0.0", - "unified": "^11.0.0" + "engines": { + "node": ">=20" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rolldown": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.5.tgz", - "integrity": "sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==", + "node_modules/package-manager-detector": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz", + "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", + "license": "MIT" + }, + "node_modules/pagefind": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.5.2.tgz", + "integrity": "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==", "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.146.0", - "@rolldown/pluginutils": "^1.0.0" - }, "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" + "pagefind": "lib/runner/bin.cjs" }, "optionalDependencies": { - "@rolldown/binding-android-arm-eabi": "1.2.5", - "@rolldown/binding-android-arm64": "1.2.5", - "@rolldown/binding-darwin-arm64": "1.2.5", - "@rolldown/binding-darwin-x64": "1.2.5", - "@rolldown/binding-freebsd-x64": "1.2.5", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.5", - "@rolldown/binding-linux-arm64-gnu": "1.2.5", - "@rolldown/binding-linux-arm64-musl": "1.2.5", - "@rolldown/binding-linux-ppc64-gnu": "1.2.5", - "@rolldown/binding-linux-s390x-gnu": "1.2.5", - "@rolldown/binding-linux-x64-gnu": "1.2.5", - "@rolldown/binding-linux-x64-musl": "1.2.5", - "@rolldown/binding-openharmony-arm64": "1.2.5", - "@rolldown/binding-win32-arm64-msvc": "1.2.5", - "@rolldown/binding-win32-x64-msvc": "1.2.5" + "@pagefind/darwin-arm64": "1.5.2", + "@pagefind/darwin-x64": "1.5.2", + "@pagefind/freebsd-x64": "1.5.2", + "@pagefind/linux-arm64": "1.5.2", + "@pagefind/linux-x64": "1.5.2", + "@pagefind/windows-arm64": "1.5.2", + "@pagefind/windows-x64": "1.5.2" } }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "node_modules/parent-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", + "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", + "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" + "callsites": "^3.1.0" }, "engines": { - "node": ">= 18" + "node": ">=8" } }, - "node_modules/run-con": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.3.tgz", - "integrity": "sha512-Lb7OKM9aaykzyoNiHGhSVCjZsvbyy6qDMp2vDXL+MoCfz3GfNJtHYH7uYsU3QNMyInBk++xx+EZ8xZ8Sxs5fNQ==", + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "license": "MIT", "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~7.0.0", - "minimist": "^1.2.8", - "strip-json-comments": "~3.1.1" + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" }, - "bin": { - "run-con": "cli.js" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/run-con/node_modules/ini": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-7.0.0.tgz", - "integrity": "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==", + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "dev": true, - "license": "ISC", - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" - } - }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, - "node_modules/sass": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.103.1.tgz", - "integrity": "sha512-9icZURbP51S6S0QGoyaeqk9uB06GNWxsFYWfH5RgpFgqK5FA8tJcM3AdVxrZEVJ7dz+L87nG95gBKf4VuaMHGw==", - "license": "MIT", - "optional": true, - "dependencies": { - "chokidar": "^5.0.0", - "immutable": "^5.1.5", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=20.19.0" - }, - "optionalDependencies": { - "@parcel/watcher": "^2.4.1" - } - }, - "node_modules/sass-embedded": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.103.1.tgz", - "integrity": "sha512-UVIuFZPzz+4DXYbHzQ5gKaKkyP2IH3Sc/WoF63N2V7QIfnC2E9UpQAtiKlCVJTfBe43HRgHDBLnXpZkYAEBsNQ==", - "devOptional": true, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", "license": "MIT", "dependencies": { - "@bufbuild/protobuf": "^2.5.0", - "colorjs.io": "^0.7.0", - "immutable": "^5.1.5", - "rxjs": "^7.4.0", - "supports-color": "^8.1.1", - "sync-child-process": "^1.0.2", - "varint": "^6.0.0" - }, - "bin": { - "sass": "dist/bin/sass.js" + "entities": "^8.0.0" }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "license": "BSD-2-Clause", "engines": { "node": ">=20.19.0" }, - "optionalDependencies": { - "sass-embedded-all-unknown": "1.103.1", - "sass-embedded-android-arm": "1.103.1", - "sass-embedded-android-arm64": "1.103.1", - "sass-embedded-android-riscv64": "1.103.1", - "sass-embedded-android-x64": "1.103.1", - "sass-embedded-darwin-arm64": "1.103.1", - "sass-embedded-darwin-x64": "1.103.1", - "sass-embedded-linux-arm": "1.103.1", - "sass-embedded-linux-arm64": "1.103.1", - "sass-embedded-linux-musl-arm": "1.103.1", - "sass-embedded-linux-musl-arm64": "1.103.1", - "sass-embedded-linux-musl-riscv64": "1.103.1", - "sass-embedded-linux-musl-x64": "1.103.1", - "sass-embedded-linux-riscv64": "1.103.1", - "sass-embedded-linux-x64": "1.103.1", - "sass-embedded-unknown-all": "1.103.1", - "sass-embedded-win32-arm64": "1.103.1", - "sass-embedded-win32-x64": "1.103.1" + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/sass-embedded-all-unknown": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.103.1.tgz", - "integrity": "sha512-MwX2ap06TbImAqlbnH6EndgBBejk6Eq2QB6Ae2hukCn9wmXf9cRu27um3mz3tyB4oJOOku0xfHqFH/+ckYj6YA==", - "cpu": [ - "!arm", - "!arm64", - "!riscv64", - "!x64" - ], + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", - "optional": true, - "dependencies": { - "sass": "1.103.1" + "engines": { + "node": ">= 0.8" } }, - "node_modules/sass-embedded-android-arm": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.103.1.tgz", - "integrity": "sha512-p36WHpsu5HEo2+NVNbI2Nmb8VgVH0xwOQyzghvZhF7ikGCzEVYI5BP28vHUZlCcgj2TUvMEJKI2lV336a+F/sg==", - "cpu": [ - "arm" - ], + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=14.0.0" + "node": ">=8" } }, - "node_modules/sass-embedded-android-arm64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.103.1.tgz", - "integrity": "sha512-jBXWMksyz55XeLOWvQs64BqiG5DcqflmMxcvMoA2oHtQT/7XZ02hBn502qpcF/q8Qd+qqG/hU5ccM+hGXrbQZw==", - "cpu": [ - "arm64" - ], + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/piccolore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", + "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", + "license": "ISC" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=14.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/sass-embedded-android-riscv64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.103.1.tgz", - "integrity": "sha512-rzrH7RNntk0rx+zCE9xOiAIUt37D1cQKvFfcoX0xiePdGbNHBN8DWKaWN9vaCRfbgKCmxPjevzaqFNI/G/8E1A==", - "cpu": [ - "riscv64" - ], + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=14.0.0" + "node": ">=16.20.0" } }, - "node_modules/sass-embedded-android-x64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.103.1.tgz", - "integrity": "sha512-EQglAJXJutuIcqgZf7YOwzao2ND6ow/OgqN+cM48/Qaeb6AimYmZiUJmM9FFcmS3Q2n1k6/2OU3l3Hlin7bFpw==", - "cpu": [ - "x64" + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } ], "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, "engines": { - "node": ">=14.0.0" + "node": "^10 || ^12 || >=14" } }, - "node_modules/sass-embedded-darwin-arm64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.103.1.tgz", - "integrity": "sha512-rlaBeCul8pLbDRKdBAxdDxSBwFU5fbX42ci6CxW2Vbs34jWTMQ72+nE2v2KkGGce+JnYbb7UV6xDP/4uDWWi+w==", - "cpu": [ - "arm64" - ], + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=14.0.0" + "node": ">=6" } }, - "node_modules/sass-embedded-darwin-x64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.103.1.tgz", - "integrity": "sha512-VSKFfhI//AOct6ppFmAaSH7tlW2LOFECMGs77jIoWf0ZjvGch/3sc9lUTTdIaYIOnTS4qpZck+8OcI2D0G92QA==", - "cpu": [ - "x64" - ], + "node_modules/process-ancestry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/process-ancestry/-/process-ancestry-0.1.0.tgz", + "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, - "node_modules/sass-embedded-linux-arm": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.103.1.tgz", - "integrity": "sha512-tJRLPUtBwXHTnBnG7I39gQvCLreuOHLLCMyKHPR1hQ7aFNwiZjADYzKMRQPNMUqti/Os9z+6I7V13FqgQHfuzg==", - "cpu": [ - "arm" - ], - "libc": "glibc", + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, "engines": { - "node": ">=14.0.0" + "node": ">= 0.10" } }, - "node_modules/sass-embedded-linux-arm64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.103.1.tgz", - "integrity": "sha512-rC+80/Xr9svo0ka2Zr/sjD+N1zEHTw2Urm/nsEjaVp5HSH2i22jwhTKTIqie2OLl6ti+qdYnbI0sSfxOYRtgrg==", - "cpu": [ - "arm64" - ], - "libc": "glibc", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=14.0.0" + "node": ">=6" } }, - "node_modules/sass-embedded-linux-musl-arm": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.103.1.tgz", - "integrity": "sha512-N8L/kgVzXpnH+8d6ErIzqvb0l8kHODR3OfPaf0Azw6DOLGtEjwDRUbHno+G7iogGzyPOjKsM8OdyqHJj/bpTdw==", - "cpu": [ - "arm" - ], - "libc": "musl", + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=14.0.0" + "node": ">=6" } }, - "node_modules/sass-embedded-linux-musl-arm64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.103.1.tgz", - "integrity": "sha512-jMgG/C/VMo7+ShMFdk0xjJmQmYkj1PbJu/yrQiaQHpuo5pE2G+vnkEgsuM5EM3lTQ4MbMfnf715qy1fkbNPiUQ==", - "cpu": [ - "arm64" - ], - "libc": "musl", - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/qs": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, "engines": { - "node": ">=14.0.0" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sass-embedded-linux-musl-riscv64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.103.1.tgz", - "integrity": "sha512-LZm8rEvI6sKU87qPOlODsYeAs7CmWy0B4ShYkjG4OMcGCcV4Ffxn25XW4TFqmruThITQvJ8WT+WGblzdoxYgbA==", - "cpu": [ - "riscv64" - ], - "libc": "musl", + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=14.0.0" + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/sass-embedded-linux-musl-x64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.103.1.tgz", - "integrity": "sha512-rmKzgk4t6RpaDhSefbbnk5yrA4pk1nHlVhJECGay8yMfzK8eglATeY9fzPgt89xCuQk6rkOiy11e+m8tLYOW5Q==", - "cpu": [ - "x64" - ], - "libc": "musl", + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, "engines": { - "node": ">=14.0.0" + "node": ">= 0.10" } }, - "node_modules/sass-embedded-linux-riscv64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.103.1.tgz", - "integrity": "sha512-xydQmtxla31uMrmN6z+mAogVGdEMDmkUElVq2+udomX/TPZDYJBkApEyJl237M2VLWVv29v1N4U4i2Z4xa7SDA==", - "cpu": [ - "riscv64" - ], - "libc": "glibc", + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=14.0.0" + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/sass-embedded-linux-x64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.103.1.tgz", - "integrity": "sha512-Rln1oWm0MWKzzemOgQWrRFzfVBARwS9qxAidZPpCQHSohzPnWizFkmY1CUJad/YJNsA7sscueMdX63OEvxoM8w==", - "cpu": [ - "x64" - ], - "libc": "glibc", + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" + "dependencies": { + "regex-utilities": "^2.3.0" } }, - "node_modules/sass-embedded-unknown-all": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.103.1.tgz", - "integrity": "sha512-p7kI4US8+n+YguKczXh+4KcodJnk+8cwv+QFdvMaz3OfPrdHV0EnhPsaVDWD9qXb1XXCEdUhpp6vQwGk3eKc3A==", + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", "license": "MIT", - "optional": true, - "os": [ - "!android", - "!darwin", - "!linux", - "!win32" - ], "dependencies": { - "sass": "1.103.1" + "regex-utilities": "^2.3.0" } }, - "node_modules/sass-embedded-win32-arm64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.103.1.tgz", - "integrity": "sha512-/0renOj3SpZGu4TA8CZJ6qZbTxGZk1khkPfiBTmV1uFB40ESYM5VsdXNj76P07bsAjIj9X2fCjTafLQFLSd9Nw==", - "cpu": [ - "arm64" - ], + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=14.0.0" + "node": ">=0.10.0" } }, - "node_modules/sass-embedded-win32-x64": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.103.1.tgz", - "integrity": "sha512-fIg60j9u5YlLUU3W8FvySMR4HHIo9R12HHFQTW7njyQ8nXqgR+t+XfCzGJloQka8g583BlAfu31Q76Ljr5o+9g==", - "cpu": [ - "x64" - ], + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=14.0.0" + "node": ">=8" } }, - "node_modules/satteri": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.9.5.tgz", - "integrity": "sha512-ZuWVl+vnM64y+/TtX8Kosv2c00W+hLQiiwnEL6H0UKVVrxFqMw4D2CJHHQaouVd89OAhtBBfjWLqhKi3TVUV4w==", + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.5", - "@types/hast": "^3.0.4", - "@types/mdast": "^4.0.4", - "@types/unist": "^3.0.3" + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" }, - "optionalDependencies": { - "@bruits/satteri-darwin-arm64": "0.9.5", - "@bruits/satteri-darwin-x64": "0.9.5", - "@bruits/satteri-linux-arm64-gnu": "0.9.5", - "@bruits/satteri-linux-arm64-musl": "0.9.5", - "@bruits/satteri-linux-x64-gnu": "0.9.5", - "@bruits/satteri-linux-x64-musl": "0.9.5", - "@bruits/satteri-wasm32-wasi": "0.9.5", - "@bruits/satteri-win32-arm64-msvc": "0.9.5", - "@bruits/satteri-win32-x64-msvc": "0.9.5" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/sax": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", - "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", - "license": "BlueOak-1.0.0", + "node_modules/rolldown": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.5.tgz", + "integrity": "sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.146.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, "engines": { - "node": ">=11.0.0" + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.5", + "@rolldown/binding-android-arm64": "1.2.5", + "@rolldown/binding-darwin-arm64": "1.2.5", + "@rolldown/binding-darwin-x64": "1.2.5", + "@rolldown/binding-freebsd-x64": "1.2.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.5", + "@rolldown/binding-linux-arm64-gnu": "1.2.5", + "@rolldown/binding-linux-arm64-musl": "1.2.5", + "@rolldown/binding-linux-ppc64-gnu": "1.2.5", + "@rolldown/binding-linux-s390x-gnu": "1.2.5", + "@rolldown/binding-linux-x64-gnu": "1.2.5", + "@rolldown/binding-linux-x64-musl": "1.2.5", + "@rolldown/binding-openharmony-arm64": "1.2.5", + "@rolldown/binding-win32-arm64-msvc": "1.2.5", + "@rolldown/binding-win32-x64-msvc": "1.2.5" } }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "license": "ISC", + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", "dependencies": { - "xmlchars": "^2.2.0" + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" }, "engines": { - "node": ">=v12.22.7" + "node": ">= 18" } }, - "node_modules/schema-dts": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.5.tgz", - "integrity": "sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==", - "license": "Apache-2.0", - "peer": true - }, - "node_modules/section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "license": "MIT", + "node_modules/run-con": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.3.tgz", + "integrity": "sha512-Lb7OKM9aaykzyoNiHGhSVCjZsvbyy6qDMp2vDXL+MoCfz3GfNJtHYH7uYsU3QNMyInBk++xx+EZ8xZ8Sxs5fNQ==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" + "deep-extend": "^0.6.0", + "ini": "~7.0.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" }, - "engines": { - "node": ">=4" + "bin": { + "run-con": "cli.js" } }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "node_modules/run-con/node_modules/ini": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-7.0.0.tgz", + "integrity": "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==", + "dev": true, "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, "engines": { - "node": ">=10" + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" } }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "license": "MIT", + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "tslib": "^2.1.0" } }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.103.1.tgz", + "integrity": "sha512-9icZURbP51S6S0QGoyaeqk9uB06GNWxsFYWfH5RgpFgqK5FA8tJcM3AdVxrZEVJ7dz+L87nG95gBKf4VuaMHGw==", "license": "MIT", + "optional": true, "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" }, "engines": { - "node": ">= 18" + "node": ">=20.19.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/sharp": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", - "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", - "license": "Apache-2.0", + "node_modules/sass-embedded": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.103.1.tgz", + "integrity": "sha512-UVIuFZPzz+4DXYbHzQ5gKaKkyP2IH3Sc/WoF63N2V7QIfnC2E9UpQAtiKlCVJTfBe43HRgHDBLnXpZkYAEBsNQ==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@img/colour": "^1.1.0", - "detect-libc": "^2.1.2", - "semver": "^7.8.5" + "@bufbuild/protobuf": "^2.5.0", + "colorjs.io": "^0.7.0", + "immutable": "^5.1.5", + "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "sync-child-process": "^1.0.2", + "varint": "^6.0.0" }, - "engines": { - "node": ">=20.9.0" + "bin": { + "sass": "dist/bin/sass.js" }, - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=20.19.0" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.35.3", - "@img/sharp-darwin-x64": "0.35.3", - "@img/sharp-freebsd-wasm32": "0.35.3", - "@img/sharp-libvips-darwin-arm64": "1.3.2", - "@img/sharp-libvips-darwin-x64": "1.3.2", - "@img/sharp-libvips-linux-arm": "1.3.2", - "@img/sharp-libvips-linux-arm64": "1.3.2", - "@img/sharp-libvips-linux-ppc64": "1.3.2", - "@img/sharp-libvips-linux-riscv64": "1.3.2", - "@img/sharp-libvips-linux-s390x": "1.3.2", - "@img/sharp-libvips-linux-x64": "1.3.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", - "@img/sharp-libvips-linuxmusl-x64": "1.3.2", - "@img/sharp-linux-arm": "0.35.3", - "@img/sharp-linux-arm64": "0.35.3", - "@img/sharp-linux-ppc64": "0.35.3", - "@img/sharp-linux-riscv64": "0.35.3", - "@img/sharp-linux-s390x": "0.35.3", - "@img/sharp-linux-x64": "0.35.3", - "@img/sharp-linuxmusl-arm64": "0.35.3", - "@img/sharp-linuxmusl-x64": "0.35.3", - "@img/sharp-webcontainers-wasm32": "0.35.3", - "@img/sharp-win32-arm64": "0.35.3", - "@img/sharp-win32-ia32": "0.35.3", - "@img/sharp-win32-x64": "0.35.3" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "sass-embedded-all-unknown": "1.103.1", + "sass-embedded-android-arm": "1.103.1", + "sass-embedded-android-arm64": "1.103.1", + "sass-embedded-android-riscv64": "1.103.1", + "sass-embedded-android-x64": "1.103.1", + "sass-embedded-darwin-arm64": "1.103.1", + "sass-embedded-darwin-x64": "1.103.1", + "sass-embedded-linux-arm": "1.103.1", + "sass-embedded-linux-arm64": "1.103.1", + "sass-embedded-linux-musl-arm": "1.103.1", + "sass-embedded-linux-musl-arm64": "1.103.1", + "sass-embedded-linux-musl-riscv64": "1.103.1", + "sass-embedded-linux-musl-x64": "1.103.1", + "sass-embedded-linux-riscv64": "1.103.1", + "sass-embedded-linux-x64": "1.103.1", + "sass-embedded-unknown-all": "1.103.1", + "sass-embedded-win32-arm64": "1.103.1", + "sass-embedded-win32-x64": "1.103.1" } }, - "node_modules/sharp/node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", - "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", + "node_modules/sass-embedded-all-unknown": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.103.1.tgz", + "integrity": "sha512-MwX2ap06TbImAqlbnH6EndgBBejk6Eq2QB6Ae2hukCn9wmXf9cRu27um3mz3tyB4oJOOku0xfHqFH/+ckYj6YA==", "cpu": [ - "arm64" + "!arm", + "!arm64", + "!riscv64", + "!x64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.2" + "dependencies": { + "sass": "1.103.1" } }, - "node_modules/sharp/node_modules/@img/sharp-darwin-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", - "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", + "node_modules/sass-embedded-android-arm": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.103.1.tgz", + "integrity": "sha512-p36WHpsu5HEo2+NVNbI2Nmb8VgVH0xwOQyzghvZhF7ikGCzEVYI5BP28vHUZlCcgj2TUvMEJKI2lV336a+F/sg==", "cpu": [ - "x64" + "arm" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "darwin" + "android" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.2" + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", - "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", + "node_modules/sass-embedded-android-arm64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.103.1.tgz", + "integrity": "sha512-jBXWMksyz55XeLOWvQs64BqiG5DcqflmMxcvMoA2oHtQT/7XZ02hBn502qpcF/q8Qd+qqG/hU5ccM+hGXrbQZw==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "darwin" + "android" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", - "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", + "node_modules/sass-embedded-android-riscv64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.103.1.tgz", + "integrity": "sha512-rzrH7RNntk0rx+zCE9xOiAIUt37D1cQKvFfcoX0xiePdGbNHBN8DWKaWN9vaCRfbgKCmxPjevzaqFNI/G/8E1A==", "cpu": [ - "x64" + "riscv64" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "darwin" + "android" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", - "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", - "cpu": [ - "arm" - ], - "libc": [ - "glibc" + "node_modules/sass-embedded-android-x64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.103.1.tgz", + "integrity": "sha512-EQglAJXJutuIcqgZf7YOwzao2ND6ow/OgqN+cM48/Qaeb6AimYmZiUJmM9FFcmS3Q2n1k6/2OU3l3Hlin7bFpw==", + "cpu": [ + "x64" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", - "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", + "node_modules/sass-embedded-darwin-arm64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.103.1.tgz", + "integrity": "sha512-rlaBeCul8pLbDRKdBAxdDxSBwFU5fbX42ci6CxW2Vbs34jWTMQ72+nE2v2KkGGce+JnYbb7UV6xDP/4uDWWi+w==", "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", - "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", + "node_modules/sass-embedded-darwin-x64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.103.1.tgz", + "integrity": "sha512-VSKFfhI//AOct6ppFmAaSH7tlW2LOFECMGs77jIoWf0ZjvGch/3sc9lUTTdIaYIOnTS4qpZck+8OcI2D0G92QA==", "cpu": [ - "ppc64" - ], - "libc": [ - "glibc" + "x64" ], - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", - "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", + "node_modules/sass-embedded-linux-arm": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.103.1.tgz", + "integrity": "sha512-tJRLPUtBwXHTnBnG7I39gQvCLreuOHLLCMyKHPR1hQ7aFNwiZjADYzKMRQPNMUqti/Os9z+6I7V13FqgQHfuzg==", "cpu": [ - "riscv64" - ], - "libc": [ - "glibc" + "arm" ], - "license": "LGPL-3.0-or-later", + "libc": "glibc", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", - "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", + "node_modules/sass-embedded-linux-arm64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.103.1.tgz", + "integrity": "sha512-rC+80/Xr9svo0ka2Zr/sjD+N1zEHTw2Urm/nsEjaVp5HSH2i22jwhTKTIqie2OLl6ti+qdYnbI0sSfxOYRtgrg==", "cpu": [ - "s390x" - ], - "libc": [ - "glibc" + "arm64" ], - "license": "LGPL-3.0-or-later", + "libc": "glibc", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", - "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", + "node_modules/sass-embedded-linux-musl-arm": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.103.1.tgz", + "integrity": "sha512-N8L/kgVzXpnH+8d6ErIzqvb0l8kHODR3OfPaf0Azw6DOLGtEjwDRUbHno+G7iogGzyPOjKsM8OdyqHJj/bpTdw==", "cpu": [ - "x64" - ], - "libc": [ - "glibc" + "arm" ], - "license": "LGPL-3.0-or-later", + "libc": "musl", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", - "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", + "node_modules/sass-embedded-linux-musl-arm64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.103.1.tgz", + "integrity": "sha512-jMgG/C/VMo7+ShMFdk0xjJmQmYkj1PbJu/yrQiaQHpuo5pE2G+vnkEgsuM5EM3lTQ4MbMfnf715qy1fkbNPiUQ==", "cpu": [ "arm64" ], - "libc": [ - "musl" - ], - "license": "LGPL-3.0-or-later", + "libc": "musl", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", - "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", + "node_modules/sass-embedded-linux-musl-riscv64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.103.1.tgz", + "integrity": "sha512-LZm8rEvI6sKU87qPOlODsYeAs7CmWy0B4ShYkjG4OMcGCcV4Ffxn25XW4TFqmruThITQvJ8WT+WGblzdoxYgbA==", "cpu": [ - "x64" - ], - "libc": [ - "musl" + "riscv64" ], - "license": "LGPL-3.0-or-later", + "libc": "musl", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-linux-arm": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", - "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", + "node_modules/sass-embedded-linux-musl-x64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.103.1.tgz", + "integrity": "sha512-rmKzgk4t6RpaDhSefbbnk5yrA4pk1nHlVhJECGay8yMfzK8eglATeY9fzPgt89xCuQk6rkOiy11e+m8tLYOW5Q==", "cpu": [ - "arm" - ], - "libc": [ - "glibc" + "x64" ], - "license": "Apache-2.0", + "libc": "musl", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.2" + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-linux-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", - "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", + "node_modules/sass-embedded-linux-riscv64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.103.1.tgz", + "integrity": "sha512-xydQmtxla31uMrmN6z+mAogVGdEMDmkUElVq2+udomX/TPZDYJBkApEyJl237M2VLWVv29v1N4U4i2Z4xa7SDA==", "cpu": [ - "arm64" - ], - "libc": [ - "glibc" + "riscv64" ], - "license": "Apache-2.0", + "libc": "glibc", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.2" + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-linux-ppc64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", - "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", + "node_modules/sass-embedded-linux-x64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.103.1.tgz", + "integrity": "sha512-Rln1oWm0MWKzzemOgQWrRFzfVBARwS9qxAidZPpCQHSohzPnWizFkmY1CUJad/YJNsA7sscueMdX63OEvxoM8w==", "cpu": [ - "ppc64" - ], - "libc": [ - "glibc" + "x64" ], - "license": "Apache-2.0", + "libc": "glibc", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.2" + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-linux-riscv64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", - "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", - "cpu": [ - "riscv64" - ], - "libc": [ - "glibc" - ], - "license": "Apache-2.0", + "node_modules/sass-embedded-unknown-all": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.103.1.tgz", + "integrity": "sha512-p7kI4US8+n+YguKczXh+4KcodJnk+8cwv+QFdvMaz3OfPrdHV0EnhPsaVDWD9qXb1XXCEdUhpp6vQwGk3eKc3A==", + "license": "MIT", "optional": true, "os": [ - "linux" + "!android", + "!darwin", + "!linux", + "!win32" ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.2" + "dependencies": { + "sass": "1.103.1" } }, - "node_modules/sharp/node_modules/@img/sharp-linux-s390x": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", - "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", + "node_modules/sass-embedded-win32-arm64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.103.1.tgz", + "integrity": "sha512-/0renOj3SpZGu4TA8CZJ6qZbTxGZk1khkPfiBTmV1uFB40ESYM5VsdXNj76P07bsAjIj9X2fCjTafLQFLSd9Nw==", "cpu": [ - "s390x" - ], - "libc": [ - "glibc" + "arm64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.2" + "node": ">=14.0.0" } }, - "node_modules/sharp/node_modules/@img/sharp-linux-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", - "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", + "node_modules/sass-embedded-win32-x64": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.103.1.tgz", + "integrity": "sha512-fIg60j9u5YlLUU3W8FvySMR4HHIo9R12HHFQTW7njyQ8nXqgR+t+XfCzGJloQka8g583BlAfu31Q76Ljr5o+9g==", "cpu": [ "x64" ], - "libc": [ - "glibc" - ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=14.0.0" + } + }, + "node_modules/satteri": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.10.5.tgz", + "integrity": "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.5", + "@types/hast": "^3.0.5", + "@types/mdast": "^4.0.4", + "@types/unist": "^3.0.3" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.2" + "@bruits/satteri-darwin-arm64": "0.10.5", + "@bruits/satteri-darwin-x64": "0.10.5", + "@bruits/satteri-linux-arm64-gnu": "0.10.5", + "@bruits/satteri-linux-arm64-musl": "0.10.5", + "@bruits/satteri-linux-x64-gnu": "0.10.5", + "@bruits/satteri-linux-x64-musl": "0.10.5", + "@bruits/satteri-wasm32-wasi": "0.10.5", + "@bruits/satteri-win32-arm64-msvc": "0.10.5", + "@bruits/satteri-win32-x64-msvc": "0.10.5" } }, - "node_modules/sharp/node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", - "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" + "engines": { + "node": ">=v12.22.7" } }, - "node_modules/sharp/node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", - "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], + "node_modules/schema-dts": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.5.tgz", + "integrity": "sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==", "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" + "peer": true + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" }, - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=4" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.2" + "engines": { + "node": ">=10" } }, - "node_modules/sharp/node_modules/@img/sharp-win32-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", - "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, "engines": { - "node": ">=20.9.0" + "node": ">= 18" }, "funding": { - "url": "https://opencollective.com/libvips" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/sharp/node_modules/@img/sharp-win32-ia32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", - "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, "engines": { - "node": "^20.9.0" + "node": ">= 18" }, "funding": { - "url": "https://opencollective.com/libvips" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/sharp/node_modules/@img/sharp-win32-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", - "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/sharp": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.4.tgz", + "integrity": "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==", + "license": "Apache-2.0", "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, "engines": { "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.4", + "@img/sharp-darwin-x64": "0.35.4", + "@img/sharp-freebsd-wasm32": "0.35.4", + "@img/sharp-libvips-darwin-arm64": "1.3.3", + "@img/sharp-libvips-darwin-x64": "1.3.3", + "@img/sharp-libvips-linux-arm": "1.3.3", + "@img/sharp-libvips-linux-arm64": "1.3.3", + "@img/sharp-libvips-linux-ppc64": "1.3.3", + "@img/sharp-libvips-linux-riscv64": "1.3.3", + "@img/sharp-libvips-linux-s390x": "1.3.3", + "@img/sharp-libvips-linux-x64": "1.3.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3", + "@img/sharp-libvips-linuxmusl-x64": "1.3.3", + "@img/sharp-linux-arm": "0.35.4", + "@img/sharp-linux-arm64": "0.35.4", + "@img/sharp-linux-ppc64": "0.35.4", + "@img/sharp-linux-riscv64": "0.35.4", + "@img/sharp-linux-s390x": "0.35.4", + "@img/sharp-linux-x64": "0.35.4", + "@img/sharp-linuxmusl-arm64": "0.35.4", + "@img/sharp-linuxmusl-x64": "0.35.4", + "@img/sharp-webcontainers-wasm32": "0.35.4", + "@img/sharp-win32-arm64": "0.35.4", + "@img/sharp-win32-ia32": "0.35.4", + "@img/sharp-win32-x64": "0.35.4" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/shebang-command": { @@ -10450,15 +8904,6 @@ "url": "https://github.com/sponsors/cyyynthia" } }, - "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">= 12" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -10562,24 +9007,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/style-to-js": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", - "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", - "license": "MIT", - "dependencies": { - "style-to-object": "1.0.14" - } - }, - "node_modules/style-to-object": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", - "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", - "license": "MIT", - "dependencies": { - "inline-style-parser": "0.2.7" - } - }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -10663,9 +9090,9 @@ "license": "MIT" }, "node_modules/tinyclip": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.15.tgz", - "integrity": "sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-1.0.3.tgz", + "integrity": "sha512-nTv2raKFMzGG6JJp0lpNDsRPdfFE6UHlu2rVEjXo8vkx1ZS3LW2CVXqIaLu8xZlu+6tbFs9V58Qc/Jmk/Ii7wA==", "license": "MIT", "engines": { "node": "^16.14.0 || >= 17.3.0" @@ -10917,20 +9344,6 @@ "node": ">=22.19.0" } }, - "node_modules/unist-util-find-after": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", - "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/unist-util-is": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", @@ -10944,20 +9357,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-modify-children": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", - "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "array-iterate": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/unist-util-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", @@ -10971,33 +9370,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-position-from-estree": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", - "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-remove-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", - "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", @@ -11026,19 +9398,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-visit-children": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", - "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/unist-util-visit-parents": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", @@ -11173,28 +9532,26 @@ "node": ">= 0.8" } }, - "node_modules/vfile": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "node_modules/verkit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.4.1.tgz", + "integrity": "sha512-mMVzj0TXExtVdlDEq+Mzp0eyOuyznNpFobNM3uAqe3HVm/Ps2c+u17BligMkZjZCA6EiXpoon8iRTer3iu40SQ==", "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" + "engines": { + "node": ">=18.12.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/vfile-location": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", - "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", - "vfile": "^6.0.0" + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", @@ -11337,16 +9694,6 @@ "node": ">=18" } }, - "node_modules/web-namespaces": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/webidl-conversions": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", @@ -11476,9 +9823,9 @@ } }, "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", + "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index 2762e6a0a2..fb8968f53f 100644 --- a/package.json +++ b/package.json @@ -147,25 +147,24 @@ "check-html-links:report": "node scripts/check-html-links.mjs --md=reports/html-links-report.md" }, "dependencies": { - "@astrojs/markdown-satteri": "^0.3.5", + "@astrojs/markdown-satteri": "^0.4.2", "astro-seo-schema": "^7.0.0", "gray-matter": "^4.0.3", - "igniteui-astro-components": "1.0.2", + "igniteui-astro-components": "1.3.0", "igniteui-theming": "^26.0.1", "igniteui-webcomponents": "^7.3.0-beta.1", "js-yaml": "^4.1.1", "jsdom": "^29.0.1", "pagefind": "^1.5.2", - "satteri": "^0.9.5", - "sharp": "0.35.3", + "satteri": "^0.10.5", "turndown": "^7.2.4", "turndown-plugin-gfm": "^1.0.2" }, "devDependencies": { - "@astrojs/mdx": "^7.0.5", - "@astrojs/ts-plugin": "^1.10.7", + "@astrojs/mdx": "^8.0.2", + "@astrojs/ts-plugin": "^1.10.12", "@types/jsdom": "^28.0.1", - "astro": "^7.2.2", + "astro": "^7.3.4", "cross-env": "^10.1.0", "cspell": "^9.2.2", "markdownlint-cli": "^0.49.1", diff --git a/scripts/check-relative-links.mjs b/scripts/check-relative-links.mjs index a2ca373826..de2f48ea02 100644 --- a/scripts/check-relative-links.mjs +++ b/scripts/check-relative-links.mjs @@ -9,6 +9,11 @@ * whether the target exists (trying .mdx, .md, and bare extensions). * JSX-style href attributes with relative paths are also checked. * + * The hrefs in each toc.json are checked in the same pass. They are file paths + * rather than URLs, but they break the same way a link does — and buildSidebar() + * drops an entry whose target is missing instead of failing, so a stale one + * disappears from the sidebar with no error. + * * When --platform=angular the script scans docs/angular/src/content. * When --platform=react|wc|blazor it scans docs/xplat/src/content. * Omitting --platform scans both trees in one pass. @@ -25,7 +30,7 @@ * Exit code: 0 = all OK, 1 = broken links found. */ -import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; +import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs'; import { dirname, join, relative, resolve } from 'node:path'; // join used in walkMdx // CLI args @@ -189,6 +194,40 @@ const MD_LINK_RE = /\[(?:[^\]\\]|\\.)*\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g; */ const JSX_HREF_RE = /href=["'](\.[^"'\s>]+)["']/g; +/** + * True when `path` is an existing *file*. + * + * Every doc page is a file, so a bare directory must never satisfy a link on + * its own: a group folder such as components/inputs/ exists on disk but + * publishes no page, and /inputs 404s. + */ +function isFile(path) { + try { + return statSync(path).isFile(); + } catch { + return false; + } +} + +/** + * Every on-disk file that can publish at the URL `base` maps to. + * + * Astro derives the id from the file path and strips a trailing `/index` + * (see getContentEntryIdAndSlug in astro/dist/content/utils.js), so + * components/themes/sass/index.mdx publishes at /themes/sass — a directory + * therefore does satisfy a link, but only when it holds an index page. + * `base` itself is included for links that already carry an extension. + */ +function pageCandidates(base) { + return [ + base, + base + '.mdx', + base + '.md', + join(base, 'index.mdx'), + join(base, 'index.md'), + ]; +} + /** Strip hash fragment (#anchor) from a URL path. */ function stripHash(url) { const i = url.indexOf('#'); @@ -205,6 +244,17 @@ const ASSET_EXTENSIONS = new Set([ '.html', '.htm', ]); +/** + * Asset extensions that disqualify an *absolute* link from being a doc link. + * + * .html/.htm are deliberately excluded from this set: legacy docfx URLs were + * written as /themes/palettes.html, and treating them as assets made them + * invisible to this check instead of reporting them as broken. + */ +const ABSOLUTE_LINK_ASSET_EXTENSIONS = new Set( + [...ASSET_EXTENSIONS].filter(ext => ext !== '.html' && ext !== '.htm') +); + /** * True when a URL is an absolute doc-internal link, e.g. /treegrid/tree-grid. * Rejects external URLs, anchors-only, protocol-relative, and asset extensions. @@ -218,7 +268,7 @@ function isAbsoluteDocLink(url) { const slash = path.lastIndexOf('/'); if (dot > slash) { const ext = path.slice(dot).toLowerCase(); - if (ASSET_EXTENSIONS.has(ext)) return false; + if (ABSOLUTE_LINK_ASSET_EXTENSIONS.has(ext)) return false; } return true; } @@ -234,27 +284,94 @@ function getLangRoot(filePath) { } /** - * Resolves an absolute doc link like /treegrid/tree-grid against the - * language content root. Tries components/{path}.mdx then {path}.mdx. - * Returns the resolved path string or null if not found. + * Paths that docs/angular/scripts/sync-generated.mjs refuses to copy into the + * Angular tree: grids/ and changelog/, because Angular ships its own versions. + * Pages under them exist in docs/xplat/generated/Angular but never reach the + * Angular site, so they must not satisfy an Angular link. + * + * Keep in step with shouldCopy() in docs/angular/scripts/sync-generated.mjs. + */ +const NOT_SYNCED_TO_ANGULAR_RE = /(^|\/)(grids|changelog)\//i; + +/** True when `relPath` (relative to components/) is synced into the Angular tree. */ +function isSyncedToAngular(relPath) { + return !NOT_SYNCED_TO_ANGULAR_RE.test(relPath); +} + +/** + * Content roots that feed the same published URL space as `langRoot`. + * + * New topics — Angular-only ones included — are authored under docs/xplat and + * copied into the Angular tree at build time by + * docs/angular/scripts/sync-generated.mjs. A link in docs/angular/src/content + * may therefore legitimately target a page that exists only under + * docs/xplat/generated/Angular/<lang>/, so resolution has to consider both + * roots. Without the second root, every link to an xplat-authored Angular topic + * reports a false "not found" whenever the sync step has not run. + * + * Returns an ordered list of { dir, accepts } (own tree first). `accepts` takes + * a path relative to components/ and reports whether that root can serve it, so + * a root only satisfies links to pages it actually publishes. + */ +const docRootsCache = new Map(); + +function getDocRoots(langRoot) { + const cached = docRootsCache.get(langRoot); + if (cached) return cached; + + const roots = [{ dir: langRoot, accepts: () => true }]; + const m = langRoot.replace(/\\/g, '/').match(/docs\/angular\/src\/content\/(en|jp|kr)\/$/i); + if (m) { + const generated = resolve(process.cwd(), 'docs/xplat/generated/Angular', m[1]) + '/'; + if (existsSync(generated)) roots.push({ dir: generated, accepts: isSyncedToAngular }); + } + + docRootsCache.set(langRoot, roots); + return roots; +} + +/** Legacy docfx extension on a doc URL, e.g. /themes/palettes.html */ +const LEGACY_HTML_RE = /\.html?$/i; + +/** + * Resolves an absolute doc link like /treegrid/tree-grid against every content + * root feeding this URL space. Returns { resolved, reason }; resolved is null + * when the target does not exist. */ function resolveAbsoluteLink(langRoot, url) { - const path = stripHash(url).slice(1); // strip leading '/' - if (!path) return 'hash-only'; + let path = stripHash(url).slice(1); // strip leading '/' + if (!path) return { resolved: 'hash-only', reason: null }; + // Astro lowercases all URL slugs at build time. Always resolve using the // lowercased path so that camelCase links like /pivotGrid/... are flagged // as broken (the built URL is /pivotgrid/...). - const pathLower = path.toLowerCase(); - const candidates = [ - resolve(langRoot, 'components', pathLower), - resolve(langRoot, pathLower), - ]; - for (const base of candidates) { - if (existsSync(base)) return base; - if (existsSync(base + '.mdx')) return base + '.mdx'; - if (existsSync(base + '.md')) return base + '.md'; + path = path.toLowerCase(); + + // The docs collection is rooted at content/<lang>/components (see + // docs/*/src/content.config.ts), so "components" is never a URL segment. + // A link starting with it is the on-disk file path written as a URL: it + // resolves to a real file yet 404s in the browser, which is what let + // https://github.com/IgniteUI/igniteui-documentation/issues/530 through. + if (path === 'components' || path.startsWith('components/')) { + return { resolved: null, reason: 'components-prefix' }; } - return null; + + // Legacy docfx URLs carried a .html suffix; Astro routes do not. + const legacyHtml = LEGACY_HTML_RE.test(path); + if (legacyHtml) path = path.replace(LEGACY_HTML_RE, ''); + + for (const { dir, accepts } of getDocRoots(langRoot)) { + if (!accepts(path)) continue; + + const base = resolve(dir, 'components', path); + for (const candidate of pageCandidates(base)) { + if (isFile(candidate)) { + return { resolved: candidate, reason: legacyHtml ? 'legacy-html' : null }; + } + } + } + + return { resolved: null, reason: legacyHtml ? 'legacy-html' : 'not-found' }; } /** @@ -336,27 +453,58 @@ function extractRelativeLinks(content, filePath) { // File resolution +/** + * Maps `abs` — a path inside the components dir of `langRoot` — onto the + * equivalent path under each additional content root feeding the same URL + * space. Returns [] when langRoot is unknown, has no extra roots, or the + * target sits outside the components dir (images and other assets). + */ +function siblingRootPaths(langRoot, abs) { + if (!langRoot) return []; + + const roots = getDocRoots(langRoot); + if (roots.length < 2) return []; + + const rel = relative(resolve(langRoot, 'components'), abs).replace(/\\/g, '/'); + if (!rel || rel.startsWith('../')) return []; + + return roots + .slice(1) + .filter(({ accepts }) => accepts(rel)) + .map(({ dir }) => resolve(dir, 'components', rel)); +} + /** * Returns { resolved, missingExt } for `href` relative to `fileDir`. - * resolved = null means the target does not exist on disk. + * resolved = null means the target does not exist in any content root. * missingExt = true means the path has no extension but resolves via .mdx — * the link should be written as ./page.mdx, not ./page. + * + * Candidates cover the tree the file lives in first, then the equivalent path + * under the other roots feeding this URL space, so a relative link to an + * xplat-authored Angular topic resolves before the sync step has run. */ -function resolveLink(fileDir, href) { +function resolveLink(fileDir, href, langRoot) { const path = stripHash(href); if (!path) return { resolved: 'hash-only', missingExt: false }; const abs = resolve(fileDir, path); + const candidates = [abs, ...siblingRootPaths(langRoot, abs)]; + + for (const candidate of candidates) { + if (isFile(candidate)) return { resolved: candidate, missingExt: false }; + } - if (existsSync(abs)) return { resolved: abs, missingExt: false }; + for (const candidate of candidates) { + const target = pageCandidates(candidate).find(isFile); + if (!target) continue; - if (existsSync(abs + '.mdx')) { const lastDot = path.lastIndexOf('.'); const lastSlash = path.lastIndexOf('/'); const hasExt = lastDot > lastSlash; const isBare = !path.startsWith('./') && !path.startsWith('../'); const missingExt = !hasExt || isBare; - return { resolved: abs + '.mdx', missingExt, bare: isBare }; + return { resolved: target, missingExt, bare: isBare }; } return { resolved: null, missingExt: false }; @@ -379,6 +527,23 @@ console.log(`Scope: ${scanDescription}`); if (PLATFORM) console.log(`Platform: ${PLATFORM}`); console.log(''); +// The Angular URL space is fed by two trees: docs/angular/src/content plus the +// xplat-authored Angular pages under docs/xplat/generated/Angular, which the +// build copies in via docs/angular/scripts/sync-generated.mjs. New topics are +// authored in xplat, so without that tree present links to them would report a +// false "not found". +if (PLATFORM === 'angular' || (!PLATFORM && !args.src)) { + for (const lang of ['en', 'jp']) { + if (existsSync(resolve(cwd, 'docs/xplat/generated/Angular', lang))) continue; + + const script = lang === 'en' ? 'generate:angular' : 'generate:angular:jp'; + console.log(` ! docs/xplat/generated/Angular/${lang} is missing — links to xplat-authored`); + console.log(` Angular topics may report a false "not found". Run:`); + console.log(` npm run ${script} --prefix docs/xplat`); + console.log(''); + } +} + /** @type {Array<{file: string, line: number, href: string}>} */ const brokenLinks = []; let totalFiles = 0; @@ -397,14 +562,16 @@ for (const file of filesToScan) { for (const { href, line, kind } of links) { if (kind === 'absolute') { if (langRoot) { - const resolved = resolveAbsoluteLink(langRoot, href); - if (resolved === null) { - brokenLinks.push({ file: relFile, line, href, reason: 'not-found' }); + const { resolved, reason } = resolveAbsoluteLink(langRoot, href); + // A legacy .html suffix 404s on the Astro routes even when the + // target page itself exists, so report it either way. + if (resolved === null || reason === 'legacy-html') { + brokenLinks.push({ file: relFile, line, href, reason }); } } continue; } - const { resolved, missingExt, bare } = resolveLink(fileDir, href); + const { resolved, missingExt, bare } = resolveLink(fileDir, href, langRoot); if (resolved === null) { brokenLinks.push({ file: relFile, line, href, reason: 'not-found' }); } else if (bare) { @@ -421,13 +588,156 @@ for (const file of filesToScan) { const href = m[1]; const hash = m[2] ?? ''; const abs = resolve(fileDir, href); - if (existsSync(abs + '.mdx')) { + const resolvesToPage = [abs, ...siblingRootPaths(langRoot, abs)] + .some(candidate => existsSync(candidate + '.mdx')); + if (resolvesToPage) { const line = (content.slice(0, m.index).match(/\n/g) || []).length + 1; brokenLinks.push({ file: relFile, line, href: href + hash, reason: 'bare-path' }); } } } +// toc.json navigation + +/** + * toc.json hrefs are the sidebar's only source of navigation, and they are file + * paths relative to the components dir carrying the .mdx extension — not URLs. + * + * They need checking for the same reason the links above do, and are easy to get + * wrong in the same way: a topic move changes both, and buildSidebar() drops an + * entry whose target is missing (docExists() → null in src/sidebar.ts) rather + * than failing, so a stale href disappears from the sidebar with no error. + * + * Resolution reuses getDocRoots(), so an Angular toc entry may point at a page + * that only exists under docs/xplat/generated/Angular/<lang>/ until the sync runs. + */ + +/** Ordered { value, line } for every "href" in a toc, read from the raw text. */ +function tocHrefLines(text) { + const lines = []; + const re = /"href"\s*:\s*"((?:[^"\\]|\\.)*)"/g; + let m; + while ((m = re.exec(text)) !== null) { + lines.push({ + value: m[1], + line: (text.slice(0, m.index).match(/\n/g) || []).length + 1, + }); + } + return lines; +} + +/** + * Yields every toc entry carrying an href, in document order, with the chain of + * entry names and the platforms it is excluded for. + * + * buildFilteredToc() in docs/xplat/astro.config.ts drops an excluded node along + * with its children, so exclusions accumulate down the tree. Excluded entries + * are still yielded (flagged) to keep the ordering aligned with tocHrefLines(). + */ +function* walkTocEntries(entries, trail = [], excluded = [], counter = { n: 0 }) { + if (!Array.isArray(entries)) return; + + for (const entry of entries) { + if (!entry || typeof entry !== 'object') continue; + + const path = [...trail, entry.name ?? '(unnamed)']; + const excl = Array.isArray(entry.exclude) ? [...excluded, ...entry.exclude] : excluded; + + if (typeof entry.href === 'string' && entry.href) { + yield { href: entry.href, trail: path, excluded: excl, index: counter.n++ }; + } + if (Array.isArray(entry.items)) { + yield* walkTocEntries(entry.items, path, excl, counter); + } + } +} + +/** + * True when a toc href resolves under any of `roots`. + * + * docExists() accepts the href as written and also swaps .md ↔ .mdx, so both + * count here. + */ +function tocHrefResolves(roots, href) { + const normalized = href.replace(/\\/g, '/'); + const swapped = normalized.endsWith('.mdx') ? normalized.slice(0, -4) + '.md' + : normalized.endsWith('.md') ? normalized.slice(0, -3) + '.mdx' + : null; + + for (const { dir, accepts } of roots) { + if (!accepts(normalized)) continue; + if (isFile(resolve(dir, 'components', normalized))) return true; + if (swapped && isFile(resolve(dir, 'components', swapped))) return true; + } + return false; +} + +/** + * The tocs in scope, as { toc, roots, platform }. + * + * Angular ships its own toc per language and resolves through getDocRoots(), so + * it picks up the xplat-authored pages the sync copies in. The xplat platforms + * share one source toc that astro.config.ts filters per platform at build time, + * so the same filter is applied here against each generated tree. + */ +function getTocTargets() { + const targets = []; + + if (!PLATFORM || PLATFORM === 'angular') { + for (const lang of ['en', 'jp']) { + const langRoot = resolve(cwd, 'docs/angular/src/content', lang) + '/'; + const toc = resolve(langRoot, 'components', 'toc.json'); + if (existsSync(toc)) targets.push({ toc, roots: getDocRoots(langRoot), platform: null }); + } + } + + if (!PLATFORM || PLATFORM === 'xplat' || XPLAT_PLATFORMS.has(PLATFORM)) { + for (const platform of ['React', 'WebComponents', 'Blazor']) { + for (const lang of ['en', 'jp']) { + const toc = resolve(cwd, 'docs/xplat/src/content', lang, 'toc.json'); + const dir = resolve(cwd, 'docs/xplat/generated', platform, lang) + '/'; + if (!existsSync(toc) || !existsSync(dir)) continue; + + targets.push({ toc, roots: [{ dir, accepts: () => true }], platform }); + } + } + } + + return targets; +} + +let totalTocHrefs = 0; + +for (const { toc, roots, platform } of getTocTargets()) { + const text = readFileSync(toc, 'utf-8'); + const relToc = relative(cwd, toc).replace(/\\/g, '/'); + + let entries; + try { + entries = JSON.parse(text); + } catch (error) { + brokenLinks.push({ file: relToc, line: 1, href: '(whole file)', reason: `unparseable JSON: ${error.message}` }); + continue; + } + + const hrefLines = tocHrefLines(text); + + for (const { href, trail, excluded, index } of walkTocEntries(entries)) { + if (platform && excluded.includes(platform)) continue; + + totalTocHrefs++; + if (tocHrefResolves(roots, href)) continue; + + brokenLinks.push({ + file: relToc, + line: hrefLines[index]?.value === href ? hrefLines[index].line : 1, + href, + reason: 'toc-not-found', + entry: platform ? `${platform}: ${trail.join(' → ')}` : trail.join(' → '), + }); + } +} + // Reporting const HR = '═'.repeat(72); @@ -437,7 +747,7 @@ const HR2 = '─'.repeat(72); if (SUMMARY) { const label = PLATFORM ?? 'all'; const status = brokenLinks.length === 0 ? '✅' : '❌'; - console.log(` ${status} ${label.padEnd(10)} Broken links: ${brokenLinks.length} (${totalFiles} files, ${totalLinks} links)`); + console.log(` ${status} ${label.padEnd(10)} Broken links: ${brokenLinks.length} (${totalFiles} files, ${totalLinks} links, ${totalTocHrefs} toc hrefs)`); process.exit(brokenLinks.length > 0 ? 1 : 0); } @@ -445,27 +755,33 @@ if (SUMMARY) { if (SUMMARY) { const label = PLATFORM ?? 'all'; const status = brokenLinks.length === 0 ? '✅' : '❌'; - console.log(` ${status} ${label.padEnd(10)} Broken links: ${brokenLinks.length} (${totalFiles} files, ${totalLinks} links)`); + console.log(` ${status} ${label.padEnd(10)} Broken links: ${brokenLinks.length} (${totalFiles} files, ${totalLinks} links, ${totalTocHrefs} toc hrefs)`); process.exit(brokenLinks.length > 0 ? 1 : 0); } console.log(` MDX/MD files scanned : ${totalFiles}`); console.log(` Relative links found : ${totalLinks}`); -console.log(` Broken links : ${brokenLinks.length}\n`); +console.log(` TOC hrefs found : ${totalTocHrefs}`); +console.log(` Broken : ${brokenLinks.length}\n`); console.log(HR); -console.log(' RELATIVE LINK CHECK REPORT (MDX source)'); +console.log(' RELATIVE LINK CHECK REPORT (MDX source + toc.json)'); console.log(HR); if (brokenLinks.length === 0) { - console.log('\n All relative links resolve to existing files.\n'); + console.log('\n All links and toc entries resolve to pages that ship.\n'); } else { for (const item of brokenLinks) { - const tag = item.reason === 'bare-path' ? '[use ./page.mdx instead]' - : item.reason === 'missing-mdx' ? '[add .mdx extension]' + const tag = item.reason === 'bare-path' ? '[use ./page.mdx instead]' + : item.reason === 'missing-mdx' ? '[add .mdx extension]' + : item.reason === 'components-prefix' ? '[drop the /components prefix]' + : item.reason === 'legacy-html' ? '[drop the .html extension]' + : item.reason === 'toc-not-found' ? '[toc target missing — entry is dropped from the sidebar]' + : item.reason.startsWith('unparseable') ? `[${item.reason}]` : '[not found]'; console.log(`\n ✗ ${item.file}:${item.line} ${tag}`); console.log(` href: ${item.href}`); + if (item.entry) console.log(` entry: ${item.entry}`); } console.log(''); } @@ -487,7 +803,8 @@ if (MD_OUTPUT) { lines.push('|---|---|'); lines.push(`| Files scanned | ${totalFiles} |`); lines.push(`| Relative links | ${totalLinks} |`); - lines.push(`| ✅ OK | ${totalLinks - brokenLinks.length} |`); + lines.push(`| TOC hrefs | ${totalTocHrefs} |`); + lines.push(`| ✅ OK | ${totalLinks + totalTocHrefs - brokenLinks.length} |`); lines.push(`| ❌ **Broken** | **${brokenLinks.length}** |`); lines.push(''); @@ -497,10 +814,15 @@ if (MD_OUTPUT) { lines.push('| File | Line | href | Issue |'); lines.push('|---|---:|---|---|'); for (const item of brokenLinks) { - const issue = item.reason === 'bare-path' ? 'use ./page.mdx instead' - : item.reason === 'missing-mdx' ? 'add .mdx extension' + const issue = item.reason === 'bare-path' ? 'use ./page.mdx instead' + : item.reason === 'missing-mdx' ? 'add .mdx extension' + : item.reason === 'components-prefix' ? 'drop the /components prefix' + : item.reason === 'legacy-html' ? 'drop the .html extension' + : item.reason === 'toc-not-found' ? 'toc target missing — entry is dropped from the sidebar' + : item.reason.startsWith('unparseable') ? item.reason : 'not found'; - lines.push(`| \`${item.file}\` | ${item.line} | \`${item.href}\` | ${issue} |`); + const where = item.entry ? ` (${item.entry})` : ''; + lines.push(`| \`${item.file}\` | ${item.line} | \`${item.href}\`${where} | ${issue} |`); } lines.push(''); } diff --git a/src/content.config.ts b/src/content.config.ts index 1fc7dcdd96..bf19164b3c 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -12,7 +12,6 @@ export const collections = { 'grids_templates/**', 'style-guide.mdx', 'themes/sass/presets/**', - 'themes.mdx', ], extendSchema: z.object({ tableOfContents: z diff --git a/src/sidebar.ts b/src/sidebar.ts index 23e042bab6..da5e9fdabc 100644 --- a/src/sidebar.ts +++ b/src/sidebar.ts @@ -142,6 +142,48 @@ function convertTocItem( return null; } +interface MissingTocTarget { + name: string; + href: string; +} + +/** + * Every named TOC entry whose href points at a file that does not exist + * exactly the entries `convertTocItem()` silently drops. Hrefs matched by + * `exclude` are dropped on purpose, so they are not reported. + */ +function findMissingTargets( + docsDir: string, + items: TocItem[], + exclude: RegExp[], + missing: MissingTocTarget[] = [], +): MissingTocTarget[] { + for (const item of items) { + if (!item.name) continue; + if (item.href && !exclude.some((p) => p.test(item.href!)) && !docExists(docsDir, item.href, exclude)) { + missing.push({ name: item.name, href: item.href }); + } + if (item.items?.length) findMissingTargets(docsDir, item.items, exclude, missing); + } + return missing; +} + +/** + * Warns about TOC entries left out of the sidebar because their target file is + * missing, or throws when `strict` is set so CI fails instead of shipping a + * sidebar with silently vanished links. + */ +function reportMissingTargets(tocPath: string, missing: MissingTocTarget[], strict: boolean): void { + if (!missing.length) return; + const noun = missing.length === 1 ? 'entry points' : 'entries point'; + const message = + `[igniteui-documentation] ${tocPath}: ${missing.length} toc ${noun} to a missing file and ` + + `${missing.length === 1 ? 'was' : 'were'} left out of the sidebar:\n` + + missing.map(({ name, href }) => ` - ${name} → ${href}`).join('\n'); + if (strict) throw new Error(message); + console.warn(message); +} + // --------------------------------------------------------------------------- // Public API // --------------------------------------------------------------------------- @@ -153,16 +195,28 @@ export interface BuildSidebarFromTocOptions { docsDir: string; /** Extra patterns to exclude (matched against the `href`). */ exclude?: RegExp[]; + /** + * Throw instead of warning when a TOC entry points at a missing file. + * Defaults to `DOCS_TOC_STRICT=true`, which CI sets. + */ + strict?: boolean; } /** * Reads a JSON TOC file and converts it to a sidebar array. */ -export function buildSidebarFromToc({ tocPath, docsDir, exclude = [] }: BuildSidebarFromTocOptions): SidebarEntry[] { +export function buildSidebarFromToc({ + tocPath, + docsDir, + exclude = [], + strict = process.env.DOCS_TOC_STRICT === 'true', +}: BuildSidebarFromTocOptions): SidebarEntry[] { if (!tocPath || !fs.existsSync(tocPath)) return []; const tocRaw = fs.readFileSync(tocPath, 'utf-8'); const tocItems: TocItem[] = JSON.parse(tocRaw); + reportMissingTargets(tocPath, findMissingTargets(docsDir, tocItems, exclude), strict); + const sidebar: SidebarEntry[] = []; let currentGroup: SidebarGroup | null = null; let currentGroupSortable = false;