wix-cli-dashboard-modal

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Overview

概述

Dashboard modals are popup dialogs triggered from dashboard pages or plugins. They consist of three files and use the Dashboard SDK for lifecycle control via
openModal()
and
closeModal()
.
仪表盘模态框是从仪表盘页面或插件触发的弹出式对话框。它们由三个文件组成,并通过
openModal()
closeModal()
方法使用Dashboard SDK进行生命周期控制。

Quick Reference

快速参考

TaskMethodExample
Create modalCreate 3 files in
src/dashboard/modals/<folder>/
See File Structure below
Open modal
dashboard.openModal()
openModal({ modalId: "modal-id" })
Pass data to modal
params
in
openModal()
params: { userId: "123" }
Read data in modal
observeState()
dashboard.observeState((state) => { ... })
Close modal
dashboard.closeModal()
closeModal()
Return data to parentPass data to
closeModal()
closeModal({ ... })
Wait for modal close
modalClosed
Promise
const { modalClosed } = openModal(...);
任务方法示例
创建模态框
src/dashboard/modals/<folder>/
目录下创建3个文件
见下方文件结构
打开模态框
dashboard.openModal()
openModal({ modalId: "modal-id" })
向模态框传递数据
openModal()
中的
params
参数
params: { userId: "123" }
在模态框中读取数据
observeState()
dashboard.observeState((state) => { ... })
关闭模态框
dashboard.closeModal()
closeModal()
向父组件返回数据
closeModal()
传递数据
closeModal({ ... })
等待模态框关闭
modalClosed
Promise
const { modalClosed } = openModal(...);

File Structure

文件结构

Create three files in
src/dashboard/modals/<folder-name>/
:
  1. extensions.ts
    - Builder configuration with modal ID, title, dimensions, component path
  2. <modal-name>.tsx
    - React component rendering modal content
  3. <modal-name>.config.ts
    - Configurable modal properties (title, width, height)
src/dashboard/modals/<folder-name>/
目录下创建三个文件
  1. extensions.ts
    - 包含模态框ID、标题、尺寸、组件路径的构建器配置文件
  2. <modal-name>.tsx
    - 渲染模态框内容的React组件
  3. <modal-name>.config.ts
    - 模态框的可配置属性(标题、宽度、高度)

Implementation

实现步骤

Creating a Modal

创建模态框

Create the three required files:
1.
extensions.ts
- Modal builder configuration:
typescript
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',
});
CRITICAL: UUID Generation
The
id
must be a unique, static UUID v4 string. Generate a fresh UUID for each extension - do NOT use
randomUUID()
or copy UUIDs from examples. Replace
{{GENERATE_UUID}}
with a freshly generated UUID like
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
.
Builder fields:
FieldTypeDescription
idstringUnique modal ID (GUID). Used with
openModal()
titlestringModal title shown in project dashboard
widthnumberInitial width while loading
heightnumberInitial height while loading
componentstringPath to the modal content
.tsx
file
2.
<modal-name>.tsx
- Modal content component:
typescript
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
- Configurable properties:
typescript
export default {
  title: "My Modal",
  width: 600,
  height: 400,
};
Then register in
src/extensions.ts
:
typescript
import { dashboardmodalYourModal } from './dashboard/modals/<modal-name>/extensions.ts';

export default app()
  .use(dashboardmodalYourModal)
  // ... other extensions
创建所需的三个文件:
1.
extensions.ts
- 模态框构建器配置:
typescript
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
- 模态框内容组件:
typescript
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;

// 要打开模态框,请调用`openModal`并传入你的模态框id。
// 例如
// import { dashboard } from '@wix/dashboard';
// function MyComponent() {
//   return <button onClick={() => dashboard.openModal({ modalId: '8ef4d434-9c80-44f5-a3f5-6f15f3a34be7' })}>打开模态框</button>;
// }
const Modal: FC = () => {
  return (
    <WixDesignSystemProvider features={{ newColorsBranding: true }}>
      <CustomModalLayout
        width={width}
        maxHeight={height}
        primaryButtonText="保存"
        secondaryButtonText="取消"
        primaryButtonOnClick={() => dashboard.closeModal()}
        secondaryButtonOnClick={() => dashboard.closeModal()}
        title={title}
        subtitle="编辑此文件来自定义你的模态框"
        content={
          <Box direction="vertical" align="center">
            <Text>Wix CLI Modal</Text>
          </Box>
        }
      />
    </WixDesignSystemProvider>
  );
};

export default Modal;
3.
<modal-name>.config.ts
- 可配置属性:
typescript
export default {
  title: "我的模态框",
  width: 600,
  height: 400,
};
然后在
src/extensions.ts
中注册:
typescript
import { dashboardmodalYourModal } from './dashboard/modals/<modal-name>/extensions.ts';

export default app()
  .use(dashboardmodalYourModal)
  // ... 其他扩展

