{"_id":"@ahmiao666/ahmiao-react-dialog-element","name":"@ahmiao666/ahmiao-react-dialog-element","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@ahmiao666/ahmiao-react-dialog-element","version":"1.0.0","type":"module","description":"react18+ dialog组件","main":"index.js","module":"index.esm.js","types":"index.d.ts","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"keywords":["react","typescript","dialog","dialog组件","React组件"],"author":{"name":"ahmiao","email":"wangyimiao666@gmail.com"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/ahmiao666/ahmiao-react-dialog-element.git"},"bugs":{"url":"https://github.com/ahmiao666/ahmiao-react-dialog-element/issues"},"homepage":"https://github.com/ahmiao666/ahmiao-react-dialog-element","engines":{"node":">=22.0.0","npm":">=10.9.2"},"peerDependencies":{"react":">=18.x","react-dom":">=18.x","motion":">=12"},"browserslist":["> 1%","last 2 versions","not dead","not ie 11"],"sideEffects":false,"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_id":"@ahmiao666/ahmiao-react-dialog-element@1.0.0","gitHead":"a5d71ae5b3087b2213a86952705adbf3f3cbbb34","_nodeVersion":"23.11.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-fSLidMfjgrjokWr8yKQsNc1CS17SAXOdXXTWcap4Nf/FZghcrDdWlBqGYzLIF2SDy36ITdugs29S+Wpxm+dcfg==","shasum":"e708745bf0a2f885b5c88b6e1578e37b0082962d","tarball":"https://registry.npmjs.org/@ahmiao666/ahmiao-react-dialog-element/-/ahmiao-react-dialog-element-1.0.0.tgz","fileCount":15,"unpackedSize":953357,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHGUQu8+IHKDefNDIWLdBcNzwsNtgCTSnd/iFzo8OpPxAiAXIj0ENL1njcBksD8ucXf1CGlP169CVlsKRdYg/gcNCQ=="}]},"_npmUser":{"name":"ahmiao666","email":"wangyimiao666@gmail.com"},"directories":{},"maintainers":[{"name":"ahmiao666","email":"wangyimiao666@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ahmiao-react-dialog-element_1.0.0_1754737354378_0.03321558452090945"},"_hasShrinkwrap":false}},"time":{"created":"2025-08-09T11:02:34.292Z","1.0.0":"2025-08-09T11:02:34.563Z","modified":"2025-08-09T11:02:34.838Z"},"maintainers":[{"name":"ahmiao666","email":"wangyimiao666@gmail.com"}],"description":"react18+ dialog组件","homepage":"https://github.com/ahmiao666/ahmiao-react-dialog-element","keywords":["react","typescript","dialog","dialog组件","React组件"],"repository":{"type":"git","url":"git+https://github.com/ahmiao666/ahmiao-react-dialog-element.git"},"author":{"name":"ahmiao","email":"wangyimiao666@gmail.com"},"bugs":{"url":"https://github.com/ahmiao666/ahmiao-react-dialog-element/issues"},"license":"MIT","readme":"# 🎉 ahmiao React18 Dialog\n\n高性能React18 Dialog组件，支持完整的性能控制和诊断功能。\n\n## 🚀 安装\n\n```bash\nnpm install @ahmiao666/ahmiao-react-dialog-element\n```\n\n## 📖 快速开始\n\n```tsx\n# amDialogCustom 弹窗组件使用说明  仅支持React18+ 因为底层订阅使用了 useSyncExternalStore \n\n## 基本使用\n\n### 使用之前需要先把提供者组件 DialogCustomProvider 挂在到 app 里\n\n```tsx\n// 在应用根组件中挂载一次\nimport { DialogCustomProvider } from '@ahmiao666/ahmiao-react-dialog-element'\nimport '@ahmiao666/ahmiao-react-dialog-element/index.css'\n\nfunction AppRoot() {\n  return (\n    <>\n      {/* 你的 App */}\n      <DialogCustomProvider />\n    </>\n  )\n}\n```\n\n```tsx\nimport { DialogCustomStaticMethods } from '@ahmiao666/ahmiao-react-dialog-element'\n\n// 方式1: await 方式\nconst result = await DialogCustomStaticMethods.open(\n  ({ onClose }) => (\n    <div>\n      <p>确定要删除吗？</p>\n      <button onClick={() => onClose(true)}>确定</button>\n      <button onClick={() => onClose(false)}>取消</button>\n    </div>\n  ),\n  {\n    title: \"确认删除\",\n    width: 400\n  }\n)\n\nif (result) {\n  console.log('用户确认删除')\n}\n\n// 方式2: .then() 方式\nDialogCustomStaticMethods.open(\n  ({ onClose }) => (\n    <div>\n      <p>确定要删除吗？</p>\n      <button onClick={() => onClose(true)}>确定</button>\n      <button onClick={() => onClose(false)}>取消</button>\n    </div>\n  ),\n  {\n    title: \"确认删除\", \n    width: 400\n  }\n).then(result => {\n  if (result) {\n    console.log('用户确认删除')\n  }\n}).catch(() => {\n  console.log('弹窗被取消')\n})\n```\n\n## 配置选项\n\n```tsx\nDialogCustomStaticMethods.open(Component, {\n  title: '弹窗标题',            // 标题文本\n  width: 500,                 // 宽度：number=vw，string=任意CSS宽度\n  showIcon: true,             // 是否显示标题图标\n  showClose: true,            // 是否显示关闭按钮\n  icon: '📣',                  // 自定义标题图标（可选）\n  maskClosable: true,         // 点击遮罩是否可关闭\n  maskBg: 'rgba(0,0,0,0.6)',  // 遮罩背景色（仅颜色）\n  familyName: 'settings',     // 弹窗命名空间（用于多弹窗并存）\n  onNext: (v) => {},          // 可选的下一步回调（会传给内容组件）\n  props: { data: '数据' }      // 传递给内容组件的自定义 props\n})\n```\n\n### 遮罩与样式\n\n- 仅支持通过 `maskBg` 修改遮罩颜色，默认值：`rgba(0, 0, 0, 0.4)`。\n- 当同时打开多个弹窗时，遮罩只渲染一次，颜色取“最上层弹窗”的 `maskBg`。\n\n```ts\nDialogCustomStaticMethods.open(Comp, {\n  maskBg: 'rgba(0,0,0,0.6)'\n})\n```\n\n## 多弹窗\n```tsx\n// 打开多个弹窗\nDialogCustomStaticMethods.openWithFamily(\"settings\", SettingsComponent)\nDialogCustomStaticMethods.openWithFamily(\"profile\", ProfileComponent)\n\n// 或者通过 options.familyName 指定\nDialogCustomStaticMethods.open(SettingsComponent, { familyName: 'settings' })\nDialogCustomStaticMethods.open(ProfileComponent, { familyName: 'profile' })\n\n// 关闭指定弹窗\nDialogCustomStaticMethods.close(\"settings\")\n\n// 关闭所有弹窗\nDialogCustomStaticMethods.closeAll()\n```\n\n## 回调方式\n\n### 方式1: onClose回调\n```tsx\nconst result = await DialogCustomStaticMethods.open(\n  ({ onClose }) => (\n    <div>\n      <button onClick={() => onClose(\"保存\")}>保存</button>\n      <button onClick={() => onClose(null)}>取消</button>\n    </div>\n  )\n)\n// result = \"保存\" 或 null\n```\n\n### 方式2: props回调\n```tsx\nconst handleSave = (data) => console.log(\"保存:\", data)\n\nawait DialogCustomStaticMethods.open(\n  ({ onSave, onClose }) => (\n    <div>\n      <button onClick={() => onSave(\"数据\")}>保存</button>\n      <button onClick={() => onClose()}>关闭</button>\n    </div>\n  ),\n  {\n    props: { onSave: handleSave }\n  }\n)\n```\n\n## 状态读取与订阅\n\n> 这些 Hook/方法用于“读取弹窗状态”。推荐优先使用只读选择器，避免直接接触底层 Map。\n\n### useHasOpenDialog\n\n是否存在任意弹窗打开（订阅式）。\n\n```tsx\nimport { useHasOpenDialog } from '@/am-ui/am-dialog'\n\nexport function Header() {\n  const hasOpen = useHasOpenDialog()\n  return hasOpen ? null : <TopBar />\n}\n```\n\n### useFamilyVisible\n\n指定 family 是否打开（订阅式）。\n\n```tsx\nimport { useFamilyVisible } from '@/am-ui/am-dialog'\n\nconst profileOpen = useFamilyVisible('profile')\n```\n\n### useDialogSelector\n\n通用选择器 Hook：订阅式返回派生值，避免暴露底层 Map。\n\n```tsx\nimport { useDialogSelector } from '@/am-ui/am-dialog'\n\n// 打开中的 family 列表\nconst openFamilies = useDialogSelector((states) =>\n  Array.from(states.entries())\n    .filter(([, s]) => s.visible)\n    .map(([family]) => family),\n)\n\n// 顶层弹窗标题（示例）\nconst topTitle = useDialogSelector((states) => {\n  const visible = Array.from(states.values()).filter((s) => s.visible && s.options)\n  const top = visible[visible.length - 1]\n  return top?.options?.title ?? ''\n})\n```\n\n### getDialogFrozenSnapshot\n\n一次性只读快照（非订阅）。适合在非 React 或初始化时读取。\n\n```ts\nimport { getDialogFrozenSnapshot } from '@/am-ui/am-dialog'\n\nconst snap = getDialogFrozenSnapshot()\nfor (const [family, state] of snap) {\n  console.log(family, state.visible, state.options?.title)\n}\n```\n\n### subscribeHasOpen\n\n非 React 环境订阅“是否有弹窗打开”的变化（会立即回调一次当前值）。\n\n```ts\nimport { subscribeHasOpen } from '@/am-ui/am-dialog'\n\nconst unsubscribe = subscribeHasOpen((hasOpen) => {\n  console.log('hasOpen changed:', hasOpen)\n})\n\n// 需要时机合适地取消订阅\nunsubscribe()\n```\n\n> 写操作请始终使用现有 API：`DialogCustomStaticMethods.open/openWithFamily/close/closeAll` 或内容组件内的 `onClose`/`onNext`，不要直接修改底层 Map。\n\n```\n\n## 🔗 相关链接\n\n- [完整文档](https://github.com/ahmiao666/ahmiao-react-dialog-element)\n- [GitHub仓库](https://github.com/ahmiao666/ahmiao-react-dialog-element)\n","readmeFilename":"README.md","_rev":"1-8cf4937d04e54fab9957f123b42e0e76"}