Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ class App : Component
}

static Element NavBtn(string label, string current, Action<string> set) =>
Button(label, () => set(label)).Disabled(label == current);
Button(label, () => set(label)).IsEnabled(!(label == current));
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs/_pipeline/ai-author-skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ case (no deps); `Memo(ctx => …, deps)` to also re-render when any dep changes;
`.Background(color|ThemeRef)`, `.Foreground(color|ThemeRef)`,
`.CornerRadius(n)`, `.WithBorder(color|ThemeRef, thickness?)`,
`.HAlign(alignment)`, `.VAlign(alignment)`,
`.Disabled(bool)`, `.Visible(bool)`, `.WithKey(string)`,
`.IsEnabled(!bool)`, `.IsVisible(bool)`, `.WithKey(string)`,
`.Flex(grow?, shrink?, basis?)`, `.ToolTip(string)`,
`.FocusTrap(FocusTrapHandle)`,
`.Set(control => { /* raw WinUI access */ })`
Expand Down
2 changes: 1 addition & 1 deletion docs/_pipeline/apps/accessibility/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public override Element Render()
CheckBox(agree, setAgree, label: "I accept the terms")
.TabIndex(3),
Button("Register", () => { })
.Disabled(!valid).TabIndex(4).AccessKey("R")
.IsEnabled(valid).TabIndex(4).AccessKey("R")
).Landmark(AutomationLandmarkType.Form).Padding(24);
}
}
Expand Down
6 changes: 3 additions & 3 deletions docs/_pipeline/apps/forms/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ public override Element Render()
// commit-on-keystroke, so validation reacts as the user types.
NumberBox(age, setAge, header: "Age").Immediate(),

// .DisabledFocusable() keeps the button tab-reachable and
// .IsDisabledFocusable() keeps the button tab-reachable and
// visually dimmed while preventing invocation. Pattern mirrors
// Fluent UI's `disabledFocusable` and ARIA `aria-disabled`.
Button("Submit", () => { /* submit */ })
.DisabledFocusable(!formValid)
.IsDisabledFocusable(!formValid)
.Margin(0, 8, 0, 0)
).Padding(24);
}
Expand Down Expand Up @@ -162,7 +162,7 @@ public override Element Render()
{
ctx.MarkAllTouched();
if (ctx.IsValid()) setSubmitted(true);
}).Disabled(submitted),
}).IsEnabled(!submitted),
When(submitted, () =>
TextBlock("Registration successful!")
.Foreground(Theme.SystemSuccess).SemiBold())
Expand Down
12 changes: 6 additions & 6 deletions docs/_pipeline/apps/navigation/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public override Element Render()
Button("Settings", () => nav.Navigate(Route.Settings)),
Button("Profile", () => nav.Navigate(Route.Profile)),
Button("Back", () => nav.GoBack())
.Disabled(!nav.CanGoBack)
.IsEnabled(nav.CanGoBack)
),
NavigationHost(nav, route => route switch
{
Expand Down Expand Up @@ -101,9 +101,9 @@ public override Element Render()
Button("Reset", () =>
nav.Reset(Route.Home)),
Button("Back", () => nav.GoBack())
.Disabled(!nav.CanGoBack),
.IsEnabled(nav.CanGoBack),
Button("Forward", () => nav.GoForward())
.Disabled(!nav.CanGoForward)
.IsEnabled(nav.CanGoForward)
),
NavigationHost(nav, route =>
TextBlock($"Page: {route}")
Expand Down Expand Up @@ -158,7 +158,7 @@ public override Element Render()
Button("Settings", () => nav.Navigate(Route.Settings)),
Button("Profile", () => nav.Navigate(Route.Profile)),
Button("Back", () => nav.GoBack())
.Disabled(!nav.CanGoBack)
.IsEnabled(nav.CanGoBack)
),
NavigationHost(nav, route => route switch
{
Expand Down Expand Up @@ -256,7 +256,7 @@ public override Element Render()
{
if (savedState is not null)
nav.SetState(savedState);
}).Disabled(savedState is null)
}).IsEnabled(!(savedState is null))
),
TextBlock($"Current: {nav.CurrentRoute}"),
TextBlock($"Saved: {savedState?[..Math.Min(50, savedState?.Length ?? 0)] ?? "(none)"}")
Expand Down Expand Up @@ -322,7 +322,7 @@ public override Element Render()
Button("Home", () => nav.Navigate(Route.Home)),
Button("Settings", () => nav.Navigate(Route.Settings)),
Button("Back", () => nav.GoBack())
.Disabled(!nav.CanGoBack)
.IsEnabled(nav.CanGoBack)
),
NavigationHost(nav, route => route switch
{
Expand Down
2 changes: 1 addition & 1 deletion docs/_pipeline/apps/todo-app/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public override Element Render()
updateItems(list => [.. list, new TodoItem(newText.Trim(), false)]);
setNewText("");
}
}).Disabled(string.IsNullOrWhiteSpace(newText))
}).IsEnabled(!(string.IsNullOrWhiteSpace(newText)))
),