Opening a Modal

打开模态框

typescript
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()
typescript
import { dashboard } from "@wix/dashboard";

// 简单打开
const result = await dashboard.openModal({
  modalId: "your-modal-id", // 来自.extension.ts文件的id字段
});

// 通过params向模态框传递数据
const result = await dashboard.openModal({
  modalId: "your-modal-id",
  params: {
    userId: user.id,
    itemData: complexObject, // 对象直接传递,无需编码
  },
});

// 监听模态框关闭事件
const { modalClosed } = dashboard.openModal({
  modalId: "your-modal-id",
});
const result = await modalClosed; // 会在closeModal()调用时接收返回的数据

Receiving Data in Modal

在模态框中接收数据

Use
observeState()
to access data passed via
params
in
openModal()
:
typescript
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>;
}
使用
observeState()
访问通过
openModal()
params
传递的数据:
typescript
import { dashboard } from "@wix/dashboard";
import { useEffect, useState } from "react";

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

  useEffect(() => {
    dashboard.observeState((state) => {
      // 访问通过openModal params传递的自定义数据
      if (state.userId) {
        setModalData({
          userId: state.userId,
          itemData: state.itemData,
        });
      }
    });
  }, []);

  return <div>用户ID: {modalData.userId}</div>;
}

Closing Modal

关闭模态框

Call
closeModal()
from within the modal extension to close it. Optionally pass data back to the opener.
typescript
import { dashboard } from "@wix/dashboard";

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

// Close with custom return data
dashboard.closeModal({ saved: true, itemId: "123" });
ParameterTypeDescription
closeDataSerializable (optional)Data to pass back to the modal opener. Must be cloneable via structured clone algorithm - no function callbacks.
Returns:
void
在模态框扩展中调用
closeModal()
来关闭它。可选择向打开者返回数据。
typescript
import { dashboard } from "@wix/dashboard";

// 不返回数据直接关闭
dashboard.closeModal();

// 携带自定义返回数据关闭
dashboard.closeModal({ saved: true, itemId: "123" });
参数类型描述
closeData可序列化类型(可选)要传递给模态框打开者的数据。必须可通过结构化克隆算法克隆 - 不支持函数回调。
返回值:
void

Customizing Modal

自定义模态框

Edit
.config.ts
for organized settings:
typescript
export default {
  title: 'User Settings',
  width: 600,
  height: 500,
}
Import in
.tsx
:
typescript
import config from './modal.config.ts';

export default function MyModal() {
  return (
    <CustomModalLayout
      title={config.title}
      // ... rest of component
    />
  );
}
编辑
.config.ts
文件来管理设置:
typescript
export default {
  title: '用户设置',
  width: 600,
  height: 500,
}
.tsx
中导入:
typescript
import config from './modal.config.ts';

export default function MyModal() {
  return (
    <CustomModalLayout
      title={config.title}
      // ... 组件其他部分
    />
  );
}

Common Mistakes

常见错误

MistakeFix
Can't find modal IDCheck
.extension.ts
file's
id
field
Forgetting to register in
extensions.ts
Import and
.use()
the modal
Using
extensionId
instead of
modalId
Use
modalId
in
openModal()
Can't access params in modalUse
dashboard.observeState()
to read passed data
Modal won't closeUse
dashboard.closeModal()
from
@wix/dashboard
错误修复方案
找不到模态框ID检查
.extension.ts
文件中的
id
字段
忘记在
extensions.ts
中注册
导入模态框并通过
.use()
方法注册
使用
extensionId
而非
modalId
openModal()
中使用
modalId
无法在模态框中访问params使用
dashboard.observeState()
读取传递的数据
模态框无法关闭使用
@wix/dashboard
中的
dashboard.closeModal()
方法

Real-World Example

实际示例

typescript
// 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 */}
    />
  );
}
typescript
// 仪表盘页面:打开编辑模态框
const handleEdit = async (item: Item) => {
  dashboard.openModal({
    modalId: "edit-item-modal-guid",
    params: {
      itemId: item._id,
      item: item, // 对象直接通过params传递
    },
  });
};

// 模态框:接收并保存数据
export default function ItemEditModal() {
  const [formData, setFormData] = useState<Item | null>(null);

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

  const handleSave = async () => {
    // 保存逻辑
    dashboard.showToast({ message: "已保存!", type: "success" });
    dashboard.closeModal();
  };

  return (
    <CustomModalLayout
      title="编辑条目"
      primaryButtonText="保存"
      onCloseButtonClick={() => dashboard.closeModal()}
      primaryButtonOnClick={handleSave}
      content={/* 表单字段 */}
    />
  );
}

Verification

验证

After implementation, use wix-cli-app-validation to validate TypeScript compilation, build, preview, and runtime behavior.
实现完成后,使用wix-cli-app-validation来验证TypeScript编译、构建、预览和运行时行为。