mcpField
W
wix-cli-dashboard-modal

wix-cli-dashboard-modal

github.com/wix开发36288 次安装今天更新
代码仓库

关于 wix-cli-dashboard-modal

用于 Wix CLI 的技能,介绍如何借助 Dashboard SDK 构建仪表板弹窗扩展,涵盖弹窗配置、与调用方交换数据、生命周期控制及注册。

主要功能

  1. 01三文件弹窗结构
  2. 02使用 SDK 打开和关闭弹窗
  3. 03通过 params 传递数据
  4. 04观察弹窗状态
  5. 05向调用方返回数据
  6. 06注册仪表板扩展

适用场景

  1. 01在仪表板页面添加编辑弹窗
  2. 02向弹窗传入选中项目
  3. 03关闭弹窗时返回保存的数据
  4. 04配置弹窗尺寸和标题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wix/skills --skill wix-cli-dashboard-modal

安装后在 Claude Code 中输入/wix-cli-dashboard-modal确认已加载。

详细介绍

概述

仪表板模态框是从仪表板页面或插件触发的弹出对话框。它们由三个文件组成,并使用 Dashboard SDK 通过 openModal() 和 closeModal() 控制生命周期。

快速参考

任务方法示例
创建模态框在 src/extensions/dashboard/modals/<folder>/ 中创建 3 个文件请参阅下文的文件结构
打开模态框dashboard.openModal()openModal({ modalId: "modal-id" })
向模态框传递数据openModal() 中的 paramsparams: { userId: "123" }
在模态框中读取数据observeState()dashboard.observeState((state) => { ... })
关闭模态框dashboard.closeModal()closeModal()
将数据返回给父级将数据传递给 closeModal()closeModal({ ... })
等待模态框关闭modalClosed Promiseconst { modalClosed } = openModal(...);

文件结构

在 src/extensions/dashboard/modals/<folder-name>/ 中创建 三个文件:

  1. extensions.ts - 包含模态框 ID、标题、尺寸和组件路径的构建器配置
  2. <modal-name>.tsx - 用于渲染模态框内容的 React 组件
  3. <modal-name>.config.ts - 可配置的模态框属性(标题、宽度、高度)

实现

创建模态框

创建三个必需文件:

1. extensions.ts - 模态框构建器配置:

import { extensions } from '@wix/astro/builders';
import config from './<modal-name>.config.ts';

export default extensions.dashboardModal({
  id: "{{GENERATE_UUID}}",
  title: config.title,
  width: config.width,
  height: config.height,
  component: './extensions/dashboard/modals/<modal-name>/<modal-name>.tsx',
});

重要:生成 UUID

id 必须是唯一且静态的 UUID v4 字符串。为每个扩展生成一个新的 UUID——不要使用 randomUUID(),也不要复制示例中的 UUID。将 {{GENERATE_UUID}} 替换为新生成的 UUID,例如 "a1b2c3d4-e5f6-7890-abcd-ef1234567890"。

构建器字段:

字段类型说明
idstring唯一的模态框 ID(GUID)。与 openModal() 配合使用
titlestring在项目仪表板中显示的模态框标题
widthnumber加载期间的初始宽度
heightnumber加载期间的初始高度
componentstring模态框内容 .tsx 文件的路径

2. <modal-name>.tsx - 模态框内容组件:

import type { FC } from 'react';
import { dashboard } from '@wix/dashboard';
import {
  WixDesignSystemProvider,
  Text,
  Box,
  CustomModalLayout,
} from '@wix/design-system';
import '@wix/design-system/styles.global.css';
import config from './<modal-name>.config.ts';

const { width, height, title } = config;

// To open your modal, call `openModal` with your modal id.
// e.g.
// import { dashboard } from '@wix/dashboard';
// function MyComponent() {
//   return <button onClick={() => dashboard.openModal({ modalId: '8ef4d434-9c80-44f5-a3f5-6f15f3a34be7' })}>Open Modal</button>;
// }
const Modal: FC = () => {
  return (
    <WixDesignSystemProvider features={{ newColorsBranding: true }}>
      <CustomModalLayout
        width={width}
        maxHeight={height}
        primaryButtonText="Save"
        secondaryButtonText="Cancel"
        primaryButtonOnClick={() => dashboard.closeModal()}
        secondaryButtonOnClick={() => dashboard.closeModal()}
        title={title}
        subtitle="Edit this file to customize your modal"
        content={
          <Box direction="vertical" align="center">
            <Text>Wix CLI Modal</Text>
          </Box>
        }
      />
    </WixDesignSystemProvider>
  );
};