// Item list
Expand Down
2 changes: 1 addition & 1 deletion docs/_pipeline/apps/xaml-developers/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public override Element Render()
TextField(email, setEmail, header: "Email"),
CheckBox(wantsUpdates, setWantsUpdates, label: "Email me updates"),
HStack(8,
Button("Save", () => { }).Disabled(!canSave),
Button("Save", () => { }).IsEnabled(canSave),
TextBlock(canSave ? "Ready to save" : "Complete all required fields")
.Opacity(0.7)
)
Expand Down
8 changes: 4 additions & 4 deletions docs/_pipeline/templates/forms.md.dt
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Reactor offers two opt-in fixes for this. They compose:

![Keep submit reachable](screenshot://forms/keep-submit-reachable)

**`.DisabledFocusable(bool)` on Button** keeps the button keyboard-focusable
**`.IsDisabledFocusable(bool)` on Button** keeps the button keyboard-focusable
and tab-reachable while presenting it as disabled (dimmed; the click is
suppressed). Mirrors Fluent UI React's `disabledFocusable` and ARIA's
`aria-disabled`. Use it for any Submit gated on validation, busy state, or
Expand All @@ -152,14 +152,14 @@ the right choice when an intermediate value would be expensive or surprising
(snapping `2.50` to `2.5` mid-edit). Apply when validation gates UI state
and you want it to feel live.

Use `.DisabledFocusable()` whenever a button is conditionally disabled in a
Use `.IsDisabledFocusable()` whenever a button is conditionally disabled in a
form — even if you've also applied `.Immediate()` to every commit-on-blur
input. The two cover different failure modes: `.Immediate()` keeps validity
in sync with typing; `.DisabledFocusable()` keeps the button discoverable
in sync with typing; `.IsDisabledFocusable()` keeps the button discoverable
when validity is gated on async checks, required-but-untouched fields,
cross-field rules, or any derived condition that can't be made instantaneous.

> **Where not to use `.DisabledFocusable()`:** only buttons. For data-entry
> **Where not to use `.IsDisabledFocusable()`:** only buttons. For data-entry
> controls (`TextField`, `NumberBox`, `CheckBox`, etc.), `IsEnabled=false`
> usually means "this field isn't part of your current task" (cascading
> from another input), and tab-skipping is the correct UX. Use
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/accessibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class AccessibleFormDemo : Component
CheckBox(agree, setAgree, label: "I accept the terms")
.TabIndex(3),
Button("Register", () => { })
.Disabled(!valid).TabIndex(4).AccessKey("R")
.IsEnabled(valid).TabIndex(4).AccessKey("R")
).Landmark(AutomationLandmarkType.Form).Padding(24);
}
}
Expand Down
14 changes: 7 additions & 7 deletions docs/guide/forms.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,11 @@ class KeepSubmitReachableDemo : Component
// commit-on-keystroke, so validation reacts as the user types.
NumberBox(age, setAge, header: "Age").Immediate(),

