diff --git a/.github/ISSUE_TEMPLATE/01_bug_report.yml b/.github/ISSUE_TEMPLATE/01_bug_report.yml new file mode 100644 index 000000000000..084c8de62fc9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01_bug_report.yml @@ -0,0 +1,77 @@ +name: Bug Report +description: Tell us about a problem you found +labels: [] +body: + - type: markdown + attributes: + value: | + Report **a problem** in MudBlazor. For questions, use [Discussions](https://github.com/MudBlazor/MudBlazor/discussions) or [Discord](https://discord.gg/mudblazor). + - type: checkboxes + id: preconditions + attributes: + label: Before reporting + options: + - label: I searched existing issues + required: true + - label: I tried in private/incognito browser + required: true + - type: textarea + id: what-happened + attributes: + label: What went wrong? + description: Describe the issue with code snippets, screenshots, or links. + validations: + required: true + - type: input + id: repro-link + attributes: + label: Reproduction link + description: Share a live example on [try.mudblazor.com](https://try.mudblazor.com). + placeholder: https://try.mudblazor.com/snippet/... + validations: + required: true + - type: textarea + id: repro-steps + attributes: + label: Reproduction steps + value: | + 1. + 2. + 3. + validations: + required: true + - type: input + id: bug-version + attributes: + label: Version (bug) + description: Which version has the issue? + placeholder: v8.x.x + validations: + required: true + - type: input + id: working-version + attributes: + label: Version (working) + description: Last working version? + placeholder: v7.x.x + - type: dropdown + id: environments + attributes: + label: Environment + multiple: true + options: + - Chrome + - Edge + - Firefox + - Safari + - iOS/Android + - Other + - type: dropdown + id: rendering-mode + attributes: + label: Blazor rendering mode + multiple: true + options: + - WASM + - Server + - Hybrid \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/02_feature_request.yml b/.github/ISSUE_TEMPLATE/02_feature_request.yml new file mode 100644 index 000000000000..435d48e105ea --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02_feature_request.yml @@ -0,0 +1,20 @@ +name: Feature Request +description: Suggest an idea or improvement +labels: [] +body: + - type: markdown + attributes: + value: | + Suggest **new features** for MudBlazor. For questions, use [Discussions](https://github.com/MudBlazor/MudBlazor/discussions) or [Discord](https://discord.gg/mudblazor). + - type: textarea + id: expected-behavior + attributes: + label: Describe your idea + description: Explain the problem this feature would solve and how it should work. + validations: + required: true + - type: textarea + id: examples + attributes: + label: Alternatives and examples + description: Other solutions you tried, or links/screenshots of similar features. diff --git a/.github/ISSUE_TEMPLATE/03_documentation.md b/.github/ISSUE_TEMPLATE/03_documentation.md new file mode 100644 index 000000000000..0e43e9c977c1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/03_documentation.md @@ -0,0 +1,22 @@ +--- +name: Documentation issue +about: Report an issue or suggest improvements for MudBlazor.com +title: '' +labels: 'docs' +assignees: '' + +--- + +### Issue type + +- [ ] Missing or incomplete documentation +- [ ] Incorrect information or broken code example +- [ ] Suggestion for improvement + +### Page or section affected + + + +### Description + + diff --git a/.github/ISSUE_TEMPLATE/04_performance_issue.md b/.github/ISSUE_TEMPLATE/04_performance_issue.md new file mode 100644 index 000000000000..ecafbebdf1f6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/04_performance_issue.md @@ -0,0 +1,29 @@ +--- +name: Performance issue +about: Report a performance problem or regression +title: '' +labels: 'performance' +assignees: '' + +--- + +### Description + + + +### Configuration + + + +### Data + + + +### Analysis + + diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 056721081dbf..000000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,140 +0,0 @@ -name: Bug Report -description: File a bug report -labels: [triage] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report for [MudBlazor](https://mudblazor.com). Note: this template is only for bug reports; Please use [GitHub Discussions](https://github.com/MudBlazor/MudBlazor/discussions) or [Discord](https://discord.gg/mudblazor) for any questions. - - type: checkboxes - id: preconditions - attributes: - label: Things to check - options: - - label: I have searched the **existing issues** for this bug - required: true - - label: To rule out a caching problem I made sure the bug also happens in an **incognito tab** - required: true - validations: - required: true - - type: dropdown - id: bug-type - attributes: - label: Bug type - multiple: true - options: - - Component - - Docs (mudblazor.com) - - Other - validations: - required: true - - type: input - id: component-name - attributes: - label: Component name - description: If this issue is about a component, please provide the name. - placeholder: MudComponent - - type: textarea - id: what-happened - attributes: - label: What happened? - description: Please describe the issue briefly. You can use code-snippets, screenshots, or videos to further explain your problem. Please post code-snippets surrounded in backticks and not as screenshots. - placeholder: Describe your issue! - validations: - required: true - - type: textarea - id: expected-behavior - attributes: - label: Expected behavior - description: Please provide a clear and concise description of what you expected to happen. - placeholder: Describe the expected behavior! - validations: - required: true - - type: input - id: repro-link - attributes: - label: Reproduction link - description: Please reproduce the issue on [try.mudblazor.com](https://try.mudblazor.com) if possible. Otherwise provide a link to a GitHub repository with a minimal reproduction (no complete applications). - placeholder: https://try.mudblazor.com/snippet/XXXXXXXXXXXXXXXX - validations: - required: true - - type: textarea - id: repro-steps - attributes: - label: Reproduction steps - description: How do you trigger this bug? Please walk us through it step by step. - value: | - 1. - 2. - 3. - ... - validations: - required: true - - type: textarea - id: logs - attributes: - label: Relevant log output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - render: shell - - type: input - id: bug-version - attributes: - label: Version (bug) - description: With which version are you experiencing the issue? - placeholder: 8.x.x - validations: - required: true - - type: input - id: working-version - attributes: - label: Version (working) - description: Did it work on a previous version? If so, which version? - placeholder: 7.x.x - - type: dropdown - id: browsers - attributes: - label: What browsers are you seeing the problem on? - description: You don't have to test it on every browser. - multiple: true - options: - - Firefox - - Chrome - - Edge - - Safari - - Other - validations: - required: true - - type: dropdown - id: os - attributes: - label: On which operating systems are you experiencing the issue? - description: You don't have to test it on every OS. - multiple: true - options: - - Windows - - macOS - - Linux - - iOS - - Android - - Other - validations: - required: true - - type: dropdown - id: rendering-mode - attributes: - label: Blazor rendering mode - description: Specify the Blazor rendering mode you are using. - multiple: false - options: - - WASM - - Server - - Hybrid - default: 0 - - type: checkboxes - id: terms - attributes: - label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/MudBlazor/MudBlazor/blob/dev/CODE_OF_CONDUCT.md). - options: - - label: I agree to follow this project's Code of Conduct - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 4e7138643dd7..fc83b18462e9 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,7 +2,7 @@ blank_issues_enabled: false contact_links: - name: GitHub Discussions url: https://github.com/MudBlazor/MudBlazor/discussions - about: Please ask and answer questions here + about: Discuss this on GitHub - name: Discord url: https://discord.gg/mudblazor - about: You can also ask and answer questions here \ No newline at end of file + about: Chat with us on Discord \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index ac7f2179322d..000000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Feature Request -description: Suggest an idea for this project -labels: [triage, enhancement] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this feature request for [MudBlazor](https://mudblazor.com). Note: this template is only for feature requests. Please use [Github Discussions](https://github.com/MudBlazor/MudBlazor/discussions) or [Discord](https://discord.gg/mudblazor) for any questions. - - type: dropdown - id: enhancement-type - attributes: - label: Feature request type - options: - - Enhance component - - New component - - Performance improvement - - Other - validations: - required: true - - type: input - id: component-name - attributes: - label: Component name - description: If this feature request is about a component, please provide the name. - placeholder: MudComponent - - type: textarea - id: related-problem - attributes: - label: Is your feature request related to a problem? - description: Please provide a clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - placeholder: Describe your problem! - - type: textarea - id: expected-behavior - attributes: - label: Describe the solution you'd like - description: Please provide a clear and concise description of what you want to happen. - placeholder: Describe your request! - validations: - required: true - - type: textarea - id: examples - attributes: - label: Have you seen this feature anywhere else? - description: Please provide links to the Material Design guidelines, other implementations, or screenshots or videos of the expected behavior if possible. - placeholder: Show us examples! - - type: textarea - id: alternatives - attributes: - label: Describe alternatives you've considered - description: Please provide a clear and concise description of any alternative solutions or features you've considered. - placeholder: Describe alternatives! - - type: checkboxes - id: terms - attributes: - label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/MudBlazor/MudBlazor/blob/dev/CODE_OF_CONDUCT.md). - options: - - label: I agree to follow this project's Code of Conduct - required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.MD b/.github/PULL_REQUEST_TEMPLATE.MD index 5bee31908ec4..fadf8235c464 100644 --- a/.github/PULL_REQUEST_TEMPLATE.MD +++ b/.github/PULL_REQUEST_TEMPLATE.MD @@ -1,36 +1,15 @@ + - - - -## Description - - - - -## How Has This Been Tested? - - - - - -## Type of Changes - -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] Documentation (fix or improvement to the website or code docs) - + -## Checklist - +**Checklist:** + -- [ ] The PR is submitted to the correct branch (`dev`). -- [ ] My code follows the code style of this project. -- [ ] I've added relevant tests. +- The PR is submitted to the correct branch (`dev`). +- My code follows the style of this project. +- I've added relevant tests or tested on existing ones. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000000..e8d54c36c242 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,49 @@ +# MudBlazor AI Coding Agent Instructions + +## Project Overview +MudBlazor is a Material Design component library for Blazor, written mostly in C#. It features minimal JavaScript, extensive documentation, and a strong focus on test coverage and code quality. The repo is organized into several key projects: +- `src/MudBlazor`: Core components, styles, enums, services, and utilities +- `src/MudBlazor.Docs`: Documentation site and examples +- `src/MudBlazor.UnitTests`: bUnit and C# tests for components +- `src/MudBlazor.Docs.Compiler`: Generates API docs from source + +## Architecture & Patterns +- **Components**: Located in `src/MudBlazor/Components`. Each component typically has `.razor` and `.razor.cs` files, with styles in `src/MudBlazor/Styles/components`. +- **ParameterState Pattern**: Component parameters must be auto-properties (no logic in getter/setter). Use the `ParameterState` registration pattern in the constructor for change handling. See `CONTRIBUTING.md` for examples. +- **RTL Support**: Components should support right-to-left layouts via `[CascadingParameter] public bool RightToLeft {get; set;}`. +- **Services**: Provided via DI, registered in `Program.cs` with `builder.Services.AddMudServices();`. See `src/MudBlazor/Services` for service implementations. +- **Enums & Extensions**: Shared enums in `src/MudBlazor/Enums`, helpers in `src/MudBlazor/Extensions`. +- **JavaScript Interop**: Minimal JS, located in `src/MudBlazor/TScripts`. + +## Developer Workflows +- **Build**: Use the VS Code task `build` or run `dotnet build src/MudBlazor.sln`. +- **Test**: Use the VS Code task `test` or run `dotnet test src/MudBlazor.UnitTests/MudBlazor.UnitTests.csproj`. All logic changes require tests. +- **Docs Preview**: Run `MudBlazor.Docs.WasmHost` locally to preview documentation changes. +- **Coverage**: Use the VS Code task `coverage report` to view test coverage HTML report. +- **Local PR Testing**: See `TESTING.md` for instructions to pack and test MudBlazor locally in your app. + +## Conventions & Best Practices +- **No logic in `[Parameter]` setters/getters**; use `ParameterState` for change handling. +- **Do not overwrite parameters in components**; use `ParameterState.SetValueAsync()`. +- **Do not set component parameters outside their markup**; use declarative syntax. +- **Tests**: bUnit tests for components, C# tests for logic. Do not save HTML element references in variables in bUnit tests. +- **Branching**: PRs should target `dev` and follow naming conventions (`feature/...`, `fix/...`). +- **Formatting**: Follow .NET formatting rules. + +## Integration Points +- **NuGet**: Main package is `MudBlazor`. Local builds can be tested via custom NuGet source (see `TESTING.md`). +- **Docs Compiler**: API docs are generated from source via `src/MudBlazor.Docs.Compiler`. +- **CI**: GitHub Actions run build, test, coverage, and quality checks on all PRs. + +## Key Files & Directories +- `src/MudBlazor/Components/`: Core component implementations +- `src/MudBlazor/Styles/components/`: SCSS styles for components +- `src/MudBlazor/Enums/`: Shared enums +- `src/MudBlazor/Extensions/`: Extension methods +- `src/MudBlazor.UnitTests/`: bUnit and logic tests +- `src/MudBlazor.Docs/Pages/Components/`: Docs pages for components +- `CONTRIBUTING.md`, `TESTING.md`, `README.md`: Essential workflow and architecture guidance + +--- + +If any section is unclear or missing important project-specific details, please provide feedback so this guide can be improved for future AI agents. diff --git a/.github/scripts/AutoTriage.js b/.github/scripts/AutoTriage.js new file mode 100644 index 000000000000..cf271c6def70 --- /dev/null +++ b/.github/scripts/AutoTriage.js @@ -0,0 +1,326 @@ +/** + * AutoTriage - AI-Powered GitHub Issue & PR Analyzer + * + * Automatically analyzes GitHub issues and pull requests using Google Gemini AI, + * then applies appropriate labels and helpful comments to improve project management. + * + * Features: + * • Smart labeling based on content analysis + * • Helpful AI-generated comments for issues (not PRs) + * • Safe dry-run mode by default + * • Comprehensive error handling and logging + * + * Usage: + * • Issues: Analyzes, labels, comments, and can close if appropriate + * • Pull Requests: Analyzes and labels only (no comments or closing) + * + * Required Environment Variables: + * • GEMINI_API_KEY - Google Gemini API key + * • GITHUB_TOKEN - GitHub token with repo permissions + * • GITHUB_ISSUE_NUMBER - Issue/PR number to process + * • GITHUB_REPOSITORY - Repository in format "owner/repo" + * • AUTOTRIAGE_ENABLED - Set to 'true' to enable real actions (default: dry-run) + * + * Based on original work by Daniel Chalmers + * https://gist.github.com/danielchalmers/503d6b9c30e635fccb1221b2671af5f8 + */ + +const fetch = require('node-fetch'); +const { Octokit } = require('@octokit/rest'); +const core = require('@actions/core'); +const fs = require('fs'); +const path = require('path'); + +// Configuration +const dryRun = process.env.AUTOTRIAGE_ENABLED !== 'true'; +const aiModel = 'gemini-2.5-pro'; + +// Load AI prompt +let basePrompt = ''; +try { + const promptPath = path.join(__dirname, 'AutoTriage.prompt'); + basePrompt = fs.readFileSync(promptPath, 'utf8'); + console.log('🤖 Base prompt loaded from AutoTriage.prompt\n'); +} catch (err) { + console.error('❌ Failed to load AutoTriage.prompt:', err.message); + process.exit(1); +} + +console.log(`🤖 Using Gemini model: ${aiModel}`); + +/** + * Analyze an issue or PR using Gemini AI + */ +async function analyzeIssue(issueText, apiKey, metadata = {}) { + const metadataText = buildMetadataText(metadata); + const commentsText = buildCommentsText(metadata.comments); + + const prompt = `${basePrompt} + +ISSUE TO ANALYZE: +${issueText} + +ISSUE METADATA: +${metadataText} + +COMMENTS: +${commentsText} + +Analyze this issue and provide your structured response.`; + + const response = await fetch( + `https://generativelanguage.googleapis.com/v1beta/models/${aiModel}:generateContent`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-goog-api-key': apiKey + }, + body: JSON.stringify({ + contents: [{ parts: [{ text: prompt }] }], + generationConfig: { + responseMimeType: "application/json", + responseSchema: { + type: "object", + properties: { + reason: { type: "string", description: "Brief technical explanation for logging purposes" }, + comment: { type: "string", description: "A comment to reply to the issue with", nullable: true }, + labels: { type: "array", items: { type: "string" }, description: "Array of labels to apply" } + }, + required: ["reason", "comment", "labels"] + } + } + }), + timeout: 60000 + } + ); + + if (!response.ok) { + const errText = await response.text(); + throw new Error(`AI API error: ${response.status} ${response.statusText} — ${errText}`); + } + + const data = await response.json(); + const analysisResult = data?.candidates?.[0]?.content?.parts?.[0]?.text; + + if (!analysisResult) { + throw new Error('No analysis result in AI response'); + } + + return JSON.parse(analysisResult); +} + +/** + * Build metadata text for AI prompt + */ +function buildMetadataText(metadata) { + const parts = []; + if (metadata.created_at) parts.push(`Created: ${metadata.created_at}`); + if (metadata.updated_at) parts.push(`Last Updated: ${metadata.updated_at}`); + if (metadata.number) parts.push(`Issue Number: #${metadata.number}`); + if (metadata.author) parts.push(`Author: ${metadata.author}`); + if (metadata.comments_count !== undefined) parts.push(`Comments: ${metadata.comments_count}`); + if (metadata.reactions_total !== undefined) parts.push(`Reactions: ${metadata.reactions_total}`); + if (metadata.labels?.length) parts.push(`Labels: ${metadata.labels.join(', ')}`); + + return parts.length ? parts.join('\n') : 'No metadata available.'; +} + +/** + * Build comments text for AI prompt + */ +function buildCommentsText(comments) { + if (!comments?.length) return 'No comments available.'; + + let text = '\nISSUE COMMENTS:'; + comments.forEach((comment, idx) => { + text += `\nComment ${idx + 1} by ${comment.author}:\n${comment.body}`; + }); + return text; +} + +/** + * Apply labels to match AI suggestions + */ +async function applyLabels(suggestedLabels, issue, repo, octokit) { + const currentLabels = issue.labels?.map(l => typeof l === 'string' ? l : l.name) || []; + const labelsToAdd = suggestedLabels.filter(l => !currentLabels.includes(l)); + const labelsToRemove = currentLabels.filter(l => !suggestedLabels.includes(l)); + + if (labelsToAdd.length === 0 && labelsToRemove.length === 0) { + console.log('🏷️ No label changes needed'); + return; + } + + if (!octokit) { + console.log(`🏷️ [DRY RUN] Would add: [${labelsToAdd.join(', ')}]`); + console.log(`🏷️ [DRY RUN] Would remove: [${labelsToRemove.join(', ')}]`); + return; + } + + if (labelsToAdd.length > 0) { + await octokit.rest.issues.addLabels({ + owner: repo.owner, + repo: repo.repo, + issue_number: issue.number, + labels: labelsToAdd + }); + console.log(`🏷️ Added: [${labelsToAdd.join(', ')}]`); + } + + for (const label of labelsToRemove) { + await octokit.rest.issues.removeLabel({ + owner: repo.owner, + repo: repo.repo, + issue_number: issue.number, + name: label + }); + } + if (labelsToRemove.length > 0) { + console.log(`🏷️ Removed: [${labelsToRemove.join(', ')}]`); + } +} + +/** + * Post a comment on an issue + */ +async function postComment(issue, repo, octokit, comment) { + const commentWithFooter = `${comment}\n\n---\n*This comment was automatically generated using AI. If you have any feedback or questions, please share it in a reply.*`; + + if (!octokit) { + console.log(`💬 [DRY RUN] Would post comment:`); + console.log(commentWithFooter.replace(/^/gm, '> ')); + return; + } + + await octokit.rest.issues.createComment({ + owner: repo.owner, + repo: repo.repo, + issue_number: issue.number, + body: commentWithFooter + }); + + console.log(`💬 Posted comment`); +} + +/** + * Fetch issue data from GitHub + */ +async function fetchIssueData(owner, repo, number, octokit) { + if (!octokit) { + throw new Error('GitHub token required to fetch issue data'); + } + + const { data: issue } = await octokit.rest.issues.get({ + owner, + repo, + issue_number: number + }); + + let comments = []; + if (issue.comments > 0) { + const { data: commentsData } = await octokit.rest.issues.listComments({ + owner, + repo, + issue_number: number + }); + comments = commentsData.map(comment => ({ + author: comment.user?.login || 'unknown', + body: comment.body || '' + })); + } + + return { issue, comments }; +} + +/** + * Process a single issue or PR + */ +async function processIssue(issue, repo, geminiApiKey, octokit, comments = []) { + const isIssue = !issue.pull_request; + const itemType = isIssue ? 'issue' : 'pull request'; + + if (issue.locked) { + console.log(`🔒 Skipping locked ${itemType} #${issue.number}`); + return null; + } + + const metadata = { + number: issue.number, + created_at: issue.created_at, + updated_at: issue.updated_at, + author: issue.user?.login || 'unknown', + comments_count: issue.comments || 0, + reactions_total: issue.reactions?.total_count || 0, + state: issue.state, + type: isIssue ? 'issue' : 'pull_request', + labels: issue.labels?.map(l => typeof l === 'string' ? l : l.name) || [], + comments: comments + }; + + // Log issue info + console.log(`\n📝 ${issue.title}`); + console.log(`📝 ${metadata.state} ${itemType} by ${metadata.author} (${metadata.created_at})`); + console.log(`🏷️ Current labels: [${metadata.labels.join(', ') || 'none'}]`); + console.log(`💬 Comments: ${metadata.comments_count}, Reactions: ${metadata.reactions_total}`); + + // Analyze with AI + const issueText = `${issue.title}\n\n${issue.body || ''}`; + const analysis = await analyzeIssue(issueText, geminiApiKey, metadata); + + if (!analysis || typeof analysis !== 'object') { + throw new Error('Invalid analysis result'); + } + + console.log(`💡 ${analysis.reason}`); + + // Apply labels + await applyLabels(analysis.labels, issue, repo, octokit); + + // Post comment for issues only + if (isIssue && analysis.comment) { + await postComment(issue, repo, octokit, analysis.comment); + } + + return analysis; +} + +/** + * Main execution + */ +async function main() { + // Validate environment + const required = ['GITHUB_ISSUE_NUMBER', 'GEMINI_API_KEY', 'GITHUB_REPOSITORY']; + for (const env of required) { + if (!process.env[env]) { + throw new Error(`${env} environment variable is required`); + } + } + + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + const number = parseInt(process.env.GITHUB_ISSUE_NUMBER, 10); + + console.log(`📝 Processing ${owner}/${repo}#${number}`); + console.log(`🔧 Mode: ${dryRun ? 'DRY RUN' : 'LIVE'}`); + + // Initialize GitHub client + let octokit = null; + if (process.env.GITHUB_TOKEN) { + octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }); + } + + // Fetch and process issue + const { issue, comments } = await fetchIssueData(owner, repo, number, octokit); + const octokitForOps = dryRun ? null : octokit; + + await processIssue(issue, { owner, repo }, process.env.GEMINI_API_KEY, octokitForOps, comments); + + console.log('\n✅ AutoTriage completed successfully'); +} + +// Execute +main().catch(err => { + console.error('\n❌ Error:', err.message); + core.setFailed(err.message); + process.exit(1); +}); diff --git a/.github/scripts/AutoTriage.prompt b/.github/scripts/AutoTriage.prompt new file mode 100644 index 000000000000..f49583b2de5b --- /dev/null +++ b/.github/scripts/AutoTriage.prompt @@ -0,0 +1,122 @@ +You are a GitHub issue analysis assistant for MudBlazor. Your purpose is to save maintainers time by triaging issues. Only process issues that are in an 'Open' state; ignore any that are 'Closed' or 'Draft'. If you can help by asking questions or giving suggestions based on public information, do so. + +PERSONA GUIDELINES: +Your role is a first-line triage assistant. Your primary goal is to ensure new issues have enough information for a maintainer to act on them. You are not a discussion moderator, a summarizer, or a participant in ongoing conversations. Your main job is to interact with the initial report; avoid inserting yourself into active back-and-forth technical discussions. On GitHub, your username is `github-actions`. +Crucially, do not attempt to diagnose the internal workings of MudBlazor components or provide code snippets. Your tone should be kind, helpful, and direct. Avoid overstepping your bounds with statements like "This seems like a useful proposal" or "I will close this issue," which imply a level of authority or ability to perform repository actions. + +When you see a potential link to a common problem (caching, static rendering, or versioning), briefly mention it as a possibility to explore. +**Example:** "Hmm, this sounds like it could be related to caching. Have you tried incognito mode to rule that out? Just a thought." + +PROJECT CONTEXT: +- MudBlazor is a Blazor component framework with Material Design +- Written in C#, Razor, and CSS with minimal JavaScript +- Cross-platform support (Server, WebAssembly, MAUI) +- Reproduction site [https://try.mudblazor.com](https://try.mudblazor.com) is always on the latest version. +- Current v8.x.x supports .NET 8 and later +- Version migration guides are at [https://github.com/MudBlazor/MudBlazor/blob/dev/MIGRATION.md](https://github.com/MudBlazor/MudBlazor/blob/dev/MIGRATION.md) +- Templates for new projects are at [https://github.com/MudBlazor/Templates](https://github.com/MudBlazor/Templates) +- Complete installation guide is at [https://mudblazor.com/getting-started/installation](https://mudblazor.com/getting-started/installation) +- Contribution guidelines are at [https://github.com/MudBlazor/MudBlazor/blob/dev/CONTRIBUTING.md](https://github.com/MudBlazor/MudBlazor/blob/dev/CONTRIBUTING.md) +- Code of Conduct is at [https://github.com/MudBlazor/MudBlazor/blob/dev/CODE_OF_CONDUCT.md](https://github.com/MudBlazor/MudBlazor/blob/dev/CODE_OF_CONDUCT.md) +- Community talk is at [GitHub Discussions](https://github.com/MudBlazor/MudBlazor/discussions) or [Discord](https://discord.gg/mudblazor). + +COMMON ISSUE TYPES: +- Component bugs (MudButton, MudTable, MudDialog, MudForm, etc.) +- Styling/theming and CSS customization +- Browser compatibility +- Accessibility and Material Design compliance +- Performance with large datasets +- Integration with Blazor Server/WASM/MAUI +- Documentation gaps +- Potential security vulnerabilities or major regressions in core components +- Caching: Often causes issues after updates. Suggest testing in incognito mode. +- Static rendering issues: NOT supported in MudSelect/MudAutocomplete. See [render modes documentation](https://learn.microsoft.com/aspnet/core/blazor/components/render-modes) or [discussion](https://github.com/MudBlazor/MudBlazor/discussions/7430). + +ANALYZE THE ISSUE FOR QUALITY: +Consider an issue's age and update frequency. Note engagement like comments and reactions to gauge community interest, especially on older, un-updated issues. + +LOW QUALITY indicators (flag for improvement): +- Vague descriptions. +- Visual problems without screenshots. +- Bug reports missing reproduction steps or a working example (the generic placeholder link "[https://try.mudblazor.com/snippet](https://try.mudblazor.com/snippet)" counts as a missing reproduction). +- A feature request or enhancement that is missing a clear problem description, use case, or motivation (the "why"). +- Missing expected vs actual behavior. +- Missing technical details (version, browser, render mode). +- Ambiguous or unhelpful issue titles. +- Pure "how-to" or usage questions that are not describing a bug or unexpected behavior. You must be very certain it is a request for help and not a bug report. If an issue describes something "not working" or "behaving unexpectedly," treat it as a potential bug, even if phrased as a question. +- Code of conduct violations (harassment, trolling, personal attacks). +- Extremely low-effort issues (single words, gibberish, spam). +- Issues where the author put zero effort into explaining the problem (e.g., just "broken", "doesn't work"). + +HIGH QUALITY indicators (ready for labeling): +- Clear component name and specific problem. +- Includes reproduction steps or a working example (e.g., on [try.mudblazor.com](https://try.mudblazor.com)). +- For feature requests, a clear problem description and use case (the "why") are provided. +- Expected vs actual behavior explained. +- Technical details and screenshots provided. +- Descriptive title. + +VALID LABELS: +{ +    "accessibility": "Impacts usability for users with disabilities (a11y).", +    "breaking change": "For PRs: Signifies that a change will require users to modify their code upon update.", +    "bug": "An unexpected behavior or defect. This is a primary issue type. Apply at most one from the group: 'bug', 'enhancement', 'docs'. If uncertain, apply 'info required' to probe for more details before classifying.", +    "build": "Relates to the project's build process, tooling, CI/CD, README, or repository configuration.", +    "dependency": "Involves external libraries, packages, or third-party services.", +    "docs": "Pertains to documentation changes. This is a primary issue type. Apply at most one from the group: 'bug', 'enhancement', 'docs'. If uncertain, apply 'info required' to probe for more details before classifying.", +    "enhancement": "A new feature or improvement. This is a primary issue type. Apply at most one from the group: 'bug', 'enhancement', 'docs'. If uncertain, apply 'info required' to probe for more details before classifying.", +    "good first issue": "A well-defined, uncontroversial, and very simple to implement issue suitable for new contributors.", + "has workaround": "Indicates that a functional, albeit temporary, solution exists for the reported bug.", +    "info required": "The primary action label when an issue is blocked pending necessary details from the author. Use this for initial triage when it's unclear if an issue is a 'bug', 'enhancement', or something else.", +    "invalid": "An action label indicating a violation of community standards that warrants closing the issue, or an issue that will be closed due to excessive low quality.", +    "localization": "Concerns support for multiple languages or regional formats.", +    "mobile": "Impacts or is exclusive to small viewports, touch devices, or mobile-specific layouts (iOS/Android).", +    "needs example": "Apply IN ADDITION TO 'info required' when the specific missing information is a code example or a reproduction link.", +    "needs screenshot": "Apply IN ADDITION TO 'info required' when the specific missing information is a screenshot or video of the visual problem.", +    "new component": "For tracking an 'enhancement' that proposes or adds a brand-new UI component.", +    "performance": "Relates to speed, responsiveness, or resource efficiency.", +    "question": "An action label for a user seeking help and not reporting a bug or requesting a feature", +    "refactor": "For PRs: The primary focus is code reorganization that preserves existing behavior.", +    "regression": "Apply IN ADDITION TO 'bug' to indicate a high-priority bug where a feature that previously worked is now broken.", +    "safari": "The issue is specific to the Safari browser on desktop or iOS.", +    "security": "Impacts application security, including vulnerabilities or data protection.", + "stale": "Indicates an issue is inactive and will be closed if no further updates occur.", +    "tests": "Relates to unit, integration, or other automated testing frameworks." +} + +TASK: Analyze the issue and provide the following with high confidence: +1.  Quality assessment (whether the issue needs improvement or should be closed). +2. Appropriate labels from the valid labels list to add or remove. Only suggest removing labels if an existing label seems like a genuine mistake. +3.  Comment only if you have suggestions highly likely to help solve/improve the issue. + +COMMENTING GUIDELINES: +The decision to comment is based on one question: "Can I add clear value to this issue without getting in the way of human contributors?" + +**Good reasons to comment:** +*To request critical missing information:* +- The issue is a bug report but is missing a reproduction link on try.mudblazor.com. +- The issue describes a visual problem but is missing a screenshot. +- The issue is vague (e.g., "it's broken") and needs a clearer description of expected vs. actual behavior. +- The issue is a feature request (enhancement) but lacks a clear problem description, use case, or motivation (the "why"). +- If an issue appears to be a high-priority security vulnerability or a major regression that could likely impact a lot of users, you may comment ping the triage team by including `cc @MudBlazor/triage` at the end of your comment. This can be done even if the issue is otherwise high-quality. Use this with caution. + +**Bad reasons to comment (DO NOT COMMENT):** +- The issue meets all criteria for a high-quality report and needs no further input (unless it's a high-priority exception). +- Another user or maintainer (especially a core team member: `versile2`, `scarletkuro`, `danielchalmers`, `henon`, `garderoben`) has already asked for the same information or provided the same suggestion. +- The discussion is an active, ongoing technical debate. +- To summarize, thank the user, or compliment the issue. +- You (`github-actions`) have already commented on the issue. +- The issue has a `stale` label. + +COMMENT STYLE: +- Be direct, technical, and kind. Use markdown for links. +- Explain *why* you need information. (do not repeat these examples verbatim) +  - **Good:** "Could you please add a reproduction of the issue using our interactive playground at [try.mudblazor.com](https://try.mudblazor.com)? It's the fastest way to investigate and confirm a bug." +  - **Good:** "Could you share the full error message and stack trace from the browser's developer console? That will help pinpoint where the problem is happening." + - **Good:** "Thanks for the suggestion. Could you elaborate a bit on the use case for this feature? Understanding the problem you're trying to solve helps the team prioritize and design the best solution." +- Frame advice as possibilities based on general web development practices or public documentation. Avoid speculating about the component's internal code. +- You can't verify if a reproduction link works, so just acknowledge its presence. +- Use the phrase "**For anyone investigating this...**" instead of implying a maintainer will follow up. +- For help questions: Answer if you can, then direct to Discussions or Discord. +- For violations: Be firm, explain the violation, and link to the Code of Conduct. +- For closures: Clearly explain the reason and state that the author can open a new, improved issue. \ No newline at end of file diff --git a/.github/workflows/issue.yml b/.github/workflows/issue.yml index 315707cf9e99..3da4db93f079 100644 --- a/.github/workflows/issue.yml +++ b/.github/workflows/issue.yml @@ -3,33 +3,26 @@ on: types: [opened] jobs: - apply-label: + triage-issue: runs-on: ubuntu-latest + steps: - - uses: actions/github-script@v7 + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 with: - script: | - const body = context.payload.issue.body; - let labels = []; - - if (body.includes("### Feature request type\n\nNew component")) { - labels.push("new component"); - console.log("Feature request type: new component."); - - } else if (body.includes("### Feature request type\n\nPerformance improvement")) { - labels.push("performance"); - console.log("Feature request type: Performance improvement."); - - } else if (body.includes("### Bug type\n\nDocs (mudblazor.com)")) { - labels.push("docs"); - console.log("Bug type: docs."); - } - - if(labels.length != 0) { - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: labels - }) - } \ No newline at end of file + node-version: '22' + + - name: Install dependencies + run: npm install node-fetch@2 @actions/core @octokit/rest + + - name: Run AI triage script + env: + GITHUB_ISSUE_NUMBER: ${{ github.event.issue.number }} + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + AUTOTRIAGE_ENABLED: ${{ vars.AUTOTRIAGE_ENABLED }} + run: node ./.github/scripts/AutoTriage.js + \ No newline at end of file diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 94ea70820688..c9cc71e7eb81 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -3,41 +3,26 @@ on: types: [opened] jobs: - pr-bot: + triage-pr: runs-on: ubuntu-latest + steps: - - uses: actions/github-script@v7 + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 with: - script: | - const pr = context.payload.pull_request; - const body = pr.body; - let labels = []; - const isChecked = /-\s*\[\s*[x|X]\s*\]\s*/; - if(RegExp(isChecked.source + "Bug fix \\(non-breaking change which fixes an issue\\)").test(body)) { - labels.push("bug"); - console.log("PR type: bug fix."); - } - - if(RegExp(isChecked.source + "New feature \\(non-breaking change which adds functionality\\)").test(body)) { - labels.push("enhancement"); - console.log("PR type: enhancement."); - } + node-version: '22' - if(RegExp(isChecked.source + "Breaking change \\(fix or feature that would cause existing functionality to not work as expected\\)").test(body)) { - labels.push("breaking change"); - console.log("PR type: breaking change."); - } + - name: Install dependencies + run: npm install node-fetch@2 @actions/core @octokit/rest - if(RegExp(isChecked.source + "Documentation \\(fix or improvement to the website or code docs\\)").test(body)) { - labels.push("docs"); - console.log("PR type: documentation."); - } - - if(labels.length != 0) { - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: labels - }) - } + - name: Run AI triage script + env: + GITHUB_ISSUE_NUMBER: ${{ github.event.pull_request.number }} + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + AUTOTRIAGE_ENABLED: ${{ vars.AUTOTRIAGE_ENABLED }} + run: node ./.github/scripts/AutoTriage.js + \ No newline at end of file diff --git a/.github/workflows/triage-backlog.yml b/.github/workflows/triage-backlog.yml new file mode 100644 index 000000000000..2f470af81e1b --- /dev/null +++ b/.github/workflows/triage-backlog.yml @@ -0,0 +1,129 @@ +name: Triage Backlog + +on: + schedule: + - cron: '30 06 * * *' # Gemini rates reset at 7am, so we can use up the remaining quota for the day. + workflow_dispatch: + inputs: + backlog-size: + description: 'Number of issues to auto-discover' + required: false + default: '3' + type: string + issue-numbers: + description: 'Or use issue numbers (comma-separated)' + required: false + type: string + model: + description: 'Gemini model' + required: false + default: 'gemini-2.5-flash' + type: string + dry-run: + description: 'Dry-run (no actual changes)' + required: false + default: true + type: boolean + +env: + DRY_RUN: ${{ inputs.dry-run || vars.AUTOTRIAGE_ENABLED != 'true' }} + +jobs: + stale-issues: + runs-on: ubuntu-latest + if: github.event_name == 'workflow_dispatch' || github.repository == 'MudBlazor/MudBlazor' + + steps: + - name: Mark stale issues + uses: actions/stale@v9 + with: + stale-issue-label: 'stale' + any-of-issue-labels: 'info required' + days-before-issue-stale: 14 + days-before-issue-close: 14 + stale-issue-message: | + This issue has been marked as stale. + If you have any updates or additional information, please comment below. + + If no response is received, it will be automatically closed. + + stale-pr-label: 'stale' + exempt-pr-labels: 'on hold,breaking change' + days-before-pr-stale: 180 + days-before-pr-close: 90 + stale-pr-message: | + Hi, this pull request hasn't had any recent activity and has been marked as stale. + + Please let us know if you're still working on it or if we can help move it forwards! @MudBlazor/triage + close-pr-message: | + This pull request has been closed due to inactivity. + + If you would like to continue working on it, please open a new PR referencing this one. + + exempt-all-assignees: true + debug-only: ${{ env.DRY_RUN }} + + auto-triage: + runs-on: ubuntu-latest + needs: stale-issues + if: github.event_name == 'workflow_dispatch' || github.repository == 'MudBlazor/MudBlazor' + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install dependencies + run: npm install node-fetch@2 @actions/core @octokit/rest + + - name: Get issues to process + id: get-issues + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if [ -n "${{ inputs.issue-numbers }}" ]; then + # Process specific issues + echo "Processing specific issues: ${{ inputs.issue-numbers }}" + echo "${{ inputs.issue-numbers }}" | tr ', ' '\n' | grep -v '^$' | jq -R . | jq -s . > issues.json + else + # Find unlabeled issues for automated processing + backlog_size="${{ inputs.backlog-size || '15' }}" + echo "Finding $backlog_size unlabeled issues" + gh issue list \ + --state open \ + --limit 99999 \ + --json number,labels \ + --jq '.[] | select((.labels // [] | length == 0)) | .number' \ + | head -n "$backlog_size" \ + | jq -R . | jq -s . > issues.json + fi + + issue_count=$(cat issues.json | jq length) + echo "Found $issue_count issues to process" + echo "issue-count=$issue_count" >> $GITHUB_OUTPUT + + if [ "$issue_count" -eq 0 ]; then + echo "No issues found to process" + exit 0 + fi + + - name: Process issues + if: steps.get-issues.outputs.issue-count > 0 + env: + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + AUTOTRIAGE_ENABLED: ${{ env.DRY_RUN == 'false' }} + run: | + cat issues.json | jq -r '.[]' | while read -r issue_number; do + if [ -n "$issue_number" ]; then + echo "——————————————————————————————————Issue #$issue_number——————————————————————————————————" + export GITHUB_ISSUE_NUMBER="$issue_number" + node .github/scripts/AutoTriage.js + # Rate limiting delay + sleep 15 + fi + done diff --git a/.github/workflows/triage-info-required.yml b/.github/workflows/triage-info-required.yml new file mode 100644 index 000000000000..67f81ef9b5aa --- /dev/null +++ b/.github/workflows/triage-info-required.yml @@ -0,0 +1,28 @@ +name: Triage 'info required' + +on: + issue_comment: + types: [created] + +jobs: + remove_label_on_author_comment: + runs-on: ubuntu-latest + + # This 'if' condition ensures the job only runs when all criteria are met: + # 1. The comment author is the same as the issue author. + # 2. The issue currently has the label "info required". + if: | + github.event.comment.user.login == github.event.issue.user.login && + contains(github.event.issue.labels.*.name, 'info required') + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Remove "info required" label + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + run: | + echo "Removing 'info required' label from issue #$ISSUE_NUMBER" + gh issue edit "$ISSUE_NUMBER" --remove-label "info required" --remove-label "stale" diff --git a/README.md b/README.md index d3a7b45b92d3..c8ff7d16ab99 100644 --- a/README.md +++ b/README.md @@ -20,72 +20,42 @@ [![NuGet version](https://img.shields.io/nuget/v/MudBlazor?color=ff4081&label=nuget%20version&logo=nuget&style=flat-square)](https://www.nuget.org/packages/MudBlazor/) [![NuGet downloads](https://img.shields.io/nuget/dt/MudBlazor?color=ff4081&label=nuget%20downloads&logo=nuget&style=flat-square)](https://www.nuget.org/packages/MudBlazor/) -MudBlazor is an ambitious Material Design component framework for Blazor with an emphasis on ease of use and clear structure. It is perfect for .NET developers who want to rapidly build web applications without having to struggle with CSS and Javascript. MudBlazor, being written entirely in C#, empowers you to adapt, fix or extend the framework. There are plenty of examples in the documentation, which makes understanding and learning MudBlazor very easy. - -## 📘 Documentation & Demo -- 🌐 [MudBlazor.com](https://mudblazor.com) – Full documentation -- ⚡ [Try.MudBlazor.com](https://try.mudblazor.com/) – Interactive playground - -## 💎 Why is MudBlazor so successful? -- Aesthetic design that follows Material Design principles. -- Intuitive, consistent component structure. -- Rich documentation with tons of examples and code snippets. -- Fully written in C# with minimal JavaScript. -- Build beautiful UIs without CSS (but fully customizable when needed). -- No third-party component dependencies – maximum flexibility. -- Strive for stability with extensive test coverage. -- Frequent releases so devs get their fixes and features fast. - -## ⚙️ Prerequisites -| MudBlazor | .NET | Support | -| :--- | :---: | :---: | -| 1.x.x - 2.0.x | .NET 3.1 | Ended 03/2021 | -| 5.x.x | .NET 5 | Ended 01/2022 | -| 6.x.x | [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0), [.NET 7](https://dotnet.microsoft.com/download/dotnet/7.0), [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) | Ended 01/2025 | -| 7.x.x | [.NET 7](https://dotnet.microsoft.com/download/dotnet/7.0), [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) | Limited | -| 8.x.x | [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0), [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) | :heavy_check_mark: | +MudBlazor is an ambitious Material Design component library for Blazor. Accelerate your web application development and build intuitive user interfaces, leveraging the full power of C# to adapt and extend this open-source framework. -> [!TIP] -> Upgrading? Check our [Migration Guide](https://github.com/MudBlazor/MudBlazor/blob/dev/MIGRATION.md) for help with breaking changes. +**🌐 [Documentation](https://mudblazor.com) ⚡ [Interactive Playground](https://try.mudblazor.com/)** -> [!WARNING] -> 1. Static rendering is not supported - [Learn more](https://learn.microsoft.com/aspnet/core/blazor/components/render-modes). -> 2. Older browsers may not be supported. Use a modern, up-to-date browser - [Blazor supported platforms](https://learn.microsoft.com/aspnet/core/blazor/supported-platforms). +## 💎 Why Choose MudBlazor? -## 📊 Repo Stats -![Alt](https://repobeats.axiom.co/api/embed/db53a44092e88fc34a4c0f37db12773b6787ec7e.svg "Repobeats analytics image") - -## 🤝 Contributing -Thanks for wanting to contribute! 👋 -Contributions from the community are what makes MudBlazor successful. - -If you're comfortable with C#, Blazor, JavaScript, or CSS, we'd love your help! -Whether it's fixing bugs, adding features, or improving documentation, every contribution counts. +🎨 Beautiful Material Design components. +💻 Fully written in C# with minimal JavaScript. +📖 Rich documentation with extensive examples. +📦 No third-party dependencies for maximum flexibility. +✅ Extensive test coverage for stability. -We aim to review and merge non-breaking pull requests quickly. -For larger features or changes, feel free to chat with us [on Discord](https://discord.gg/mudblazor) first to get feedback before diving in. +## 📊 Repo Stats -📚 Check out our [contribution guidelines](/CONTRIBUTING.md) to get started and learn more about how the project works. +![Repobeats analytics image](https://repobeats.axiom.co/api/embed/db53a44092e88fc34a4c0f37db12773b6787ec7e.svg) -### Testing a PR Locally +## 🚀 Getting Started -✅ If a PR fixes something you reported, [locally test a preview version](/TESTING.md) to ensure your app works as expected before the update is released. +We have ready-to-go templates at the [Templates](https://github.com/MudBlazor/Templates) repository, or follow the quick install guide below: -## 🚀 Getting Started -We have ready-to-go templates at the [MudBlazor.Templates](https://github.com/mudblazor/Templates) repository, or follow the quick install guide to set things up manually: +### Installation -### 🛠️ Quick Install Install Package: -``` + +```bash dotnet add package MudBlazor ``` Add to `_Imports.razor`: + ```razor @using MudBlazor ``` -Add to the `MainLayout.razor` or `App.razor`: +Add to `MainLayout.razor` or `App.razor`: + ```razor @@ -93,30 +63,31 @@ Add to the `MainLayout.razor` or `App.razor`: ``` -Add to your HTML `head` section: +Add to your HTML `head` section (`index.html`/`_Layout.cshtml`/`_Host.cshtml`/`App.razor`): + ```razor ``` -It's either `index.html` or `_Layout.cshtml`/`_Host.cshtml`/`App.razor` depending on whether you're running WebAssembly or Server. - -Next, add to the default Blazor script at the end of the `body`: + +Add to the default Blazor script at the end of the `body`: + ```razor ``` Add to the relevant sections of `Program.cs`: + ```c# using MudBlazor.Services; ``` + ```c# builder.Services.AddMudServices(); ``` -### 🔗 Full Setup Guide -For more details, see the [complete installation guide](https://mudblazor.com/getting-started/installation) on our website. +### Example Usage -### 💻 Example Usage ```razor MudBlazor is @Text @@ -141,3 +112,35 @@ For more details, see the [complete installation guide](https://mudblazor.com/ge } } ``` + +For more details, see the [complete installation guide](https://mudblazor.com/getting-started/installation) on our website. + +## 🤝 Contributing + +Contributions from the community are what makes MudBlazor successful. + +If you're comfortable with C#, Blazor, JavaScript, or CSS, we'd love your help! +Whether it's fixing bugs, adding features, or improving documentation, every contribution counts. + +We aim to review and merge non-breaking pull requests quickly. +For larger features or changes, feel free to chat with us [on Discord](https://discord.gg/mudblazor) to get feedback before diving in. + +📚 Check out our [contribution guidelines](/CONTRIBUTING.md) to get started and learn more about how the project works. +✅ If a PR fixes something you reported, [locally test a preview version](/TESTING.md) to ensure your app works as expected. + +## ⚙️ Version Support + +| MudBlazor | .NET | Support | +| :--- | :---: | :---: | +| 5.x.x | .NET 5 | Ended (Jan 2022) | +| 6.x.x | [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0), [.NET 7](https://dotnet.microsoft.com/download/dotnet/7.0), [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) | Ended (Jan 2025) | +| 7.x.x | [.NET 7](https://dotnet.microsoft.com/download/dotnet/7.0), [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) | Limited Support | +| 8.x.x | [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0), [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) | :heavy_check_mark: Full Support | + +> [!TIP] +> Upgrading? Check our [Migration Guide](https://github.com/MudBlazor/MudBlazor/blob/dev/MIGRATION.md) for help with breaking changes. + +> [!WARNING] +> +> 1. Static rendering is not supported - [Learn more](https://learn.microsoft.com/aspnet/core/blazor/components/render-modes). +> 2. Older browsers may not be supported. Use a modern, up-to-date browser - [Blazor supported platforms](https://learn.microsoft.com/aspnet/core/blazor/supported-platforms). diff --git a/src/MudBlazor.Docs/Models/CommunityExtension.cs b/src/MudBlazor.Docs/Models/CommunityExtension.cs index d6745e9fc625..5f45c7dbfd47 100644 --- a/src/MudBlazor.Docs/Models/CommunityExtension.cs +++ b/src/MudBlazor.Docs/Models/CommunityExtension.cs @@ -3,34 +3,25 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Text.Json.Serialization; namespace MudBlazor.Docs.Models; [DebuggerDisplay($"Name = {nameof(Name)}")] public class CommunityExtension { - [JsonPropertyName("AvatarImageSrc")] - public string AvatarImageSrc { get; set; } = @"https://mudblazor.com/_content/MudBlazor.Docs/images/logo.png"; + public string AvatarImageSrc => @$"_content/MudBlazor.Docs/images/extensions/{GitHubUserPath}.{GitHubRepoPath}.webp"; - [JsonPropertyName("Category")] - public string Category { get; set; } = "Parent"; + public required string Category { get; set; } - [JsonPropertyName("Name")] - public string Name { get; set; } = "MudBlazor"; + public required string Name { get; set; } - [JsonPropertyName("Description")] - public string Description { get; set; } = "With millions of downloads, from hobby developers to large enterprises, MudBlazor enables you to rapidly build amazing web applications without leaving your beloved C# language and toolchain. "; + public required string Description { get; set; } - [JsonPropertyName("Link")] - public string Link { get; set; } = @"https://mudblazor.com"; + public required string Link { get; set; } - [JsonPropertyName("GitHubUserPath")] - public string GitHubUserPath { get; set; } = "MudBlazor"; + public required string GitHubUserPath { get; set; } - [JsonPropertyName("GitHubRepoPath")] - public string GitHubRepoPath { get; set; } = "MudBlazor"; + public required string GitHubRepoPath { get; set; } - [JsonIgnore] public string GitHubLink => @$"https://github.com/{GitHubUserPath}/{GitHubRepoPath}"; } diff --git a/src/MudBlazor.Docs/Models/TeamMember.cs b/src/MudBlazor.Docs/Models/TeamMember.cs index 24dceac2c29c..72e7b27800fa 100644 --- a/src/MudBlazor.Docs/Models/TeamMember.cs +++ b/src/MudBlazor.Docs/Models/TeamMember.cs @@ -10,7 +10,7 @@ public class TeamMember public string From { get; set; } public string GitHub { get; set; } public bool GitHubSponsor { get; set; } - public string Avatar { get; set; } + public string Avatar => $"https://github.com/{GitHub}.png?size=56"; public string LinkedIn { get; set; } public string Bio { get; set; } } diff --git a/src/MudBlazor.Docs/Models/TeamMemberData.cs b/src/MudBlazor.Docs/Models/TeamMemberData.cs index 2e99aab05b47..f7c51138c29f 100644 --- a/src/MudBlazor.Docs/Models/TeamMemberData.cs +++ b/src/MudBlazor.Docs/Models/TeamMemberData.cs @@ -19,7 +19,6 @@ public static TeamMember[] GetCoreTeam() => Name = "Jonny Larsson (Creator)", From = "Örebro, Sweden", GitHub = "Garderoben", - Avatar = "https://avatars.githubusercontent.com/u/10367109?v=4", LinkedIn = "https://www.linkedin.com/in/jonny-larsson-b72480161/", Bio = "DevOps Engineer.\r\nRecently been doing more developing in free time and for in house applications for my company to automate processes.", }, @@ -28,7 +27,6 @@ public static TeamMember[] GetCoreTeam() => Name = "Meinrad Recheis (Co-Creator)", From = "Vienna, Austria", GitHub = "henon", - Avatar = "https://avatars.githubusercontent.com/u/44090?v=4", LinkedIn = "https://www.linkedin.com/in/meinrad-recheis-6a9885171/", Bio = "Entrepreneur and Open Source contributor. Co-founder of MudBlazor. Creator of Numpy.NET and Python.Included. ", }, @@ -37,7 +35,6 @@ public static TeamMember[] GetCoreTeam() => Name = "András Tangl", From = "Szombathely, Hungary", GitHub = "tungi52", - Avatar = "https://avatars.githubusercontent.com/u/22996720?v=4", LinkedIn = "https://www.linkedin.com/in/andr%C3%A1s-tangl-683a20215/", Bio = null, }, @@ -46,7 +43,6 @@ public static TeamMember[] GetCoreTeam() => Name = "Mike Surcouf", From = "Jersey, Channel Islands", GitHub = "mikes-gh", - Avatar = "https://avatars.githubusercontent.com/u/16208742?v=4", LinkedIn = null, Bio = null, }, @@ -55,7 +51,6 @@ public static TeamMember[] GetCoreTeam() => Name = "Benjamin Kappel", From = "Malaysia", GitHub = "just-the-benno", - Avatar = "https://avatars.githubusercontent.com/u/51370361?v=4", LinkedIn = "https://www.linkedin.com/in/benjamin-kappel-558428168/", Bio = "A long time ago, there was an enormous book with an even more significant discount on it, titled C#. That is the starting point of still ongoing love.", }, @@ -64,7 +59,6 @@ public static TeamMember[] GetCoreTeam() => Name = "Jonas B.", From = "Germany", GitHub = "JonBunator", - Avatar = "https://avatars.githubusercontent.com/u/62108893?v=4", LinkedIn = null, Bio = null, }, @@ -73,7 +67,6 @@ public static TeamMember[] GetCoreTeam() => Name = "Riley Nielsen", From = "Minnesota, United States", GitHub = "Mr-Technician", - Avatar = "https://avatars.githubusercontent.com/u/26885142?v=4", LinkedIn = "https://www.linkedin.com/in/riley-nielsen-a57399223/", Bio = null, }, @@ -83,7 +76,6 @@ public static TeamMember[] GetCoreTeam() => From = "Estonia, Tallinn", GitHub = "ScarletKuro", GitHubSponsor = true, - Avatar = "https://avatars.githubusercontent.com/u/19953225?v=4", LinkedIn = "https://www.linkedin.com/in/artyommelnikov/", Bio = ".NET/Java developer", }, @@ -92,7 +84,6 @@ public static TeamMember[] GetCoreTeam() => Name = "Daniel Chalmers", From = "Texas, United States", GitHub = "danielchalmers", - Avatar = "https://avatars.githubusercontent.com/u/7112040?v=4", LinkedIn = "https://www.linkedin.com/in/daniel-c-5799252b1", Bio = "Full stack engineer specializing in .NET, Blazor, CSS, WPF. Building accessible apps with a focus on modern UI/UX", }, @@ -105,7 +96,6 @@ public static TeamMember[] GetContributionTeam() => Name = "Henrique Clausing", From = "Brazil", GitHub = "HClausing", - Avatar = "https://avatars.githubusercontent.com/u/15158923?v=4", LinkedIn = "https://www.linkedin.com/in/henrique-clausing-cunha-45085944/", Bio = "Accountant and Full-Stack .NET developer. Founder of Eficaz Sistemas.", }, @@ -114,7 +104,6 @@ public static TeamMember[] GetContributionTeam() => Name = "Porkopek", From = "Fundão, Portugal", GitHub = "porkopek", - Avatar = "https://avatars.githubusercontent.com/u/13745954?v=4", LinkedIn = null, Bio = null, }, @@ -123,7 +112,6 @@ public static TeamMember[] GetContributionTeam() => Name = "Mehmet Can Karagöz", From = "Alanya, Turkey", GitHub = "mckaragoz", - Avatar = "https://avatars.githubusercontent.com/u/78308169?v=4", LinkedIn = null, Bio = null, }, @@ -132,7 +120,6 @@ public static TeamMember[] GetContributionTeam() => Name = "Jon Person", From = "Denver, CO", GitHub = "jperson2000", - Avatar = "https://avatars.githubusercontent.com/u/18043079?v=4", LinkedIn = null, Bio = "I'm a full-stack C# developer for the U.S. Department of Defense who specializes in Blazor, durable back-end systems, and reusable frameworks.", }, @@ -141,7 +128,6 @@ public static TeamMember[] GetContributionTeam() => Name = "Lukas Klinger", From = "Germany", GitHub = "Flaflo", - Avatar = "https://avatars.githubusercontent.com/u/12973684?v=4", LinkedIn = null, Bio = ".NET & Java Full-Stack Developer", }, @@ -151,7 +137,6 @@ public static TeamMember[] GetContributionTeam() => From = "Luxembourg", GitHub = "igotinfected", GitHubSponsor = true, - Avatar = "https://avatars.githubusercontent.com/u/15004223?v=4", LinkedIn = null, Bio = "Web & Mobile Analyst Developer with a faible for Open Source and Cybersecurity.", }, @@ -160,7 +145,6 @@ public static TeamMember[] GetContributionTeam() => Name = "Samuel Meenzen", From = "Germany", GitHub = "meenzen", - Avatar = "https://avatars.githubusercontent.com/u/22305878?v=4", LinkedIn = null, Bio = null, }, @@ -169,7 +153,6 @@ public static TeamMember[] GetContributionTeam() => Name = "Justin Lampe", From = null, GitHub = "xC0dex", - Avatar = "https://avatars.githubusercontent.com/u/22918366?v=4", LinkedIn = null, Bio = null, }, @@ -178,7 +161,6 @@ public static TeamMember[] GetContributionTeam() => Name = "Roman Alvarez", From = "Uruguay", GitHub = "ralvarezing", - Avatar = "https://avatars.githubusercontent.com/u/40799354?v=4", LinkedIn = null, Bio = "DevOps at SONDA & Computing Engineering student.", }, @@ -188,7 +170,6 @@ public static TeamMember[] GetContributionTeam() => From = "Texas, United States", GitHub = "versile2", GitHubSponsor = true, - Avatar = "https://avatars.githubusercontent.com/u/148913404?v=4", LinkedIn = null, Bio = null, }, @@ -197,7 +178,6 @@ public static TeamMember[] GetContributionTeam() => Name = "Anu6is", From = "Trinidad & Tobago", GitHub = "anu6is", - Avatar = "https://avatars.githubusercontent.com/u/4596077?v=4", LinkedIn = null, Bio = null, }, @@ -206,7 +186,6 @@ public static TeamMember[] GetContributionTeam() => Name = "digitaldirk", From = "the woods", GitHub = "digitaldirk", - Avatar = "https://avatars.githubusercontent.com/u/22691956?v=4", LinkedIn = null, Bio = "C# and game things", }, diff --git a/src/MudBlazor.Docs/NotificationContent/Announcement_v7_GA.razor b/src/MudBlazor.Docs/NotificationContent/Announcement_v7_GA.razor index c005d5e69a25..992ec859fe8d 100644 --- a/src/MudBlazor.Docs/NotificationContent/Announcement_v7_GA.razor +++ b/src/MudBlazor.Docs/NotificationContent/Announcement_v7_GA.razor @@ -1,63 +1,11 @@  - + - MudBlazor version 7.0.0 is officially released, bringing many new features along with several breaking changes that were holding us back, and which we don't want to postpone any longer as we strive for more consistency and innovation. + MudBlazor v7 is officially released, bringing many new features along with several breaking changes. + This update creates a more solid foundation for future growth.

- Stay up-to-date by checking our GitHub or NuGet for updates. -
-
-
- - - - - .NET 6 is no longer supported and .NET 7 is the new minimum version. - We recommend switching to .NET 8 LTS for the best experience. -
-
- If you still need .NET 6, you can stay on the v6.x.x branch which is still supported. - We'll fix critical bugs and security issues, but new features will only come to version 7. -
-
- Found a bug you want backported to v6? - Submit a pull request and we'll include it in an update. -
-
-
- - - - - This update brings a significant number of bug fixes, improvements, and new features. - Please note that in order to create a more solid foundation for future growth we have made several breaking changes that may impact your existing workflow. -
-
- We've prepared a list of all the changes you need to be aware of when upgrading from v6.x.x in the v7.0.0 Migration Guide. -
-
-
- - - - - We welcome contributions from our community! -
-
- If you come across any issues in the new version, please report them on our issue tracker so we can get this new major version as stable as possible! -
-
- We try to merge all bugfix PRs and will deliberate the value of feature PRs for the community. -
- To get started, please visit our GitHub page and familiarize yourself with the contribution guidelines. -
-
-
- - - - - Find more details about our future plans in the roadmap. + For detailed migration information, please see the v7.0.0 Migration Guide. diff --git a/src/MudBlazor.Docs/NotificationContent/Announcement_v8_GA.razor b/src/MudBlazor.Docs/NotificationContent/Announcement_v8_GA.razor index fab90599d3b3..16cbd4ff5658 100644 --- a/src/MudBlazor.Docs/NotificationContent/Announcement_v8_GA.razor +++ b/src/MudBlazor.Docs/NotificationContent/Announcement_v8_GA.razor @@ -1,74 +1,11 @@  - + - MudBlazor continues to thrive with millions of downloads on - NuGet and thousands of members on - Discord. + MudBlazor v8 continues to build on the success of v7 with new features and improvements. + This version focuses on .NET 8 and .NET 9 support while maintaining a stable foundation.

- With the recent release of v7, and now v8, we've made significant progress in ensuring the library remains healthy and robust. - Not only have we introduced countless new features and bug fixes, but we've built a more stable foundation for future development, allowing us to continue moving the project forward to meet the needs of the community. -
-
-
- - - - - .NET Lifecycle - Builds are no longer provided for .NET 6 or .NET 7. - This aligns with Microsoft's - .NET support policies and lets us focus on providing the best support for newer editions. -
-
- Update your SDK to .NET 8 or .NET 9 to get the latest packages. - - MudBlazor Lifecycle - v8: This is the current recommended version and all new features and development effort will be directed here. -
- v7: We will continue to accept bugfixes from the community for v7 but no new features will be introduced and we won't accept any requests. -
- v6: Support for v6 ended 01/2025 and no new patches will be released. - - Migrating from a Previous Version - The release of v7 addressed several long-standing needs for breaking changes and our goal for v8 is to build on that success while ensuring a smoother transition. -
-
- For help with migrating to a new version, please refer to the - v7.0.0 Migration Guide or - v8.0.0 Migration Guide. - In addition we've created a - built-in analyzer that identifies parameters that have been removed or renamed. -
-
-
- - - - - We are passionate about improving the library but can't make firm promises about release timelines or specific features as the MudBlazor team is made up of volunteers who contribute to the project in their personal time. -
-
- Our goal is to keep MudBlazor stable, performant, and evolving with thoughtful enhancements, but the pace of development depends on the availability of contributors. -
-
- We appreciate your support as we continue to work on keeping MudBlazor the premiere UI library for Blazor. -
-
-
- - - - - MudBlazor thrives thanks to our amazing community. Whether you specialize in C#, Blazor, JavaScript, CSS, documentation, testing, or design, your help is always welcome. -
-
- If you’re interested in contributing, please check out - our contribution guidelines to get started. -
-
- You can also open an issue, start a discussion, or tag a member of the team in relevant - GitHub issues to collaborate with us. + For detailed migration information, please see the v8.0.0 Migration Guide.
diff --git a/src/MudBlazor.Docs/Pages/Components/Drawer/DrawerPage.razor b/src/MudBlazor.Docs/Pages/Components/Drawer/DrawerPage.razor index 41f2f44128db..9f0180b24b80 100644 --- a/src/MudBlazor.Docs/Pages/Components/Drawer/DrawerPage.razor +++ b/src/MudBlazor.Docs/Pages/Components/Drawer/DrawerPage.razor @@ -63,8 +63,10 @@ - The Mini variant is a variation of the Responsive Drawer. It will responsively shrink to a slim band of icons (default 56px) according do its breakpoint configuration. - Mini Drawers currently only have built-in style support for MudNavLinks. + The Mini variant is a streamlined version of the Responsive Drawer. It automatically shrinks to a narrow strip (default width: 56px) according to its breakpoint configuration. +
Currently, Mini Drawers have built-in style support only for MudNavLink components. + To control whether the Mini Drawer is open or closed, use the Open parameter. +
To disable automatic responsiveness and manage the open state manually, set Breakpoint="Breakpoint.None".
diff --git a/src/MudBlazor.Docs/Pages/Components/Drawer/Examples/DrawerMiniExample.razor b/src/MudBlazor.Docs/Pages/Components/Drawer/Examples/DrawerMiniExample.razor index d68267af36a5..39a4afc7eeba 100644 --- a/src/MudBlazor.Docs/Pages/Components/Drawer/Examples/DrawerMiniExample.razor +++ b/src/MudBlazor.Docs/Pages/Components/Drawer/Examples/DrawerMiniExample.razor @@ -2,7 +2,7 @@ - + Store Library @@ -23,4 +23,4 @@ { _open = !_open; } -} \ No newline at end of file +} diff --git a/src/MudBlazor.Docs/Pages/Components/Field/FieldPage.razor b/src/MudBlazor.Docs/Pages/Components/Field/FieldPage.razor index 7e9e5755d677..c9399c7b15d0 100644 --- a/src/MudBlazor.Docs/Pages/Components/Field/FieldPage.razor +++ b/src/MudBlazor.Docs/Pages/Components/Field/FieldPage.razor @@ -5,8 +5,13 @@ - - + + + MudField provides the foundation for creating custom input controls with consistent styling and behavior. + It offers the same visual variants as text fields and + numeric fields while allowing you to embed any custom content. + Fields support labels, helper text, validation states, and adornments just like other input components. + @@ -14,30 +19,43 @@ - + - Set InnerPadding to false to minimize the inner padding. - It does not remove the full inner padding, but it is minimized to the absolute necessary value, to not concur with the label. + Customize the field's appearance and spacing to fit your design requirements. - - - + + + + + + Set InnerPadding="false" to minimize the internal padding around your content. + This is particularly useful when embedding components that need to fill the available space, such as radio groups or custom controls. + + + + + + + + - Ultimately you could build your own custom input controls with MudField. One step in that - direction is to define the content as a RenderFragment. This allows to set the - ChildContent to null which results in the label becoming a placeholder automatically. - Of course it makes a lot of sense to add some kind of input in the content like we did in this example with a - native color picker. + Build custom input controls by leveraging MudField's flexible content system. When ChildContent is null, + the label automatically becomes a placeholder, enabling dynamic behavior based on content state. + This example demonstrates creating a custom color picker input using native HTML controls within a MudField wrapper. + + Related Components: For ready-made input controls, see TextField and + NumericField which are built on top of MudField. + diff --git a/src/MudBlazor.Docs/Pages/Components/FileUpload/Examples/FileUploadDragAndDropCustomScenarioExample.razor b/src/MudBlazor.Docs/Pages/Components/FileUpload/Examples/FileUploadDragAndDropCustomScenarioExample.razor index 365b77437665..56c2ed8e87be 100644 --- a/src/MudBlazor.Docs/Pages/Components/FileUpload/Examples/FileUploadDragAndDropCustomScenarioExample.razor +++ b/src/MudBlazor.Docs/Pages/Components/FileUpload/Examples/FileUploadDragAndDropCustomScenarioExample.razor @@ -2,14 +2,24 @@ @inject ISnackbar Snackbar + +
- + - When you bind value types, the numeric field will not be empty even if the user hasn't entered a value yet because a value type always has a value, even when unassigned. - The two-way-bindable Value property will automatically assume the default value of that type (i.e. 0 for int).
- Thus, if you want your numeric fields to be empty, as long as nothing has been entered yet or after the field has been cleared, use the nullable version of that type (i.e. int?).
- Do not assign null values to Min, Max and Step. + Numeric fields support different data binding patterns depending on your requirements for default values and empty states.
- - - + + + + + + Value types always have a default value (e.g., 0 for int), so fields won't appear empty initially. + Use nullable types (e.g., int?) when you want fields to start empty until the user enters a value. + + Tip: Do not assign null values to Min, Max and Step properties. + + + + + + + + + + + + By default, numeric fields update the bound value on Enter or when focus is lost. Set Immediate="true" to update values as the user types. + You can also use DebounceInterval to delay updates until the user stops typing, preventing excessive updates during input. The debounced example updates 500ms after typing stops. + + Note: Arrow keys and Shift + mouse wheel interactions are not debounced for immediate responsiveness. + + + + + + + + +
- + - By default, MudNumericField updates the bound value on Enter or when it loses focus. Set Immediate="true" to update the value whenever the user types.
- You can also set the DebounceInterval parameter to the number of milliseconds you want to wait before updating the bound value. If you need to know when the interval elapses, you can pass an OnDebounceIntervalElapsed EventCallback. - Notice how in this example the debounced text only updates 500 ms after you stop typing. - Warning: Pressing Arrow Up/Down or Shift + MouseWheel are not debounced. + Customize how numeric values are displayed and parsed to match different cultural conventions and formatting requirements.
- - + + + + For Floating Point Values: When using string literals for Min, Max or Step, + add a decimal point (e.g., 0.0) or suffix (e.g., 0.5M for decimal) to avoid compilation errors. +
- + - You can change MudNumericField's value (by step) with Shift + MouseWheel. - You can also set the InvertMouseWheel parameter to reverse the mouse wheel up and down event. + Enhance user experience by allowing value changes via mouse wheel. Hold Shift while scrolling to increment or decrement values by the configured step amount. + Use InvertMouseWheel="true" to reverse the scroll direction if desired. diff --git a/src/MudBlazor.Docs/Pages/Components/Overlay/Examples/OverlayPositionExample.razor b/src/MudBlazor.Docs/Pages/Components/Overlay/Examples/OverlayPositionExample.razor new file mode 100644 index 000000000000..4b10969d66fb --- /dev/null +++ b/src/MudBlazor.Docs/Pages/Components/Overlay/Examples/OverlayPositionExample.razor @@ -0,0 +1,47 @@ +@namespace MudBlazor.Docs.Examples + + + + + Open Calendar with Override + + + Open Calendar without Override + + + + + + + + +@code { + private bool _isPopoverOpen = false; + private DateTime? _selectedDate { get; set; } = DateTime.Today; + private string _className = string.Empty; + + private void TogglePopover(bool overRide) + { + if (overRide) + { + _className = "mud-skip-overlay-section"; + } + else + { + _className = string.Empty; + } + _isPopoverOpen = !_isPopoverOpen; + } +} diff --git a/src/MudBlazor.Docs/Pages/Components/Overlay/OverlayPage.razor b/src/MudBlazor.Docs/Pages/Components/Overlay/OverlayPage.razor index c037a2a9edce..dd6f4522e2b6 100644 --- a/src/MudBlazor.Docs/Pages/Components/Overlay/OverlayPage.razor +++ b/src/MudBlazor.Docs/Pages/Components/Overlay/OverlayPage.razor @@ -1,7 +1,8 @@ @page "/components/overlay" - + + @@ -59,5 +60,24 @@ + + + +