export default Modal;

3. <modal-name>.config.ts - 可配置属性:

export default {
  title: "My Modal",
  width: 600,
  height: 400,
};

然后在 src/extensions.ts 中注册:

import { dashboardmodalYourModal } from './extensions/dashboard/modals/<modal-name>/extensions.ts';

export default app()
  .use(dashboardmodalYourModal)
  // ... other extensions
打开模态框
import { dashboard } from "@wix/dashboard";

// Simple open
const result = await dashboard.openModal({
  modalId: "your-modal-id", // From .extension.ts id field
});

// Pass data to modal via params
const result = await dashboard.openModal({
  modalId: "your-modal-id",
  params: {
    userId: user.id,
    itemData: complexObject, // Objects are passed directly, no encoding needed
  },
});

// Get notified when the modal is closed
const { modalClosed } = dashboard.openModal({
  modalId: "your-modal-id",
});
const result = await modalClosed; // Resolves with data from closeModal()
在模态框中接收数据

使用 observeState() 访问通过 openModal() 中的 params 传递的数据:

import { dashboard } from "@wix/dashboard";
import { useEffect, useState } from "react";

function MyModal() {
  const [modalData, setModalData] = useState<{ userId?: string; itemData?: any }>({});

  useEffect(() => {
    dashboard.observeState((state) => {
      // Access custom data passed through openModal params
      if (state.userId) {
        setModalData({
          userId: state.userId,
          itemData: state.itemData,
        });
      }
    });
  }, []);

  return <div>User ID: {modalData.userId}</div>;
}
关闭模态框

在模态框扩展中调用 closeModal() 以关闭模态框。也可以选择将数据返回给打开模态框的一方。

import { dashboard } from "@wix/dashboard";

// Close without returning data
dashboard.closeModal();

// Close with custom return data
dashboard.closeModal({ saved: true, itemId: "123" });
参数类型说明
closeDataSerializable(可选)要传回给模态框打开方的数据。必须可通过结构化克隆算法进行克隆。

**支持的类型:**字符串、数字、布尔值、普通对象、数组、Dates、Maps、Sets、ArrayBuffers。 **不支持:**函数、DOM 节点、带有方法的类实例、Symbols、Promises。

返回值:void

自定义模态框

在 .config.ts 中编辑整理后的设置:

export default {
  title: 'User Settings',
  width: 600,
  height: 500,
}

在 .tsx 中导入:

import config from './modal.config.ts';

export default function MyModal() {
  return (
    <CustomModalLayout
      title={config.title}
      // ... rest of component
    />
  );
}

常见错误

错误修复方法
找不到模态框 ID检查 .extension.ts 文件的 id 字段
忘记在 extensions.ts 中注册导入模态框并调用 .use()
使用 extensionId 而不是 modalId在 openModal() 中使用 modalId
无法在模态框中访问 params使用 dashboard.observeState() 读取传递的数据
模态框无法关闭使用来自 @wix/dashboard 的 dashboard.closeModal()

实际示例

// Dashboard Page: Opening edit modal
const handleEdit = async (item: Item) => {
  dashboard.openModal({
    modalId: "edit-item-modal-guid",
    params: {
      itemId: item._id,
      item: item, // Objects passed directly via params
    },
  });
};

// Modal: Receiving and saving data
export default function ItemEditModal() {
  const [formData, setFormData] = useState<Item | null>(null);

  useEffect(() => {
    dashboard.observeState((state) => {
      if (state.item) {
        setFormData(state.item);
      }
    });
  }, []);

  const handleSave = async () => {
    // Save logic
    dashboard.showToast({ message: "Saved!", type: "success" });
    dashboard.closeModal();
  };

  return (
    <CustomModalLayout
      title="Edit Item"
      primaryButtonText="Save"
      onCloseButtonClick={() => dashboard.closeModal()}
      primaryButtonOnClick={handleSave}
      content={/* form fields */}
    />
  );
}

评论

支持 Markdown