// .DisabledFocusable() keeps the button tab-reachable and
// .IsDisabledFocusable() keeps the button tab-reachable and
// visually dimmed while preventing invocation. Pattern mirrors
// Fluent UI's `disabledFocusable` and ARIA `aria-disabled`.
Button("Submit", () => { /* submit */ })
.DisabledFocusable(!formValid)
.IsDisabledFocusable(!formValid)
.Margin(0, 8, 0, 0)
).Padding(24);
}
Expand All @@ -259,7 +259,7 @@ class KeepSubmitReachableDemo : Component

![Keep submit reachable](images/forms/keep-submit-reachable.png)

**`.DisabledFocusable(bool)` on Button** keeps the button keyboard-focusable
**`.IsDisabledFocusable(bool)` on Button** keeps the button keyboard-focusable
and tab-reachable while presenting it as disabled (dimmed; the click is
suppressed). Mirrors Fluent UI React's `disabledFocusable` and ARIA's
`aria-disabled`. Use it for any Submit gated on validation, busy state, or
Expand All @@ -273,14 +273,14 @@ the right choice when an intermediate value would be expensive or surprising
(snapping `2.50` to `2.5` mid-edit). Apply when validation gates UI state
and you want it to feel live.

Use `.DisabledFocusable()` whenever a button is conditionally disabled in a
Use `.IsDisabledFocusable()` whenever a button is conditionally disabled in a
form — even if you've also applied `.Immediate()` to every commit-on-blur
input. The two cover different failure modes: `.Immediate()` keeps validity
in sync with typing; `.DisabledFocusable()` keeps the button discoverable
in sync with typing; `.IsDisabledFocusable()` keeps the button discoverable
when validity is gated on async checks, required-but-untouched fields,
cross-field rules, or any derived condition that can't be made instantaneous.

> **Where not to use `.DisabledFocusable()`:** only buttons. For data-entry
> **Where not to use `.IsDisabledFocusable()`:** only buttons. For data-entry
> controls (`TextField`, `NumberBox`, `CheckBox`, etc.), `IsEnabled=false`
> usually means "this field isn't part of your current task" (cascading
> from another input), and tab-skipping is the correct UX. Use
Expand Down Expand Up @@ -324,7 +324,7 @@ class ValidationContextDemo : Component
{
ctx.MarkAllTouched();
if (ctx.IsValid()) setSubmitted(true);
}).Disabled(submitted),
}).IsEnabled(!submitted),
When(submitted, () =>
TextBlock("Registration successful!")
.Foreground(Theme.SystemSuccess).SemiBold())
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ class TodoApp : Component
updateItems(list => [.. list, new TodoItem(newText.Trim(), false)]);
setNewText("");
}
}).Disabled(string.IsNullOrWhiteSpace(newText))
}).IsEnabled(!(string.IsNullOrWhiteSpace(newText)))
),