+ By default, MudOverlay is automatically placed inside the MudPopoverProvider and supports + only a single instance, with the most recently created instance taking precedence over previous and scaffolding back down as they close. +

+ However, this behavior can be overridden in the following ways: +
    +
  1. 1. Set Absolute="true" to constrain the overlay to a specific section of the page.
  2. +
  3. 2. Apply the mud-skip-overlay-section class to exclude an overlay from the singleton effect.
  4. +
  5. 3. Provide ChildContent directly within MudOverlay to display custom content.
  6. +
+
+
+ + + +
diff --git a/src/MudBlazor.Docs/Pages/Components/Rating/Examples/RatingTestExample.razor b/src/MudBlazor.Docs/Pages/Components/Rating/Examples/RatingTestExample.razor deleted file mode 100644 index e0fedd85cfd4..000000000000 --- a/src/MudBlazor.Docs/Pages/Components/Rating/Examples/RatingTestExample.razor +++ /dev/null @@ -1,56 +0,0 @@ -@namespace MudBlazor.Docs.Examples - -@*I delete this file later*@ - - - -

Default

- -

More Values

- -

Disabled

- -

Custom Icons, Color

- -
-

Size

- - - -
-
-

Hover feedback

- - @GetLabelText() -
- -
-

Normal

- -
- -
-

