Remove pencil icon, use cursor-text to signal editable name
The hover-revealed pencil icon caused layout shift on rows with conditions. Modern UIs (Figma, Notion, Linear) rely on double-click without a visible edit icon. Replace with cursor-text on hover. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import {
|
|||||||
type ConditionId,
|
type ConditionId,
|
||||||
deriveHpStatus,
|
deriveHpStatus,
|
||||||
} from "@initiative/domain";
|
} from "@initiative/domain";
|
||||||
import { Brain, Pencil, X } from "lucide-react";
|
import { Brain, X } from "lucide-react";
|
||||||
import { type Ref, useCallback, useEffect, useRef, useState } from "react";
|
import { type Ref, useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { cn } from "../lib/utils";
|
import { cn } from "../lib/utils";
|
||||||
import { AcShield } from "./ac-shield";
|
import { AcShield } from "./ac-shield";
|
||||||
@@ -138,21 +138,10 @@ function EditableName({
|
|||||||
onTouchEnd={cancelLongPress}
|
onTouchEnd={cancelLongPress}
|
||||||
onTouchCancel={cancelLongPress}
|
onTouchCancel={cancelLongPress}
|
||||||
onTouchMove={cancelLongPress}
|
onTouchMove={cancelLongPress}
|
||||||
className="truncate text-left text-sm text-foreground hover:text-hover-neutral transition-colors"
|
className="truncate text-left text-sm text-foreground cursor-text hover:text-hover-neutral transition-colors"
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
startEditing();
|
|
||||||
}}
|
|
||||||
aria-label="Edit name"
|
|
||||||
className="hidden shrink-0 items-center text-muted-foreground hover:text-hover-neutral group-hover:inline-flex"
|
|
||||||
>
|
|
||||||
<Pencil size={14} />
|
|
||||||
</button>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ A user attempts to edit a combatant that no longer exists or provides an invalid
|
|||||||
|
|
||||||
**Story C3 — Rename trigger UX (Priority: P1)**
|
**Story C3 — Rename trigger UX (Priority: P1)**
|
||||||
|
|
||||||
A user wants to rename a combatant. Single-clicking the name opens the stat block panel instead of entering edit mode. To rename, the user double-clicks the name, clicks a hover-revealed pencil icon, or long-presses on touch devices.
|
A user wants to rename a combatant. Single-clicking the name opens the stat block panel instead of entering edit mode. To rename, the user double-clicks the name or long-presses on touch devices. A `cursor-text` cursor on hover signals that the name is editable.
|
||||||
|
|
||||||
**Acceptance Scenarios**:
|
**Acceptance Scenarios**:
|
||||||
|
|
||||||
@@ -124,13 +124,9 @@ A user wants to rename a combatant. Single-clicking the name opens the stat bloc
|
|||||||
|
|
||||||
2. **Given** a combatant row is visible, **When** the user double-clicks the combatant name, **Then** inline edit mode is entered for that combatant's name.
|
2. **Given** a combatant row is visible, **When** the user double-clicks the combatant name, **Then** inline edit mode is entered for that combatant's name.
|
||||||
|
|
||||||
3. **Given** a combatant row is visible on a pointer device, **When** the user hovers over the combatant name, **Then** a pencil icon appears next to the name.
|
3. **Given** a combatant row is visible on a pointer device, **When** the user hovers over the combatant name, **Then** the cursor changes to a text cursor (`cursor-text`) to signal editability.
|
||||||
|
|
||||||
4. **Given** the pencil icon is visible, **When** the user clicks it, **Then** inline edit mode is entered for that combatant's name.
|
4. **Given** a combatant row is visible on a touch device, **When** the user long-presses the combatant name, **Then** inline edit mode is entered for that combatant's name.
|
||||||
|
|
||||||
5. **Given** a combatant row is visible on a touch device, **When** the user long-presses the combatant name, **Then** inline edit mode is entered for that combatant's name.
|
|
||||||
|
|
||||||
6. **Given** a combatant row is visible on a touch device, **When** the user views the combatant name without hovering, **Then** no pencil icon is permanently visible.
|
|
||||||
|
|
||||||
7. **Given** inline edit mode has been entered (via any trigger), **When** the user types a new name and presses Enter or blurs the field, **Then** the name is committed. **When** the user presses Escape, **Then** the edit is cancelled and the original name is restored.
|
7. **Given** inline edit mode has been entered (via any trigger), **When** the user types a new name and presses Enter or blurs the field, **Then** the name is committed. **When** the user presses Escape, **Then** the edit is cancelled and the original name is restored.
|
||||||
|
|
||||||
@@ -295,7 +291,7 @@ EditCombatant MUST return an `"invalid-name"` error when the new name is empty o
|
|||||||
EditCombatant MUST preserve the combatant's position in the list, `activeIndex`, and `roundNumber`. Setting a name to the same value it already has is treated as a valid update; a `CombatantUpdated` event is still emitted.
|
EditCombatant MUST preserve the combatant's position in the list, `activeIndex`, and `roundNumber`. Setting a name to the same value it already has is treated as a valid update; a `CombatantUpdated` event is still emitted.
|
||||||
|
|
||||||
#### FR-024 — Edit: UI
|
#### FR-024 — Edit: UI
|
||||||
The UI MUST provide an inline name-edit mechanism for each combatant, activated by double-clicking the name, clicking a hover-revealed pencil icon, or long-pressing on touch devices. Single-clicking the name MUST open/toggle the stat block panel, not enter edit mode. The updated name MUST be immediately visible after submission.
|
The UI MUST provide an inline name-edit mechanism for each combatant, activated by double-clicking the name or long-pressing on touch devices. The name MUST display a `cursor-text` cursor on hover to signal editability. Single-clicking the name MUST open/toggle the stat block panel, not enter edit mode. The updated name MUST be immediately visible after submission.
|
||||||
|
|
||||||
#### FR-025 — ConfirmButton: Reusable component
|
#### FR-025 — ConfirmButton: Reusable component
|
||||||
The system MUST provide a reusable `ConfirmButton` component that wraps any icon button to add a two-step confirmation flow.
|
The system MUST provide a reusable `ConfirmButton` component that wraps any icon button to add a two-step confirmation flow.
|
||||||
@@ -369,7 +365,7 @@ All domain events MUST be returned as plain data values from operations, not dis
|
|||||||
- **ConfirmButton: two instances in confirm state simultaneously**: Each manages its own state independently.
|
- **ConfirmButton: two instances in confirm state simultaneously**: Each manages its own state independently.
|
||||||
- **ConfirmButton: combatant row re-renders while in confirm state**: Confirm state persists through re-renders as long as combatant identity is stable.
|
- **ConfirmButton: combatant row re-renders while in confirm state**: Confirm state persists through re-renders as long as combatant identity is stable.
|
||||||
- **Name single-click vs double-click**: A single click on the combatant name opens the stat block panel; only a completed double-click enters inline edit mode. The system must disambiguate between the two gestures.
|
- **Name single-click vs double-click**: A single click on the combatant name opens the stat block panel; only a completed double-click enters inline edit mode. The system must disambiguate between the two gestures.
|
||||||
- **Pencil icon on touch devices**: The hover pencil icon MUST NOT be permanently visible on touch devices. Long-press is the touch equivalent for entering edit mode.
|
- **Touch edit affordance**: No hover-dependent affordance is shown on touch devices. Long-press is the touch equivalent for entering edit mode.
|
||||||
- **Long-press threshold**: The long-press duration should follow platform conventions (typically ~500ms). A short tap must not trigger edit mode.
|
- **Long-press threshold**: The long-press duration should follow platform conventions (typically ~500ms). A short tap must not trigger edit mode.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -405,4 +401,4 @@ All domain events MUST be returned as plain data values from operations, not dis
|
|||||||
- Cross-tab synchronization is not required for the MVP baseline.
|
- Cross-tab synchronization is not required for the MVP baseline.
|
||||||
- The `ConfirmButton` 5-second timeout is a fixed value and is not configurable in the MVP baseline.
|
- The `ConfirmButton` 5-second timeout is a fixed value and is not configurable in the MVP baseline.
|
||||||
- The `Check` icon from the Lucide icon library is used for the `ConfirmButton` confirm state.
|
- The `Check` icon from the Lucide icon library is used for the `ConfirmButton` confirm state.
|
||||||
- The inline name-edit mechanism is activated by double-click, hover pencil icon, or long-press (touch). Single-clicking the name opens the stat block panel.
|
- The inline name-edit mechanism is activated by double-click or long-press (touch). A `cursor-text` cursor on hover signals editability. Single-clicking the name opens the stat block panel.
|
||||||
|
|||||||
Reference in New Issue
Block a user