// Item list
Expand Down
12 changes: 6 additions & 6 deletions docs/guide/navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class BasicNavDemo : Component
Button("Settings", () => nav.Navigate(Route.Settings)),
Button("Profile", () => nav.Navigate(Route.Profile)),
Button("Back", () => nav.GoBack())
.Disabled(!nav.CanGoBack)
.IsEnabled(nav.CanGoBack)
),
NavigationHost(nav, route => route switch
{
Expand Down Expand Up @@ -163,9 +163,9 @@ class StackOperationsDemo : Component
Button("Reset", () =>
nav.Reset(Route.Home)),
Button("Back", () => nav.GoBack())
.Disabled(!nav.CanGoBack),
.IsEnabled(nav.CanGoBack),
Button("Forward", () => nav.GoForward())
.Disabled(!nav.CanGoForward)
.IsEnabled(nav.CanGoForward)
),
NavigationHost(nav, route =>
TextBlock($"Page: {route}")
Expand Down Expand Up @@ -272,7 +272,7 @@ class PageTransitionsDemo : Component
Button("Settings", () => nav.Navigate(Route.Settings)),
Button("Profile", () => nav.Navigate(Route.Profile)),
Button("Back", () => nav.GoBack())
.Disabled(!nav.CanGoBack)
.IsEnabled(nav.CanGoBack)
),
NavigationHost(nav, route => route switch
{
Expand Down Expand Up @@ -411,7 +411,7 @@ class PageCachingDemo : Component
Button("Home", () => nav.Navigate(Route.Home)),
Button("Settings", () => nav.Navigate(Route.Settings)),
Button("Back", () => nav.GoBack())
.Disabled(!nav.CanGoBack)
.IsEnabled(nav.CanGoBack)
),
NavigationHost(nav, route => route switch
{
Expand Down Expand Up @@ -514,7 +514,7 @@ class StateSerializationDemo : Component
{
if (savedState is not null)
nav.SetState(savedState);
}).Disabled(savedState is null)
}).IsEnabled(!(savedState is null))
),
TextBlock($"Current: {nav.CurrentRoute}"),
TextBlock($"Saved: {savedState?[..Math.Min(50, savedState?.Length ?? 0)] ?? "(none)"}")
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/xaml-developers.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class TutorialFormPage : Component
TextField(email, setEmail, header: "Email"),
CheckBox(wantsUpdates, setWantsUpdates, label: "Email me updates"),
HStack(8,
Button("Save", () => { }).Disabled(!canSave),
Button("Save", () => { }).IsEnabled(canSave),
TextBlock(canSave ? "Ready to save" : "Complete all required fields")
.Opacity(0.7)
)
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/async-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ cause a flicker on the next render.
Overlapping `RunAsync` calls each get their own `callCts`; both complete in
completion order. There is no built-in serialization — if the caller wants
"only one in flight at a time," they gate the `RunAsync` invocation
themselves (e.g., `Button.Disabled(mut.IsPending)`).
themselves (e.g., `Button.IsEnabled(!mut.IsPending)`).

### 6.3 Unmount

Expand Down
2 changes: 1 addition & 1 deletion docs/specs/002-winui3-gap-analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ XY focus, and drag-drop are all missing as first-class modifiers.**
| **XamlUICommand** | Missing | Label+Icon+Accelerator+Description bundling not replicated |
| **StandardUICommand** | Missing | No pre-built Cut/Copy/Paste/Undo command objects |
| **Command property on controls** | Missing | Controls only have OnClick/OnChanged callbacks, not a Command binding point |
| **CanExecute / auto-disable** | Missing | No automatic disable-when-unavailable; `.Disabled(condition)` is manual and must be wired separately per control |
| **CanExecute / auto-disable** | Missing | No automatic disable-when-unavailable; `.IsEnabled(!condition)` is manual and must be wired separately per control |

**Verdict: Missing.** Reactor has no command abstraction. Action callbacks cover the simplest
case (click → do thing) but do not replicate what ICommand provides: a named, queryable,
Expand Down
4 changes: 2 additions & 2 deletions docs/specs/008-csharp-language-improvements.md
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,7 @@ return VStack(16) {
Text("Name"),
TextField(name, setName, placeholder: "Enter your name").Width(300)
},
Button("Submit", () => setSubmitted(true)).Disabled(!isValid)
Button("Submit", () => setSubmitted(true)).IsEnabled(isValid)
};
```

Expand Down Expand Up @@ -1879,7 +1879,7 @@ class FormDemo : Component
CheckBox(agreeToTerms, setAgree, label: "I agree to the terms"),
When(!isValid, () =>
Text("Please fill all fields and agree to terms").Opacity(0.6)),
Button("Submit", () => setSubmitted(true)).Disabled(!isValid)
Button("Submit", () => setSubmitted(true)).IsEnabled(isValid)
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/specs/020-async-resources-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ var save = UseMutation<Employee, Employee>(
OnError: (ex, e) => cache.Revert(e.Key),
InvalidateKeys: ["employees.list"]));

Button("Save", () => save.RunAsync(edited)).Disabled(save.IsPending);
Button("Save", () => save.RunAsync(edited)).IsEnabled(!save.IsPending);
```