Custom styles

- -
- -
- -@code { - private int selectedVal = 0; - private int? activeVal; - - private void HandleSelectedValueChanged(int val) => selectedVal = val; - - private void HandleHoveredValueChanged(int? val) => activeVal = val; - - private string GetLabelText() => (activeVal ?? selectedVal) switch - { - 1 => "Very bad", - 2 => "Bad", - 3 => "Sufficient", - 4 => "Good", - 5 => "Awesome!", - _ => "Rate our product!" - }; -} \ No newline at end of file diff --git a/src/MudBlazor.Docs/Pages/Components/Tabs/Examples/TabsDragAndDropExample.razor b/src/MudBlazor.Docs/Pages/Components/Tabs/Examples/TabsDragAndDropExample.razor index df8444ed93b0..f7e18965956d 100644 --- a/src/MudBlazor.Docs/Pages/Components/Tabs/Examples/TabsDragAndDropExample.razor +++ b/src/MudBlazor.Docs/Pages/Components/Tabs/Examples/TabsDragAndDropExample.razor @@ -14,7 +14,7 @@ Tab Four - " + Tab Five diff --git a/src/MudBlazor.Docs/Pages/Components/Tabs/TabsPage.razor b/src/MudBlazor.Docs/Pages/Components/Tabs/TabsPage.razor index a577998c5acf..4d650166a153 100644 --- a/src/MudBlazor.Docs/Pages/Components/Tabs/TabsPage.razor +++ b/src/MudBlazor.Docs/Pages/Components/Tabs/TabsPage.razor @@ -121,7 +121,8 @@ Tab reordering can be enabled by setting EnableDragAndDrop to true. When enabled, users can rearrange tabs by dragging them to new positions. This is useful for dynamic interfaces where the number or order of tabs may change. - The example below demonstrates drag-and-drop with a variable number of tabs that can be reordered interactively at various positions. + The example below demonstrates drag-and-drop with a variable number of tabs that can be reordered interactively. + An event is available that fires after a drag-and-drop operation is completed: OnItemDropped, which contains the original details of the operation. diff --git a/src/MudBlazor.Docs/Pages/Components/TextField/TextFieldPage.razor b/src/MudBlazor.Docs/Pages/Components/TextField/TextFieldPage.razor index 78f047dc4b83..729f64771065 100644 --- a/src/MudBlazor.Docs/Pages/Components/TextField/TextFieldPage.razor +++ b/src/MudBlazor.Docs/Pages/Components/TextField/TextFieldPage.razor @@ -5,8 +5,9 @@ - + + Text fields allow users to enter text input. MudBlazor provides three visual variants: Text (standard), Filled, and Outlined. Filled text fields naturally draw more attention, making them ideal for dialogs and short forms where their visual emphasis is beneficial. In contrast, outlined text fields have a subtler appearance, which helps simplify the layout in longer forms by reducing visual clutter. @@ -17,32 +18,18 @@ - - + + + These are the most frequently used properties that control the basic behavior and appearance of text fields. + - - - With the Typo property you can control the typography of the text field. - - - - - - - - - With the Margin property you can reduce the text field height. - - - - - - - + + Helper text provides additional context or instructions below the text field. It helps users understand what to enter or provides formatting guidance. + @@ -51,7 +38,9 @@ - With the HelperTextOnFocus property set to true, the helper text will only display on focus. + + When HelperTextOnFocus is enabled, the helper text only appears when the field is focused, reducing visual clutter while still providing guidance when needed. + @@ -59,8 +48,10 @@ - - + + + Disabled text fields prevent user interaction and are typically used when a field should not be editable under certain conditions. + @@ -69,7 +60,9 @@ - + + Read-only text fields display data that users can see and select but cannot modify. The field remains interactive for copying text. + @@ -77,11 +70,13 @@ - - With the ShrinkLabel property set to true, the label will not move into the field when empty. + + + Enable the Clearable property to add a clear button that allows users to quickly empty the text field. This works alongside other adornments. + - - + + @@ -89,85 +84,100 @@ - + - If you set the Counter prop to any int, the counter will be display at the bottom of the textfield.
- Using a specific number will show the desired max while setting it to 0 will only show the current count.
- Add MaxLength to force a max count directly on the input and use Validation to validate the data. + Customize the visual appearance of text fields to match your design requirements.
- - - -
- - - - This can be used to add a prefix or a suffix. Text, Icon or Icon Button. For WCAG standards for buttons, an AdornmentAriaLabel can be added to use as the aria-label. - - - - + - - The color of the adornment can be changed separately from the text field. + + + Use the Margin="Margin.Dense" property to reduce the text field height for compact layouts. + - - + + - - + + + Control the text appearance with the Typo property to match different content hierarchies. + - - + + - - + + + When ShrinkLabel is enabled, the label remains in its reduced size position and doesn't move when the field is empty. + - - + + + + + + + + + Adornments allow you to add icons, text, or buttons to the start or end of text fields. They're perfect for adding context, actions, or visual cues. + + + + + + + - - + + + The color of adornments can be customized independently from the text field using the AdornmentColor property. + - - + + + - - + + + Display character counts and enforce length limits to help users stay within content boundaries. Set Counter to show the count, + and combine with MaxLength to enforce limits at the input level. + - - + + - - + + + Text fields support comprehensive data binding patterns for different scenarios and data types. + - + - + - The following text fields are bound against the properties of a POCO (Plain old C-Sharp Object). Edit them to see the model change. Reset the model and see the textfields change. - Note: always use two-way bindings (@("@bind-Value")) with textfields. - Note: only on BSS, the parameter TextUpdateSuppression prevents the text from being updated via a bound value while the input is focused. Defaults to true. + Bind text fields to properties of objects (POCOs). Changes in the fields automatically update the model, and model changes reflect in the fields. + Note: Always use two-way bindings (@("@bind-Value")) with text fields. + Note: The TextUpdateSuppression parameter prevents text updates via bound values while the input is focused. Defaults to true. @@ -178,9 +188,8 @@ - When you bind value types, the text field will not be empty even if the user hasn't entered a value yet because a value type always has a value, even when unassigned. - The two-way-bindable Value property will automatically assume the default value of that type (i.e. 0 for int).
- So if you want your text fields to be empty as long as nothing has been entered yet, use the nullable version of that type (i.e. int?). + Value types always have a default value (e.g., 0 for int), so text fields won't appear empty initially. + Use nullable types (e.g., int?) when you want fields to start empty until the user enters a value.
@@ -189,23 +198,43 @@
- + - By default, MudTextField updates the bound value on Enter or when it loses focus. Set Immediate="true" to update the value whenever the user types.
- You can also set the DebounceInterval parameter to the number of milliseconds you want to wait before updating the bound value. If you need to know when the interval elapses, you can pass an OnDebounceIntervalElapsed EventCallback. - Notice how in this example the debounced text only updates 500 ms after you stop typing. + By default, text fields update on Enter or blur. Use Immediate="true" for real-time updates, or set DebounceInterval + to delay updates until the user stops typing. The debounced example updates 500ms after typing stops.
+
+ + + + You can change the InputType of MudTextField to use the native browser implementation of the + HTML input element. + Note that any Placeholder will be ignored where the browser provides a default placeholder. +
+
+ All inputs can be bound to string types; alternatively, input types Date and DateTimeLocal + can be bound to a nullable DateTime?. When binding to a DateTime? you must set the Format property to yyyy-MM-dd for input type Date, and you + must set the Format property to s (ISO 8601) for input type DateTimeLocal. +
+
+ + + +
+ - + + Text fields can be expanded to accommodate multiple lines of text by setting the Lines property. This is useful for longer text input like comments, descriptions, or messages. + @@ -232,35 +261,7 @@ - - - You can change the InputType of MudTextField to use the native browser implementation of the - HTML input element. - Note that any Placeholder will be ignored where the browser provides a default placeholder. -
-
- All inputs can be bound to string types; alternatively, input types Date and DateTimeLocal - can be bound to a nullable DateTime?. When binding to a DateTime? you must set the Format property to yyyy-MM-dd for input type Date, and you - must set the Format property to s (ISO 8601) for input type DateTimeLocal. - -
-
- - - -
- - - - MudInput a building block of MudTextField without label or helper text. - - - - - - - - + If you set the Mask property, the text field will apply formatting rules or input restrictions on-the-fly while the user is typing. @@ -280,5 +281,60 @@
+ + + + Text fields provide methods for programmatically controlling focus and text selection. These are useful for creating better user experiences and accessibility features. + + + + + + + + Use the FocusAsync() method to programmatically set focus to a text field. This is particularly useful for form validation feedback or guiding user attention. + + + + + + + + + + + The SelectAsync() method selects all text in the field, while SelectRangeAsync() allows you to select specific character ranges. + + + + + + + + + + + Select specific ranges of text using SelectRangeAsync(start, end). This example selects characters 5-10 when you click the button. + + + + + + + + + + + + + + MudInput is the underlying component that powers MudTextField, providing a simpler interface without labels or helper text for when you need basic input functionality. + + + + + + +
diff --git a/src/MudBlazor.Docs/Services/Notifications/InMemoryNotificationService.cs b/src/MudBlazor.Docs/Services/Notifications/InMemoryNotificationService.cs index 5819493f5f73..8695d7ee154b 100644 --- a/src/MudBlazor.Docs/Services/Notifications/InMemoryNotificationService.cs +++ b/src/MudBlazor.Docs/Services/Notifications/InMemoryNotificationService.cs @@ -89,8 +89,8 @@ public void Preload() { _messages.Add(new NotificationMessage( typeof(Announcement_v8_GA).Name, - "v8: Riding the Momentum of v7", - "Learn about the new major version", + "MudBlazor v8.0.0 Released", + "Major Version", "Announcement", new DateTime(2025, 01, 19), "https://github.com/MudBlazor/MudBlazor/blob/f979c2c84e3ddd5f01a20ebc1102838d32a4b01b/content/Nuget.png", @@ -100,8 +100,8 @@ public void Preload() _messages.Add(new NotificationMessage( typeof(Announcement_v7_GA).Name, - "v7 Is Here!", - "Learn about the new major version", + "MudBlazor v7.0.0 Released", + "Major Version", "Announcement", new DateTime(2024, 06, 29), "https://github.com/MudBlazor/MudBlazor/blob/f979c2c84e3ddd5f01a20ebc1102838d32a4b01b/content/Nuget.png", diff --git a/src/MudBlazor.Docs/Shared/Appbar.razor b/src/MudBlazor.Docs/Shared/Appbar.razor index 2ef0ccaae3ca..704dc1562beb 100644 --- a/src/MudBlazor.Docs/Shared/Appbar.razor +++ b/src/MudBlazor.Docs/Shared/Appbar.razor @@ -20,9 +20,6 @@ Learn More - - Official -
MudBlazor @@ -45,18 +42,27 @@
Templates
- Blazor templates loaded with MudBlazor + Blazor templates with MudBlazor - - Community - + +
+ Icon Pack +
+ Extra Material icons and symbols +
+ +
+ Translations +
+ Support for additional locales +
- Community Extensions + Extensions
- Links and Github Repositories + Community Extensions
diff --git a/src/MudBlazor.Docs/wwwroot/CommunityExtensions.json b/src/MudBlazor.Docs/wwwroot/CommunityExtensions.json index 8a23b315c92c..fa95b888a41b 100644 --- a/src/MudBlazor.Docs/wwwroot/CommunityExtensions.json +++ b/src/MudBlazor.Docs/wwwroot/CommunityExtensions.json @@ -1,8 +1,7 @@ [ { - "CategoryComment": "// Valid Categories are Parent, Components, Utility, Style, Other,", - "AvatarImageSrc": "a link to an image file for the Avatar area", - "Category": "Invalid selections are ignored, Valid options are: Parent, Components, Utility, Style, or Other", + "CategoryComment": "// Valid Categories are Components, Utility, Style, Other,", + "Category": "Invalid selections are ignored, Valid options are: Components, Utility, Style, or Other", "Name": "The name of your extension, avoid super long names if possible.", "Description": "A brief description of what the extension does for MudBlazor users", "Link": "Your preferred landing page, users will have this link and a link to github automatically generated", @@ -10,34 +9,6 @@ "GitHubRepoPath": "Your github repo" }, { - "AvatarImageSrc": "https://mudblazor.com/_content/MudBlazor.Docs/images/logo.png", - "Category": "Parent", - "Name": "MudBlazor", - "Description": "With millions of downloads, from hobby developers to large enterprises, MudBlazor enables you to rapidly build amazing web applications without leaving your beloved C# language and toolchain.", - "Link": "https://mudblazor.com", - "GitHubUserPath": "MudBlazor", - "GitHubRepoPath": "MudBlazor" - }, - { - "AvatarImageSrc": "https://mudblazor.com/_content/MudBlazor.Docs/images/logo.png", - "Category": "Parent", - "Name": "MudBlazor Translations", - "Description": "Crowdsourced translations for the MudBlazor component library.", - "Link": "https://github.com/MudBlazor/Translations", - "GitHubUserPath": "MudBlazor", - "GitHubRepoPath": "Translations" - }, - { - "AvatarImageSrc": "https://mudblazor.com/_content/MudBlazor.Docs/images/logo.png", - "Category": "Parent", - "Name": "MudBlazor Icons", - "Description": "Official Material Icon & Symbols pack for MudBlazor.", - "Link": "https://github.com/MudBlazor/MudBlazor.Icons", - "GitHubUserPath": "MudBlazor", - "GitHubRepoPath": "MudBlazor.Icons" - }, - { - "AvatarImageSrc": "https://themes.arctechonline.tech/ThemeCreator.png", "Category": "Style", "Name": "Theme Creator", "Description": "Blazor Theme Creator site for MudBlazor library. This app is designed to be used to create and manage themes for MudBlazor, not as part of your application.", @@ -46,7 +17,6 @@ "GitHubRepoPath": "ThemeCreatorMudBlazor" }, { - "AvatarImageSrc": "https://avatars.githubusercontent.com/u/65362616?s=48&v=4", "Category": "Components", "Name": "MudBlazor Markdown", "Description": "A Markdown Component for MudBlazor.", @@ -55,7 +25,6 @@ "GitHubRepoPath": "MudBlazor.Markdown" }, { - "AvatarImageSrc": "https://avatars.githubusercontent.com/u/105243816?s=48&v=4", "Category": "Components", "Name": "CodeBeam MudBlazor Extensions", "Description": "MudExtensions has 30+ components and utilities from the core library contributors. There are both unique and extended components that add additional features on current Mud components.", @@ -64,7 +33,6 @@ "GitHubRepoPath": "CodeBeam.MudBlazor.Extensions" }, { - "AvatarImageSrc": "https://raw.githubusercontent.com/fgilde/MudBlazor.Extensions/main/MudExtension.png", "Category": "Components", "Name": "Fgilde MudBlazor Extensions", "Description": "MudBlazor.Extensions is a convenient package that extends the capabilities of the MudBlazor component library. There are both unique and extended components and utilities that add additional features on current Mud components.", @@ -73,7 +41,6 @@ "GitHubRepoPath": "MudBlazor.Extensions" }, { - "AvatarImageSrc": "https://raw.githubusercontent.com/fgilde/MudBlazor.Extensions/main/MudExtension.png", "Category": "Components", "Name": "Fgilde MudEx RichTextEditor", "Description": "MudExRichTextEditor is a custom reusable control that allows us to easily consume Quill combining in a MudBlazor project Features with MudBlazor Theme Support. This compnent also works without a MudBlazor Project.", @@ -82,7 +49,6 @@ "GitHubRepoPath": "MudExRichTextEditor" }, { - "AvatarImageSrc": "https://avatars.githubusercontent.com/u/88168386?s=48&v=4", "Category": "Components", "Name": "Static Input (for SSR)", "Description": "Tailored specifically for Static Server-Side Rendered (static SSR) pages. It offers seamless integration for some of MudBlazor's Component design into your static application pages. Focusing particularly on components designed for forms and edit forms, in situations where interactive components are not feasible.", @@ -91,7 +57,6 @@ "GitHubRepoPath": "MudBlazor.StaticInput" }, { - "AvatarImageSrc": "https://avatars.githubusercontent.com/u/51314385?s=48&v=4", "Category": "Components", "Name": "Heron MudCalendar", "Description": "A simple but powerful calendar component for MudBlazor. Calendar includes multiple views (month, week, work week, and day), customizable events, and easy integration with your existing MudBlazor project.", @@ -100,7 +65,6 @@ "GitHubRepoPath": "Heron.MudCalendar" }, { - "AvatarImageSrc": "https://mudblocks.cc/assets/images/logo/favicon-512.png", "Category": "Style", "Name": "MudBlocks", "Description": "A collection of MudBlazor blocks. Predefined, reusable UI elements or layouts designed to simplify development by combining multiple components into cohesive sections; such as headers, footers, forms, cards, or dashboards.", @@ -109,7 +73,6 @@ "GitHubRepoPath": "mudblocks" }, { - "AvatarImageSrc": "https://avatars.githubusercontent.com/u/5263228?s=48&v=4", "Category": "Components", "Name": "MudBlazor PdfViewer", "Description": "A component for displaying and manipulating PDF documents.", @@ -118,7 +81,6 @@ "GitHubRepoPath": "MudBlazor.PdfViewer" }, { - "AvatarImageSrc": "https://raw.githubusercontent.com/phmatray/FormCraft/refs/heads/main/FormCraft/icon.png", "Category": "Utility", "Name": "FormCraft", "Description": "A powerful, type-safe dynamic form library for Blazor applications with fluent API design. Provides seamless integration with MudBlazor components, enabling developers to build complex forms with minimal code.", diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/0phois.MudBlazor.StaticInput.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/0phois.MudBlazor.StaticInput.webp new file mode 100644 index 000000000000..258cf0999edc Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/0phois.MudBlazor.StaticInput.webp differ diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/CodeBeamOrg.CodeBeam.MudBlazor.Extensions.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/CodeBeamOrg.CodeBeam.MudBlazor.Extensions.webp new file mode 100644 index 000000000000..72d32d238d9a Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/CodeBeamOrg.CodeBeam.MudBlazor.Extensions.webp differ diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/MyNihongo.MudBlazor.Markdown.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/MyNihongo.MudBlazor.Markdown.webp new file mode 100644 index 000000000000..c127ae916cf9 Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/MyNihongo.MudBlazor.Markdown.webp differ diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/danheron.Heron.MudCalendar.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/danheron.Heron.MudCalendar.webp new file mode 100644 index 000000000000..b3e7d7ac4131 Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/danheron.Heron.MudCalendar.webp differ diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/fgilde.MudBlazor.Extensions.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/fgilde.MudBlazor.Extensions.webp new file mode 100644 index 000000000000..fbf2689e3dbc Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/fgilde.MudBlazor.Extensions.webp differ diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/fgilde.MudExRichTextEditor.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/fgilde.MudExRichTextEditor.webp new file mode 100644 index 000000000000..fbf2689e3dbc Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/fgilde.MudExRichTextEditor.webp differ diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/mouse0270.mudblocks.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/mouse0270.mudblocks.webp new file mode 100644 index 000000000000..a52676c903ed Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/mouse0270.mudblocks.webp differ diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/phmatray.FormCraft.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/phmatray.FormCraft.webp new file mode 100644 index 000000000000..c5f06991ffb8 Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/phmatray.FormCraft.webp differ diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/tgothorp.MudBlazor.PdfViewer.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/tgothorp.MudBlazor.PdfViewer.webp new file mode 100644 index 000000000000..cf3dfa6563ee Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/tgothorp.MudBlazor.PdfViewer.webp differ diff --git a/src/MudBlazor.Docs/wwwroot/images/extensions/versile2.ThemeCreatorMudBlazor.webp b/src/MudBlazor.Docs/wwwroot/images/extensions/versile2.ThemeCreatorMudBlazor.webp new file mode 100644 index 000000000000..1b266ad5d7d0 Binary files /dev/null and b/src/MudBlazor.Docs/wwwroot/images/extensions/versile2.ThemeCreatorMudBlazor.webp differ diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridDateOnlyFilterTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridDateOnlyFilterTest.razor index 8b0b73eca422..f65e39d80afb 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridDateOnlyFilterTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridDateOnlyFilterTest.razor @@ -1,4 +1,13 @@ - + + Filter Mode: + + + + + + + + @@ -7,9 +16,11 @@ @code { - public static string __description__ = @"Test DateOnly filtering in DataGrid"; + public static string __description__ = @"Test DateOnly filtering in DataGrid with all filter modes"; public record Model(string Name, int? Age, DateOnly? HiredOn); + private DataGridFilterMode _filterMode = DataGridFilterMode.ColumnFilterRow; + private readonly IEnumerable _people = [ new("Sam", 56, new DateOnly(2020, 3, 10)), diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridFiltersTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridFiltersTest.razor index 1a19992b8c45..b6cecb85a232 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridFiltersTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/DataGrid/DataGridFiltersTest.razor @@ -8,6 +8,7 @@ + @@ -15,11 +16,11 @@ @code { private IEnumerable _items = new List() { - new Model("Sam", 56, Severity.Normal, false, null, null), - new Model("Alicia", 54, Severity.Info, null, null, new Guid("b7accfd5-928d-48ad-8a0c-9448ae37bf96")), - new Model("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2), null), - new Model("John", 32, Severity.Warning, false, null, null) + new Model("Sam", 56, Severity.Normal, false, null, new DateOnly(2020, 3, 10), null), + new Model("Alicia", 54, Severity.Info, null, null, null, new Guid("b7accfd5-928d-48ad-8a0c-9448ae37bf96")), + new Model("Ira", 27, Severity.Success, true, new DateTime(2011, 1, 2), new DateOnly(2011, 1, 2), null), + new Model("John", 32, Severity.Warning, false, null, new DateOnly(2022, 6, 15), null) }; - public record Model (string Name, int? Age, Severity? Status, bool? Hired, DateTime? HiredOn, Guid? ApplicationId); + public record Model (string Name, int? Age, Severity? Status, bool? Hired, DateTime? HiredOn, DateOnly? StartDate, Guid? ApplicationId); } diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Dialog/DialogOkCancel.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Dialog/DialogOkCancel.razor index f92d8e475e57..fac8419e7df8 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Dialog/DialogOkCancel.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Dialog/DialogOkCancel.razor @@ -1,4 +1,4 @@ - + Wabalabadubdub! diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/Dialog/TestInlineDialog.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/Dialog/TestInlineDialog.razor index ae069a06b536..950f7394f0fa 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/Dialog/TestInlineDialog.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/Dialog/TestInlineDialog.razor @@ -2,7 +2,7 @@ Open - + Wabalabadubdub! @@ -26,4 +26,4 @@ return DialogService.ShowMessageBox(title: "hello from inline", message: "BUG4871", yesText: "BUG4871"); } -} \ No newline at end of file +} diff --git a/src/MudBlazor.UnitTests.Viewer/TestComponents/FileUpload/FileUploadWithDragAndDropActivatorTest.razor b/src/MudBlazor.UnitTests.Viewer/TestComponents/FileUpload/FileUploadWithDragAndDropActivatorTest.razor index 0e9c0f8b2202..2693d6a56733 100644 --- a/src/MudBlazor.UnitTests.Viewer/TestComponents/FileUpload/FileUploadWithDragAndDropActivatorTest.razor +++ b/src/MudBlazor.UnitTests.Viewer/TestComponents/FileUpload/FileUploadWithDragAndDropActivatorTest.razor @@ -1,13 +1,22 @@ @using System.IO + +