mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-07-08 18:16:08 +00:00
Mirror the spreadsheet grid in right-to-left layouts: column A on the right, columns flowing leftward, row headers and the vertical scrollbar on the left. All direction logic lives in JS and CSS; the C# render path stays direction-agnostic: - Position cells, headers and overlays with logical insets (inset-inline-start / inset-block-start) instead of transform: translate, so the browser mirrors the grid using the unchanged logical coordinates. - Mirror pointer clientX/offsetX and normalize scrollLeft in JS so the existing C# pointer and scroll math need no changes. - Convert physical CSS (borders, text-align, chevron, validation triangle, resize cursors) to logical properties; flip the merged/active-cell selection mask via a [dir=rtl] rule.
125 lines
3.5 KiB
C#
125 lines
3.5 KiB
C#
using System;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Radzen.Blazor.Rendering;
|
|
|
|
#nullable enable
|
|
using Radzen.Documents.Spreadsheet;
|
|
namespace Radzen.Blazor.Spreadsheet;
|
|
|
|
/// <summary>
|
|
/// Renders a data validation input prompt near the selected cell.
|
|
/// </summary>
|
|
public partial class InputPrompt : IDisposable
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the sheet.
|
|
/// </summary>
|
|
[Parameter]
|
|
public Worksheet Worksheet { get; set; } = default!;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the virtual grid context.
|
|
/// </summary>
|
|
[Parameter]
|
|
public IVirtualGridContext Context { get; set; } = default!;
|
|
|
|
private bool visible;
|
|
private CellRef cell = CellRef.Invalid;
|
|
private string? title;
|
|
private string? message;
|
|
private string? style;
|
|
private string? className;
|
|
|
|
private readonly EventBinding<Selection> selectionBinding;
|
|
private readonly EventBinding<IVirtualGridContext> contextBinding;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="InputPrompt"/> class.
|
|
/// </summary>
|
|
public InputPrompt()
|
|
{
|
|
selectionBinding = new EventBinding<Selection>(
|
|
s => s.Changed += OnSelectionChanged,
|
|
s => s.Changed -= OnSelectionChanged);
|
|
|
|
contextBinding = new EventBinding<IVirtualGridContext>(
|
|
c => c.Scrolled += OnScroll,
|
|
c => c.Scrolled -= OnScroll);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void OnParametersSet()
|
|
{
|
|
selectionBinding.Bind(Worksheet?.Selection);
|
|
contextBinding.Bind(Context);
|
|
}
|
|
|
|
private void OnSelectionChanged()
|
|
{
|
|
visible = false;
|
|
title = null;
|
|
message = null;
|
|
cell = CellRef.Invalid;
|
|
|
|
if (Worksheet is not null)
|
|
{
|
|
var address = Worksheet.Selection.Cell;
|
|
|
|
if (address != CellRef.Invalid
|
|
&& !(Worksheet.Cells.TryGet(address.Row, address.Column, out var cellData) && cellData.HasValidationErrors))
|
|
{
|
|
var validators = Worksheet.Validation.GetValidatorsForCell(address);
|
|
|
|
foreach (var v in validators)
|
|
{
|
|
if (v is DataValidationRule rule && rule.ShowInputMessage)
|
|
{
|
|
title = rule.InputTitle;
|
|
message = rule.InputMessage;
|
|
visible = true;
|
|
cell = address;
|
|
Render();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
StateHasChanged();
|
|
}
|
|
|
|
private void OnScroll()
|
|
{
|
|
if (visible)
|
|
{
|
|
visible = false;
|
|
cell = CellRef.Invalid;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private void Render()
|
|
{
|
|
if (cell == CellRef.Invalid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var rect = Context.GetRectangle(cell.Row, cell.Column);
|
|
var left = rect.Left + 4;
|
|
var top = rect.Top + rect.Height + 2;
|
|
style = $"inset-inline-start: {left.ToPx()}; inset-block-start: {top.ToPx()};";
|
|
|
|
className = ClassList.Create("rz-spreadsheet-input-prompt")
|
|
.Add("rz-spreadsheet-frozen-column", Worksheet is not null && cell.Column < Worksheet.Columns.Frozen)
|
|
.Add("rz-spreadsheet-frozen-row", Worksheet is not null && cell.Row < Worksheet.Rows.Frozen)
|
|
.ToString();
|
|
}
|
|
|
|
void IDisposable.Dispose()
|
|
{
|
|
selectionBinding.Dispose();
|
|
contextBinding.Dispose();
|
|
}
|
|
}
|