### 8.3 Why a separate hook, not "write support on UseResource"
Expand Down
2 changes: 1 addition & 1 deletion docs/specs/026-charting-accessibility-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ LineChart(...)
```

`.Interactive()` is implicit when any of `.Pan()`, `.Zoom()`, `.Brush()`, `.OnPointInvoke()`,
or `.Selectable()` is used.
or `.IsTextSelectionEnabled()` is used.

---

Expand Down
2 changes: 1 addition & 1 deletion docs/specs/archived/cpp-native-reconciler.md
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ class CounterDemo : Component
Text($"Current count: {count}").FontSize(24).SemiBold(),
HStack(8,
Button($"- {step}", () => setCount(count - step)),
Button("Reset", () => setCount(0)).Disabled(count == 0),
Button("Reset", () => setCount(0)).IsEnabled(!(count == 0)),
Button($"+ {step}", () => setCount(count + step))
),
HStack(8,
Expand Down
8 changes: 4 additions & 4 deletions docs/specs/proposals/forms-data-entry-ideas.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ ValidationVisualizer(VisualizerStyle.InfoBar,
),

Button("Submit", HandleSubmit)
.Disabled(!UseValidationContext().IsValid())
.IsEnabled(UseValidationContext().IsValid())
)
)
```
Expand Down Expand Up @@ -637,9 +637,9 @@ return VStack(16,
HStack(12,
When(wizard.CanGoBack, () => Button("Back", wizard.GoBack)),
When(!wizard.IsLastStep, () =>
Button("Next", wizard.GoNext).Disabled(!wizard.IsCurrentStepValid)),
Button("Next", wizard.GoNext).IsEnabled(wizard.IsCurrentStepValid)),
When(wizard.IsLastStep, () =>
Button("Submit", HandleSubmit).Disabled(!wizard.IsValid))
Button("Submit", HandleSubmit).IsEnabled(wizard.IsValid))
)
);
```
Expand Down Expand Up @@ -841,7 +841,7 @@ class RegistrationForm : Component
if (result.Errors is { } errors)
foreach (var e in errors)
ctx.Add(e.Field, e.Message);
}).Disabled(!ctx.IsValid()),
}).IsEnabled(ctx.IsValid()),

When(ctx.IsDirty(), () =>
Button("Reset", () => ctx.Reset())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ values, series headers, and axis labels without any visible table.

- [x] Add `.Interactive()` modifier — turns on navigator (default off for static)
- [x] `.Interactive()` is implicit when `.Pan()`, `.Zoom()`, `.Brush()`,
`.OnPointInvoke()`, or `.Selectable()` is used
`.OnPointInvoke()`, or `.IsTextSelectionEnabled()` is used
- [x] Add `.OnPointInvoke(Action<T, int>)` for Enter/Space + click
- [x] Add `.OnBrushChanged(Action<ChartRange>)` for brush selection

Expand Down
2 changes: 1 addition & 1 deletion plugins/reactor/skills/reactor-async/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ var addTodo = UseMutation<TodoInput, Todo>(

return VStack(
Button("Add", () => _ = addTodo.RunAsync(new TodoInput("New")))
.Disabled(addTodo.IsPending));
.IsEnabled(!addTodo.IsPending));
```

- `OnOptimistic` runs synchronously on the caller. If it throws, the mutator
Expand Down
Loading
Loading