AgentSkillsCN

rezi-modal-dialogs

添加模态对话框与叠加式UI,并实现焦点捕获功能。在实现确认提示、警示信息,或构建多层界面时使用。

SKILL.md
--- frontmatter
name: rezi-modal-dialogs
description: Add modal dialogs and overlay UI with focus trapping. Use when implementing confirmations, alerts, or layered interfaces.
user-invocable: true
allowed-tools: Read, Glob, Grep, Edit, Write
argument-hint: "[modal-type]"
metadata:
  short-description: Add modal dialogs

When to use

Use this skill when:

  • Adding confirmation dialogs, alerts, or prompts
  • Building layered/overlay UI
  • Need focus trapping within a dialog

Source of truth

  • packages/core/src/widgets/useModalStack.tsuseModalStack() hook
  • packages/core/src/widgets/types.tsModalProps, LayersProps
  • packages/core/src/widgets/ui.tsui.modal(), ui.layers()
  • packages/core/src/ui/recipes.tsrecipe.modal() and recipe.surface() for design-system-consistent modal styling

Steps

Option A: useModalStack (recommended for multiple modals)

  1. Use useModalStack() inside a defineWidget:
    typescript
    const modals = useModalStack(ctx);
    
    // Push a modal
    modals.push("confirm", {
      title: "Confirm",
      content: body,
      onClose: () => modals.pop(),
    });
    
    // Include in view
    return ui.layers([mainContent, ...modals.render()]);
    

Option B: ui.modal (simple single modal)

  1. Use ui.modal() directly with a state-controlled flag:

    typescript
    return ui.layers([
      mainContent,
      ...(state.showModal
        ? [
            ui.modal({
              id: "confirm-modal",
              title: "Confirm",
              initialFocus: "confirm-ok",
              returnFocusTo: "open-confirm",
              onClose: () => app.update((s) => ({ ...s, showModal: false })),
              content: ui.text("Are you sure?"),
              actions: [ui.button({ id: "confirm-ok", label: "OK" })],
            }),
          ]
        : []),
    ]);
    
  2. Overlay ordering note:

    • Modal, dropdown, and toast overlays share unified z-ordering through the LayerRegistry.
    • Prefer ui.layers([...]) as the common overlay composition root.

Verification

  • Modal opens and closes correctly
  • Focus traps within the modal (Tab doesn't escape)
  • Focus returns to previous element on close