Conversation
|
/review |
commit: |
|
/review |
| const iconSlotClasses = "astw:flex astw:size-4 astw:items-center astw:justify-center"; | ||
|
|
||
| const ActionSpinner = () => ( | ||
| <span className={iconSlotClasses} aria-hidden data-testid="action-panel-spinner"> |
There was a problem hiding this comment.
[2/2 — Medium] Double-nested iconSlotClasses span when loading
ActionSpinner wraps the spinner SVG in its own iconSlotClasses span (astw:flex astw:size-4 astw:items-center astw:justify-center):
const ActionSpinner = () => (
<span className={iconSlotClasses} …> {/* ← size-4 container */}
(svg className="astw:size-4 …" /)
</span>
);But in ActionRow, the spinner is rendered inside another iconSlotClasses span:
<span className={iconSlotClasses} aria-hidden> {/* ← another size-4 container */}
{loading ? (ActionSpinner /) : icon}
</span>When loading is true you get two nested 16×16 flex containers. This is redundant and will cause subtle alignment differences vs. the non-loading state (the icon is placed directly inside one container; the spinner sits two levels deep).
Fix by making ActionSpinner return only the SVG (no wrapping span), since the outer iconSlotClasses span in ActionRow already provides the sizing/centering:
const ActionSpinner = () => (
(svg
className="astw:size-4 astw:animate-spin"
viewBox="0 0 16 16"
fill="none"
xmlns="(www.w3.org/redacted)
aria-hidden
data-testid="action-panel-spinner"
)
…
(/svg)
);|
@itsprade need rebasing this branch with main 🙏 |
There was a problem hiding this comment.
This file needs converging into docs dir 🙏
Introduces a new ActionPanel component for displaying a card with a
title and a vertical list of clickable/linkable action rows, each with
an icon and label. Supports both onClick handlers and href navigation.
Usage:
import { ActionPanel } from "@tailor-platform/app-shell";
<ActionPanel
title="Actions"
actions={[
{ key: "create", label: "Create invoice", icon: <Icon />, onClick: () => {} },
{ key: "docs", label: "View docs", icon: <Icon />, href: "/docs" },
]}
/>
Made-with: Cursor
- Add optional loading prop to ActionItem; show spinner and disable row when loading - Reduce horizontal padding (px-6 to px-4), align title with action row icon (pl-3) - Reduce gap between actions to 0; increase top padding (pt-6), add title mb-2 - Add loading example on 2-column layout (Create invoice shows loading for 1.5s) - Update docs and tests for loading support Made-with: Cursor
- Add 320px min-width to ActionPanel card - Empty state: align message with title (pl-3), add py-2; title spacing via container pb-4 - 2-column layout: second ActionPanel with empty actions to demonstrate empty state - Add README.md with design rationale, API, usage, and backend-driven pattern - README: replace 'dumb' with 'presentational component with no internal business logic' Made-with: Cursor
- Use ============ section comments and ALL CAPS labels - Inline card/header/list classes in JSX; keep row/icon constants - Add EXPORTS section; match repo style Made-with: Cursor
- ActionItem: only onClick (no href); use useNavigate() in callback for navigation - Remove ActionItem from public API (consumers infer from ActionPanelProps) - Always render button; remove link branch and href+disabled/loading edge case - Update demo and 2-column example to use navigate() for link-like actions - Remove test for 'renders as link when href provided' Made-with: Cursor
Made-with: Cursor
Remove the extra spinner wrapper to keep icon-slot alignment consistent, and update ActionPanel docs to reflect the onClick-only action contract. Made-with: Cursor
5a9c1da to
acc9853
Compare
Relocate ActionPanel documentation from the component folder into the central docs/components structure so it follows the same format and discoverability as other component docs. Made-with: Cursor
Made-with: Cursor
Apply oxfmt output to docs, examples, and tests to keep formatting consistent. Made-with: Cursor
ActionPanel – PR summary
What it is
ActionPanel is a presentational card component that displays a title and a vertical list of actions (icon + label). Each action is a button (
onClick) or a link (href). The parent decides which actions to show and what they do (e.g. from the backend or a registry).In this PR
loadingper action; shows a spinner in the icon slot and makes the row non-interactive (for backend-driven flows).actions.length === 0, shows “No actions available” with alignment and padding consistent with the title.px-4); title aligned with action row icon; no gap between rows; spacing handled via container padding.Usage
Parent passes
titleandactions: ActionItem[](each withkey,label,icon, andonClickorhref; optionaldisabled,loading). Suitable for backend-driven UIs where the API returns available action keys and the app resolves them with a registry and setsloadingfrom mutation state.