@ploykit/ui 0.5.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/dist/AppProviders.js +2 -2
  2. package/dist/components/ConfirmDialog.js +1 -1
  3. package/dist/components/CronInput.js +3 -3
  4. package/dist/components/DataTable.js +4 -4
  5. package/dist/components/FormField.js +1 -1
  6. package/dist/components/ImpersonationBanner.js +1 -1
  7. package/dist/components/NotificationBell.js +1 -1
  8. package/dist/components/OnboardingChecklist.js +3 -3
  9. package/dist/components/Page.js +2 -2
  10. package/dist/components/ReauthDialog.js +4 -4
  11. package/dist/components/SecretModal.js +2 -2
  12. package/dist/components/SettingsCard.js +2 -2
  13. package/dist/components/SiteBanner.js +1 -1
  14. package/dist/components/SiteBannerLayer.js +1 -1
  15. package/dist/components/StatusBadge.js +1 -1
  16. package/dist/components/UserMenu.js +3 -3
  17. package/dist/components/WorkspaceSwitcher.js +7 -7
  18. package/dist/components/ui/alert-dialog.js +2 -2
  19. package/dist/components/ui/avatar.js +1 -1
  20. package/dist/components/ui/badge.js +1 -1
  21. package/dist/components/ui/breadcrumb.js +1 -1
  22. package/dist/components/ui/button.js +1 -1
  23. package/dist/components/ui/card.js +1 -1
  24. package/dist/components/ui/checkbox.js +1 -1
  25. package/dist/components/ui/dialog.js +2 -2
  26. package/dist/components/ui/dropdown-menu.js +1 -1
  27. package/dist/components/ui/empty.js +1 -1
  28. package/dist/components/ui/field.js +3 -3
  29. package/dist/components/ui/input.js +1 -1
  30. package/dist/components/ui/label.js +1 -1
  31. package/dist/components/ui/popover.js +1 -1
  32. package/dist/components/ui/progress.js +1 -1
  33. package/dist/components/ui/select.js +1 -1
  34. package/dist/components/ui/separator.js +1 -1
  35. package/dist/components/ui/sheet.js +2 -2
  36. package/dist/components/ui/sidebar.js +8 -8
  37. package/dist/components/ui/skeleton.js +1 -1
  38. package/dist/components/ui/switch.js +1 -1
  39. package/dist/components/ui/tabs.js +1 -1
  40. package/dist/components/ui/textarea.js +1 -1
  41. package/dist/components/ui/tooltip.js +1 -1
  42. package/dist/index.js +78 -78
  43. package/dist/layouts/AppShell.js +4 -4
  44. package/dist/layouts/SettingsShell.js +4 -4
  45. package/dist/pages/LoginPage.js +5 -5
  46. package/dist/pages/account/NotificationPreferencesPage.js +3 -3
  47. package/dist/pages/account/ProfileSettingsPage.js +9 -9
  48. package/dist/pages/account/SecuritySettingsPage.js +13 -13
  49. package/dist/pages/account/TokensPage.js +12 -12
  50. package/dist/pages/admin/AdminSettingsPage.js +11 -11
  51. package/dist/pages/admin/AdminShell.js +3 -3
  52. package/dist/pages/admin/AuditPage.js +8 -8
  53. package/dist/pages/admin/OrdersPage.js +12 -12
  54. package/dist/pages/admin/OverviewPage.js +13 -13
  55. package/dist/pages/admin/SSOPage.js +6 -6
  56. package/dist/pages/admin/UserDetailPage.js +13 -13
  57. package/dist/pages/admin/UsersPage.js +13 -13
  58. package/dist/pages/admin/WebhookDeliveriesPage.js +9 -9
  59. package/dist/pages/admin/WorkspaceDetailPage.js +14 -14
  60. package/dist/pages/admin/WorkspacesPage.js +9 -9
  61. package/dist/pages/admin/shared.js +1 -1
  62. package/dist/pages/auth/ForgotPasswordPage.js +4 -4
  63. package/dist/pages/auth/InviteAcceptPage.js +6 -6
  64. package/dist/pages/auth/RegisterPage.js +7 -7
  65. package/dist/pages/auth/ResetPasswordPage.js +5 -5
  66. package/dist/pages/auth/VerifyEmailPage.js +3 -3
  67. package/dist/pages/workspace/BillingPage.js +11 -11
  68. package/dist/pages/workspace/BillingSuccessPage.js +2 -2
  69. package/dist/pages/workspace/MembersPage.js +15 -15
  70. package/dist/pages/workspace/RolePermissionsPage.js +9 -9
  71. package/dist/pages/workspace/SchedulesPage.js +12 -12
  72. package/dist/pages/workspace/UsagePage.js +6 -6
  73. package/dist/pages/workspace/WebhooksPage.js +16 -16
  74. package/dist/pages/workspace/WorkspaceAuditPage.js +7 -7
  75. package/dist/pages/workspace/WorkspaceGeneralPage.js +9 -9
  76. package/package.json +6 -5
  77. package/src/AppProviders.tsx +29 -0
  78. package/src/components/ConfirmDialog.tsx +77 -0
  79. package/src/components/CronInput.tsx +195 -0
  80. package/src/components/DataTable.tsx +152 -0
  81. package/src/components/ErrorBoundary.tsx +46 -0
  82. package/src/components/FormField.tsx +56 -0
  83. package/src/components/ImpersonationBanner.tsx +23 -0
  84. package/src/components/NotificationBell.tsx +135 -0
  85. package/src/components/OnboardingChecklist.tsx +114 -0
  86. package/src/components/Page.tsx +67 -0
  87. package/src/components/ReauthDialog.tsx +94 -0
  88. package/src/components/SecretModal.tsx +147 -0
  89. package/src/components/SettingsCard.tsx +39 -0
  90. package/src/components/SiteBanner.tsx +32 -0
  91. package/src/components/SiteBannerLayer.tsx +29 -0
  92. package/src/components/StatusBadge.tsx +12 -0
  93. package/src/components/UserMenu.tsx +103 -0
  94. package/src/components/WorkspaceSwitcher.tsx +159 -0
  95. package/src/components/__tests__/AppProviders.test.tsx +111 -0
  96. package/src/components/__tests__/CronInput.test.tsx +180 -0
  97. package/src/components/__tests__/DataTable.test.tsx +208 -0
  98. package/src/components/__tests__/ErrorBoundary.test.tsx +61 -0
  99. package/src/components/__tests__/ImpersonationBanner.test.tsx +59 -0
  100. package/src/components/__tests__/NotificationBell.test.tsx +207 -0
  101. package/src/components/__tests__/OnboardingChecklist.test.tsx +97 -0
  102. package/src/components/__tests__/SecretModal.test.tsx +112 -0
  103. package/src/components/__tests__/SiteBannerLayer.test.tsx +44 -0
  104. package/src/components/__tests__/UserMenu.test.tsx +98 -0
  105. package/src/components/__tests__/WorkspaceSwitcher.test.tsx +162 -0
  106. package/src/components/__tests__/form.test.tsx +133 -0
  107. package/src/components/__tests__/semantic-tokens.test.ts +41 -0
  108. package/src/components/__tests__/smoke.test.tsx +11 -0
  109. package/src/components/__tests__/toast.test.tsx +27 -0
  110. package/src/components/toast.tsx +23 -0
  111. package/src/components/ui/__tests__/alert-dialog.test.tsx +66 -0
  112. package/src/components/ui/__tests__/avatar.test.tsx +30 -0
  113. package/src/components/ui/__tests__/checkbox.test.tsx +18 -0
  114. package/src/components/ui/__tests__/dropdown-menu.test.tsx +33 -0
  115. package/src/components/ui/__tests__/field.test.tsx +43 -0
  116. package/src/components/ui/__tests__/overlay-size.test.tsx +84 -0
  117. package/src/components/ui/__tests__/popover.test.tsx +32 -0
  118. package/src/components/ui/__tests__/progress.test.tsx +24 -0
  119. package/src/components/ui/__tests__/select-callback.test.tsx +72 -0
  120. package/src/components/ui/__tests__/select.test.tsx +48 -0
  121. package/src/components/ui/__tests__/sidebar.test.tsx +121 -0
  122. package/src/components/ui/__tests__/stock-mirror.test.ts +39 -0
  123. package/src/components/ui/__tests__/subpath.test.tsx +38 -0
  124. package/src/components/ui/__tests__/switch.test.tsx +24 -0
  125. package/src/components/ui/__tests__/tabs.test.tsx +24 -0
  126. package/src/components/ui/__tests__/textarea.test.tsx +41 -0
  127. package/src/components/ui/alert-dialog.tsx +187 -0
  128. package/src/components/ui/avatar.tsx +108 -0
  129. package/src/components/ui/badge.tsx +51 -0
  130. package/src/components/ui/breadcrumb.tsx +124 -0
  131. package/src/components/ui/button.tsx +57 -0
  132. package/src/components/ui/card.tsx +102 -0
  133. package/src/components/ui/checkbox.tsx +28 -0
  134. package/src/components/ui/dialog.tsx +166 -0
  135. package/src/components/ui/dropdown-menu.tsx +265 -0
  136. package/src/components/ui/empty.tsx +103 -0
  137. package/src/components/ui/field.tsx +238 -0
  138. package/src/components/ui/input.tsx +19 -0
  139. package/src/components/ui/label.tsx +17 -0
  140. package/src/components/ui/popover.tsx +89 -0
  141. package/src/components/ui/progress.tsx +82 -0
  142. package/src/components/ui/select.tsx +235 -0
  143. package/src/components/ui/separator.tsx +24 -0
  144. package/src/components/ui/sheet.tsx +146 -0
  145. package/src/components/ui/sidebar.tsx +723 -0
  146. package/src/components/ui/skeleton.tsx +13 -0
  147. package/src/components/ui/switch.tsx +29 -0
  148. package/src/components/ui/tabs.tsx +79 -0
  149. package/src/components/ui/textarea.tsx +26 -0
  150. package/src/components/ui/tooltip.tsx +63 -0
  151. package/src/dev.css +1 -0
  152. package/src/hooks/use-mobile.ts +19 -0
  153. package/src/index.ts +150 -0
  154. package/src/layouts/AppShell.tsx +163 -0
  155. package/src/layouts/AuthShell.tsx +24 -0
  156. package/src/layouts/SettingsShell.tsx +129 -0
  157. package/src/layouts/__tests__/AppShell.test.tsx +163 -0
  158. package/src/layouts/__tests__/SettingsShell.test.tsx +146 -0
  159. package/src/lib/__tests__/api-error.test.ts +163 -0
  160. package/src/lib/__tests__/utils.test.ts +21 -0
  161. package/src/lib/api-error.ts +98 -0
  162. package/src/lib/utils.ts +109 -0
  163. package/src/pages/LandingPage.tsx +88 -0
  164. package/src/pages/LoginPage.tsx +291 -0
  165. package/src/pages/__tests__/LandingPage.test.tsx +58 -0
  166. package/src/pages/__tests__/LoginPage.test.tsx +229 -0
  167. package/src/pages/__tests__/RegisterPage.test.tsx +138 -0
  168. package/src/pages/__tests__/ssr-smoke.test.tsx +99 -0
  169. package/src/pages/account/NotificationPreferencesPage.tsx +138 -0
  170. package/src/pages/account/ProfileSettingsPage.tsx +189 -0
  171. package/src/pages/account/SecuritySettingsPage.tsx +214 -0
  172. package/src/pages/account/TokensPage.tsx +211 -0
  173. package/src/pages/account/__tests__/NotificationPreferencesPage.test.tsx +150 -0
  174. package/src/pages/account/__tests__/ProfileSettingsPage.test.tsx +173 -0
  175. package/src/pages/account/__tests__/SecuritySettingsPage.test.tsx +212 -0
  176. package/src/pages/account/__tests__/TokensPage.test.tsx +180 -0
  177. package/src/pages/admin/AdminSettingsPage.tsx +564 -0
  178. package/src/pages/admin/AdminShell.tsx +199 -0
  179. package/src/pages/admin/AuditPage.tsx +338 -0
  180. package/src/pages/admin/OrdersPage.tsx +642 -0
  181. package/src/pages/admin/OverviewPage.tsx +559 -0
  182. package/src/pages/admin/SSOPage.tsx +166 -0
  183. package/src/pages/admin/UserDetailPage.tsx +641 -0
  184. package/src/pages/admin/UsersPage.tsx +462 -0
  185. package/src/pages/admin/WebhookDeliveriesPage.tsx +318 -0
  186. package/src/pages/admin/WorkspaceDetailPage.tsx +551 -0
  187. package/src/pages/admin/WorkspacesPage.tsx +299 -0
  188. package/src/pages/admin/__tests__/AdminSettingsPage.test.tsx +260 -0
  189. package/src/pages/admin/__tests__/OrdersPageMarkPaid.test.tsx +207 -0
  190. package/src/pages/admin/__tests__/OverviewPageActivity.test.tsx +213 -0
  191. package/src/pages/admin/__tests__/SSOPage.test.tsx +128 -0
  192. package/src/pages/admin/__tests__/UsersPageActions.test.tsx +188 -0
  193. package/src/pages/admin/__tests__/WorkspaceDetailPageTransfer.test.tsx +170 -0
  194. package/src/pages/admin/__tests__/WorkspacesPagePlans.test.tsx +138 -0
  195. package/src/pages/admin/shared.ts +42 -0
  196. package/src/pages/auth/ForgotPasswordPage.tsx +83 -0
  197. package/src/pages/auth/InviteAcceptPage.tsx +105 -0
  198. package/src/pages/auth/RegisterPage.tsx +204 -0
  199. package/src/pages/auth/ResetPasswordPage.tsx +150 -0
  200. package/src/pages/auth/VerifyEmailPage.tsx +76 -0
  201. package/src/pages/auth/__tests__/ForgotPasswordPage.test.tsx +67 -0
  202. package/src/pages/auth/__tests__/InviteAcceptPage.test.tsx +86 -0
  203. package/src/pages/auth/__tests__/ResetPasswordPage.test.tsx +115 -0
  204. package/src/pages/auth/__tests__/VerifyEmailPage.test.tsx +74 -0
  205. package/src/pages/workspace/BillingPage.tsx +361 -0
  206. package/src/pages/workspace/BillingSuccessPage.tsx +115 -0
  207. package/src/pages/workspace/MembersPage.tsx +568 -0
  208. package/src/pages/workspace/RolePermissionsPage.tsx +202 -0
  209. package/src/pages/workspace/SchedulesPage.tsx +387 -0
  210. package/src/pages/workspace/UsagePage.tsx +207 -0
  211. package/src/pages/workspace/WebhooksPage.tsx +506 -0
  212. package/src/pages/workspace/WorkspaceAuditPage.tsx +229 -0
  213. package/src/pages/workspace/WorkspaceGeneralPage.tsx +184 -0
  214. package/src/pages/workspace/__tests__/BillingPage.test.tsx +302 -0
  215. package/src/pages/workspace/__tests__/BillingSuccessPage.test.tsx +134 -0
  216. package/src/pages/workspace/__tests__/MembersPage.test.tsx +347 -0
  217. package/src/pages/workspace/__tests__/RolePermissionsPage.test.tsx +138 -0
  218. package/src/pages/workspace/__tests__/SchedulesPage.test.tsx +239 -0
  219. package/src/pages/workspace/__tests__/UsagePage.test.tsx +223 -0
  220. package/src/pages/workspace/__tests__/WebhooksPage.test.tsx +309 -0
  221. package/src/pages/workspace/__tests__/WorkspaceAuditPage.test.tsx +112 -0
  222. package/src/pages/workspace/__tests__/WorkspaceGeneralPage.test.tsx +164 -0
@@ -3,22 +3,22 @@ import { useState } from 'react';
3
3
  import { Link, useNavigate, useParams } from 'react-router';
4
4
  import { ArrowLeft } from 'lucide-react';
5
5
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
6
- import { useConfirm } from '../../components/ConfirmDialog';
7
- import { DataTable } from '../../components/DataTable';
8
- import { FormField } from '../../components/FormField';
9
- import { PageEmpty, PageError, PageHeader } from '../../components/Page';
10
- import { ImpactConfirmation } from '../../components/SecretModal';
11
- import { SettingsCard } from '../../components/SettingsCard';
12
- import { toast } from '../../components/toast';
13
- import { Badge } from '../../components/ui/badge';
14
- import { Button } from '../../components/ui/button';
15
- import { Input } from '../../components/ui/input';
16
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../components/ui/select';
6
+ import { useConfirm } from '../../components/ConfirmDialog.js';
7
+ import { DataTable } from '../../components/DataTable.js';
8
+ import { FormField } from '../../components/FormField.js';
9
+ import { PageEmpty, PageError, PageHeader } from '../../components/Page.js';
10
+ import { ImpactConfirmation } from '../../components/SecretModal.js';
11
+ import { SettingsCard } from '../../components/SettingsCard.js';
12
+ import { toast } from '../../components/toast.js';
13
+ import { Badge } from '../../components/ui/badge.js';
14
+ import { Button } from '../../components/ui/button.js';
15
+ import { Input } from '../../components/ui/input.js';
16
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../components/ui/select.js';
17
17
  import { useApi } from '@ploykit/hooks';
18
18
  import { useAuth } from '@ploykit/hooks';
19
- import { apiErrorMessage } from '../../lib/api-error';
20
- import { formatDate, formatDateTime, shortID } from '../../lib/utils';
21
- import { adminError } from './shared';
19
+ import { apiErrorMessage } from '../../lib/api-error.js';
20
+ import { formatDate, formatDateTime, shortID } from '../../lib/utils.js';
21
+ import { adminError } from './shared.js';
22
22
  const ROLE_OPTIONS = ['owner', 'admin', 'member'];
23
23
  const QUOTA_KEY_HINT = '如 tasks_monthly';
24
24
  export function WorkspaceDetailPage() {
@@ -2,16 +2,16 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
3
  import { Link, useSearchParams } from 'react-router';
4
4
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
5
- import { DataTable } from '../../components/DataTable';
6
- import { PageEmpty, PageError, PageHeader } from '../../components/Page';
7
- import { toast } from '../../components/toast';
8
- import { Badge } from '../../components/ui/badge';
9
- import { Button } from '../../components/ui/button';
10
- import { Input } from '../../components/ui/input';
11
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../components/ui/select';
5
+ import { DataTable } from '../../components/DataTable.js';
6
+ import { PageEmpty, PageError, PageHeader } from '../../components/Page.js';
7
+ import { toast } from '../../components/toast.js';
8
+ import { Badge } from '../../components/ui/badge.js';
9
+ import { Button } from '../../components/ui/button.js';
10
+ import { Input } from '../../components/ui/input.js';
11
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../components/ui/select.js';
12
12
  import { useApi } from '@ploykit/hooks';
13
- import { formatDate } from '../../lib/utils';
14
- import { ADMIN_PAGE_SIZE, adminError, adminListQuery, } from './shared';
13
+ import { formatDate } from '../../lib/utils.js';
14
+ import { ADMIN_PAGE_SIZE, adminError, adminListQuery, } from './shared.js';
15
15
  const FALLBACK_PLAN_CODES = ['free'];
16
16
  export function WorkspacesPage() {
17
17
  const api = useApi();
@@ -1,5 +1,5 @@
1
1
  import { ApiError } from '@ploykit/hooks';
2
- import { apiErrorMessage } from '../../lib/api-error';
2
+ import { apiErrorMessage } from '../../lib/api-error.js';
3
3
  export const ADMIN_PAGE_SIZE = 20;
4
4
  export function adminError(err, fallback) {
5
5
  if (err instanceof ApiError && err.status === 403) {
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import { AuthShell } from '../../layouts/AuthShell';
4
- import { FormField } from '../../components/FormField';
5
- import { Button } from '../../components/ui/button';
6
- import { Input } from '../../components/ui/input';
3
+ import { AuthShell } from '../../layouts/AuthShell.js';
4
+ import { FormField } from '../../components/FormField.js';
5
+ import { Button } from '../../components/ui/button.js';
6
+ import { Input } from '../../components/ui/input.js';
7
7
  import { usePasswordReset } from '@ploykit/hooks';
8
8
  export function ForgotPasswordPage({ title = '找回密码', sentHint = '如果该邮箱存在,重置链接已发送,请查收邮箱。', backPath = '/login', }) {
9
9
  const { requestReset } = usePasswordReset();
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useNavigate } from 'react-router';
3
3
  import { Check, X } from 'lucide-react';
4
- import { Button } from '../../components/ui/button';
5
- import { Badge } from '../../components/ui/badge';
6
- import { PageLoading, PageEmpty } from '../../components/Page';
7
- import { toast } from '../../components/toast';
4
+ import { Button } from '../../components/ui/button.js';
5
+ import { Badge } from '../../components/ui/badge.js';
6
+ import { PageLoading, PageEmpty } from '../../components/Page.js';
7
+ import { toast } from '../../components/toast.js';
8
8
  import { useMyInvitations } from '@ploykit/hooks';
9
- import { formatDateTime } from '../../lib/utils';
10
- import { apiErrorMessage } from '../../lib/api-error';
9
+ import { formatDateTime } from '../../lib/utils.js';
10
+ import { apiErrorMessage } from '../../lib/api-error.js';
11
11
  const ROLE_LABEL = { owner: '所有者', admin: '管理员', member: '成员' };
12
12
  export function InviteAcceptPage({ onAccepted, onDeclined } = {}) {
13
13
  const navigate = useNavigate();
@@ -1,17 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { z } from 'zod';
4
- import { AuthShell } from '../../layouts/AuthShell';
5
- import { FormField } from '../../components/FormField';
6
- import { Button } from '../../components/ui/button';
7
- import { Input } from '../../components/ui/input';
8
- import { FieldDescription, FieldSeparator } from '../../components/ui/field';
4
+ import { AuthShell } from '../../layouts/AuthShell.js';
5
+ import { FormField } from '../../components/FormField.js';
6
+ import { Button } from '../../components/ui/button.js';
7
+ import { Input } from '../../components/ui/input.js';
8
+ import { FieldDescription, FieldSeparator } from '../../components/ui/field.js';
9
9
  import { useApi } from '@ploykit/hooks';
10
10
  import { useAuth } from '@ploykit/hooks';
11
11
  import { useSiteConfig } from '@ploykit/hooks';
12
12
  import { useZodForm } from '@ploykit/hooks';
13
- import { apiErrorMessage } from '../../lib/api-error';
14
- import { toast } from '../../components/toast';
13
+ import { apiErrorMessage } from '../../lib/api-error.js';
14
+ import { toast } from '../../components/toast.js';
15
15
  function passwordKinds(pw) {
16
16
  let kinds = 0;
17
17
  if (/[0-9]/.test(pw))
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
- import { AuthShell } from '../../layouts/AuthShell';
4
- import { FormField } from '../../components/FormField';
5
- import { Button } from '../../components/ui/button';
6
- import { Input } from '../../components/ui/input';
3
+ import { AuthShell } from '../../layouts/AuthShell.js';
4
+ import { FormField } from '../../components/FormField.js';
5
+ import { Button } from '../../components/ui/button.js';
6
+ import { Input } from '../../components/ui/input.js';
7
7
  import { usePasswordReset } from '@ploykit/hooks';
8
- import { passwordSchema } from './RegisterPage';
8
+ import { passwordSchema } from './RegisterPage.js';
9
9
  const REDIRECT_DELAY_MS = 3000;
10
10
  export function ResetPasswordPage({ onDone }) {
11
11
  const { reset } = usePasswordReset();
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState } from 'react';
3
3
  import { api } from '@ploykit/client';
4
- import { AuthShell } from '../../layouts/AuthShell';
5
- import { buttonVariants } from '../../components/ui/button';
6
- import { Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent, } from '../../components/ui/empty';
4
+ import { AuthShell } from '../../layouts/AuthShell.js';
5
+ import { buttonVariants } from '../../components/ui/button.js';
6
+ import { Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent, } from '../../components/ui/empty.js';
7
7
  import { MailCheck, LoaderCircle, CircleX } from 'lucide-react';
8
8
  export function VerifyEmailPage() {
9
9
  const [state, setState] = useState('verifying');
@@ -2,22 +2,22 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { useSearchParams } from 'react-router';
4
4
  import { useQuery, useQueryClient } from '@tanstack/react-query';
5
- import { PageHeader, PageLoading, PageError, PageEmpty } from '../../components/Page';
6
- import { DataTable } from '../../components/DataTable';
7
- import { SettingsCard } from '../../components/SettingsCard';
8
- import { useConfirm } from '../../components/ConfirmDialog';
9
- import { toast } from '../../components/toast';
10
- import { Button } from '../../components/ui/button';
11
- import { Badge } from '../../components/ui/badge';
12
- import { StatusBadge } from '../../components/StatusBadge';
13
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components/ui/select';
5
+ import { PageHeader, PageLoading, PageError, PageEmpty } from '../../components/Page.js';
6
+ import { DataTable } from '../../components/DataTable.js';
7
+ import { SettingsCard } from '../../components/SettingsCard.js';
8
+ import { useConfirm } from '../../components/ConfirmDialog.js';
9
+ import { toast } from '../../components/toast.js';
10
+ import { Button } from '../../components/ui/button.js';
11
+ import { Badge } from '../../components/ui/badge.js';
12
+ import { StatusBadge } from '../../components/StatusBadge.js';
13
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components/ui/select.js';
14
14
  import { useApi } from '@ploykit/hooks';
15
15
  import { useBilling } from '@ploykit/hooks';
16
16
  import { useSiteConfig } from '@ploykit/hooks';
17
17
  import { useWorkspace } from '@ploykit/hooks';
18
18
  import { queryKeys, } from '@ploykit/hooks';
19
- import { formatDateTime, cn } from '../../lib/utils';
20
- import { apiErrorMessage } from '../../lib/api-error';
19
+ import { formatDateTime, cn } from '../../lib/utils.js';
20
+ import { apiErrorMessage } from '../../lib/api-error.js';
21
21
  const INTERVAL_LABEL = { monthly: '按月', yearly: '按年' };
22
22
  const INTERVAL_UNIT = { monthly: '月', yearly: '年' };
23
23
  const CHANNEL_LABEL = {
@@ -2,8 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState } from 'react';
3
3
  import { useNavigate } from 'react-router';
4
4
  import { useQuery, useQueryClient } from '@tanstack/react-query';
5
- import { Skeleton } from '../../components/ui/skeleton';
6
- import { toast } from '../../components/toast';
5
+ import { Skeleton } from '../../components/ui/skeleton.js';
6
+ import { toast } from '../../components/toast.js';
7
7
  import { useApi } from '@ploykit/hooks';
8
8
  import { useWorkspace } from '@ploykit/hooks';
9
9
  import { queryKeys } from '@ploykit/hooks';
@@ -3,23 +3,23 @@ import { useState } from 'react';
3
3
  import { useSearchParams } from 'react-router';
4
4
  import { z } from 'zod';
5
5
  import { UserPlus, Link2 } from 'lucide-react';
6
- import { PageHeader, PageLoading, PageError, PageEmpty, } from '../../components/Page';
7
- import { DataTable } from '../../components/DataTable';
8
- import { FormField } from '../../components/FormField';
9
- import { SecretModal, ImpactConfirmation } from '../../components/SecretModal';
10
- import { useConfirm } from '../../components/ConfirmDialog';
11
- import { toast } from '../../components/toast';
12
- import { Button } from '../../components/ui/button';
13
- import { Input } from '../../components/ui/input';
14
- import { Badge } from '../../components/ui/badge';
15
- import { StatusBadge } from '../../components/StatusBadge';
16
- import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../components/ui/tabs';
17
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../components/ui/select';
18
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '../../components/ui/dialog';
6
+ import { PageHeader, PageLoading, PageError, PageEmpty, } from '../../components/Page.js';
7
+ import { DataTable } from '../../components/DataTable.js';
8
+ import { FormField } from '../../components/FormField.js';
9
+ import { SecretModal, ImpactConfirmation } from '../../components/SecretModal.js';
10
+ import { useConfirm } from '../../components/ConfirmDialog.js';
11
+ import { toast } from '../../components/toast.js';
12
+ import { Button } from '../../components/ui/button.js';
13
+ import { Input } from '../../components/ui/input.js';
14
+ import { Badge } from '../../components/ui/badge.js';
15
+ import { StatusBadge } from '../../components/StatusBadge.js';
16
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../components/ui/tabs.js';
17
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../components/ui/select.js';
18
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '../../components/ui/dialog.js';
19
19
  import { useZodForm } from '@ploykit/hooks';
20
20
  import { useMembers, useMemberMutations, ASSIGNABLE_ROLES, LIST_PAGE_SIZE, } from '@ploykit/hooks';
21
- import { formatDateTime } from '../../lib/utils';
22
- import { apiErrorMessage } from '../../lib/api-error';
21
+ import { formatDateTime } from '../../lib/utils.js';
22
+ import { apiErrorMessage } from '../../lib/api-error.js';
23
23
  import { roleSatisfies } from '@ploykit/hooks';
24
24
  const inviteSchema = z.object({
25
25
  email: z.string().min(1, '请输入邮箱').email('邮箱格式不正确'),
@@ -1,17 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from 'react';
3
3
  import { RotateCcw, Save } from 'lucide-react';
4
- import { PageHeader, PageLoading, PageError, } from '../../components/Page';
5
- import { SettingsCard } from '../../components/SettingsCard';
6
- import { ReauthDialog } from '../../components/ReauthDialog';
7
- import { useConfirm } from '../../components/ConfirmDialog';
8
- import { toast } from '../../components/toast';
9
- import { Button } from '../../components/ui/button';
10
- import { Badge } from '../../components/ui/badge';
11
- import { Checkbox } from '../../components/ui/checkbox';
4
+ import { PageHeader, PageLoading, PageError, } from '../../components/Page.js';
5
+ import { SettingsCard } from '../../components/SettingsCard.js';
6
+ import { ReauthDialog } from '../../components/ReauthDialog.js';
7
+ import { useConfirm } from '../../components/ConfirmDialog.js';
8
+ import { toast } from '../../components/toast.js';
9
+ import { Button } from '../../components/ui/button.js';
10
+ import { Badge } from '../../components/ui/badge.js';
11
+ import { Checkbox } from '../../components/ui/checkbox.js';
12
12
  import { useRoleConfig } from '@ploykit/hooks';
13
13
  import { isApiError } from '@ploykit/client';
14
- import { apiErrorMessage } from '../../lib/api-error';
14
+ import { apiErrorMessage } from '../../lib/api-error.js';
15
15
  const ROLE_LABEL = { owner: '所有者', admin: '管理员', member: '成员' };
16
16
  const DOMAIN_LABEL = {
17
17
  workspace: '工作区',
@@ -3,21 +3,21 @@ import { useState } from 'react';
3
3
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
4
4
  import { Plus } from 'lucide-react';
5
5
  import { z } from 'zod';
6
- import { PageHeader, PageLoading, PageError, PageEmpty, } from '../../components/Page';
7
- import { DataTable } from '../../components/DataTable';
8
- import { FormField } from '../../components/FormField';
9
- import { CronInput, describeCron } from '../../components/CronInput';
10
- import { toast } from '../../components/toast';
11
- import { Button } from '../../components/ui/button';
12
- import { Input } from '../../components/ui/input';
13
- import { Switch } from '../../components/ui/switch';
14
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '../../components/ui/dialog';
6
+ import { PageHeader, PageLoading, PageError, PageEmpty, } from '../../components/Page.js';
7
+ import { DataTable } from '../../components/DataTable.js';
8
+ import { FormField } from '../../components/FormField.js';
9
+ import { CronInput, describeCron } from '../../components/CronInput.js';
10
+ import { toast } from '../../components/toast.js';
11
+ import { Button } from '../../components/ui/button.js';
12
+ import { Input } from '../../components/ui/input.js';
13
+ import { Switch } from '../../components/ui/switch.js';
14
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '../../components/ui/dialog.js';
15
15
  import { useApi } from '@ploykit/hooks';
16
16
  import { useWorkspace } from '@ploykit/hooks';
17
17
  import { useZodForm } from '@ploykit/hooks';
18
- import { useConfirm } from '../../components/ConfirmDialog';
19
- import { browserTzLabel, formatDateTimeTz } from '../../lib/utils';
20
- import { apiErrorMessage } from '../../lib/api-error';
18
+ import { useConfirm } from '../../components/ConfirmDialog.js';
19
+ import { browserTzLabel, formatDateTimeTz } from '../../lib/utils.js';
20
+ import { apiErrorMessage } from '../../lib/api-error.js';
21
21
  export const MISFIRE_LABEL = {
22
22
  skip: '错过跳过',
23
23
  once: '错过补发',
@@ -1,12 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Link } from 'react-router';
3
- import { PageHeader, PageLoading, PageError, PageEmpty } from '../../components/Page';
4
- import { Badge } from '../../components/ui/badge';
5
- import { Card, CardHeader, CardTitle, CardAction, CardContent } from '../../components/ui/card';
6
- import { Progress, ProgressLabel, ProgressValue, } from '../../components/ui/progress';
7
- import { DataTable } from '../../components/DataTable';
3
+ import { PageHeader, PageLoading, PageError, PageEmpty } from '../../components/Page.js';
4
+ import { Badge } from '../../components/ui/badge.js';
5
+ import { Card, CardHeader, CardTitle, CardAction, CardContent } from '../../components/ui/card.js';
6
+ import { Progress, ProgressLabel, ProgressValue, } from '../../components/ui/progress.js';
7
+ import { DataTable } from '../../components/DataTable.js';
8
8
  import { useUsage } from '@ploykit/hooks';
9
- import { apiErrorMessage } from '../../lib/api-error';
9
+ import { apiErrorMessage } from '../../lib/api-error.js';
10
10
  const NEAR_FULL_PCT = 80;
11
11
  const DIM_LABEL = {
12
12
  tasks_monthly: '任务数(本月)',
@@ -3,26 +3,26 @@ import { useMemo, useState } from 'react';
3
3
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
4
4
  import { MoreHorizontal, Plus } from 'lucide-react';
5
5
  import { z } from 'zod';
6
- import { PageHeader, PageLoading, PageError, PageEmpty, } from '../../components/Page';
7
- import { DataTable } from '../../components/DataTable';
8
- import { FormField } from '../../components/FormField';
9
- import { SecretModal } from '../../components/SecretModal';
10
- import { useConfirm } from '../../components/ConfirmDialog';
11
- import { toast } from '../../components/toast';
12
- import { Button } from '../../components/ui/button';
13
- import { Input } from '../../components/ui/input';
14
- import { StatusBadge } from '../../components/StatusBadge';
15
- import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../components/ui/tabs';
16
- import { Switch } from '../../components/ui/switch';
17
- import { Checkbox } from '../../components/ui/checkbox';
18
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '../../components/ui/dialog';
19
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '../../components/ui/dropdown-menu';
6
+ import { PageHeader, PageLoading, PageError, PageEmpty, } from '../../components/Page.js';
7
+ import { DataTable } from '../../components/DataTable.js';
8
+ import { FormField } from '../../components/FormField.js';
9
+ import { SecretModal } from '../../components/SecretModal.js';
10
+ import { useConfirm } from '../../components/ConfirmDialog.js';
11
+ import { toast } from '../../components/toast.js';
12
+ import { Button } from '../../components/ui/button.js';
13
+ import { Input } from '../../components/ui/input.js';
14
+ import { StatusBadge } from '../../components/StatusBadge.js';
15
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../components/ui/tabs.js';
16
+ import { Switch } from '../../components/ui/switch.js';
17
+ import { Checkbox } from '../../components/ui/checkbox.js';
18
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '../../components/ui/dialog.js';
19
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '../../components/ui/dropdown-menu.js';
20
20
  import { useApi } from '@ploykit/hooks';
21
21
  import { useWorkspace } from '@ploykit/hooks';
22
22
  import { useZodForm } from '@ploykit/hooks';
23
23
  import { queryKeys } from '@ploykit/hooks';
24
- import { formatDateTime } from '../../lib/utils';
25
- import { apiErrorMessage } from '../../lib/api-error';
24
+ import { formatDateTime } from '../../lib/utils.js';
25
+ import { apiErrorMessage } from '../../lib/api-error.js';
26
26
  import { roleSatisfies } from '@ploykit/hooks';
27
27
  const createSchema = z.object({
28
28
  url: z
@@ -2,14 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useEffect, useMemo, useState } from 'react';
3
3
  import { useSearchParams } from 'react-router';
4
4
  import { Download, Search } from 'lucide-react';
5
- import { PageHeader, PageLoading, PageError, PageEmpty } from '../../components/Page';
6
- import { DataTable } from '../../components/DataTable';
7
- import { Button } from '../../components/ui/button';
8
- import { Input } from '../../components/ui/input';
9
- import { toast } from '../../components/toast';
5
+ import { PageHeader, PageLoading, PageError, PageEmpty } from '../../components/Page.js';
6
+ import { DataTable } from '../../components/DataTable.js';
7
+ import { Button } from '../../components/ui/button.js';
8
+ import { Input } from '../../components/ui/input.js';
9
+ import { toast } from '../../components/toast.js';
10
10
  import { useAudit, exportAuditCsv, } from '@ploykit/hooks';
11
- import { formatDateTime } from '../../lib/utils';
12
- import { apiErrorMessage } from '../../lib/api-error';
11
+ import { formatDateTime } from '../../lib/utils.js';
12
+ import { apiErrorMessage } from '../../lib/api-error.js';
13
13
  const PAGE_SIZE = 20;
14
14
  function draftFromParams(p) {
15
15
  return {
@@ -3,19 +3,19 @@ import { useState } from 'react';
3
3
  import { useNavigate } from 'react-router';
4
4
  import { useQueryClient } from '@tanstack/react-query';
5
5
  import { z } from 'zod';
6
- import { PageHeader, PageError } from '../../components/Page';
7
- import { SettingsCard } from '../../components/SettingsCard';
8
- import { FormField } from '../../components/FormField';
9
- import { ImpactConfirmation } from '../../components/SecretModal';
10
- import { useConfirm } from '../../components/ConfirmDialog';
11
- import { toast } from '../../components/toast';
12
- import { Button } from '../../components/ui/button';
13
- import { Input } from '../../components/ui/input';
6
+ import { PageHeader, PageError } from '../../components/Page.js';
7
+ import { SettingsCard } from '../../components/SettingsCard.js';
8
+ import { FormField } from '../../components/FormField.js';
9
+ import { ImpactConfirmation } from '../../components/SecretModal.js';
10
+ import { useConfirm } from '../../components/ConfirmDialog.js';
11
+ import { toast } from '../../components/toast.js';
12
+ import { Button } from '../../components/ui/button.js';
13
+ import { Input } from '../../components/ui/input.js';
14
14
  import { useApi } from '@ploykit/hooks';
15
15
  import { useWorkspace } from '@ploykit/hooks';
16
16
  import { useZodForm } from '@ploykit/hooks';
17
17
  import { queryKeys } from '@ploykit/hooks';
18
- import { apiErrorMessage } from '../../lib/api-error';
18
+ import { apiErrorMessage } from '../../lib/api-error.js';
19
19
  import { roleSatisfies } from '@ploykit/hooks';
20
20
  const renameSchema = z.object({
21
21
  name: z.string().trim().min(1, '请输入工作区名称').max(64, '名称最多 64 字符'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ploykit/ui",
3
- "version": "0.5.0",
3
+ "version": "0.6.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,7 +18,8 @@
18
18
  "./package.json": "./package.json"
19
19
  },
20
20
  "files": [
21
- "dist"
21
+ "dist",
22
+ "src"
22
23
  ],
23
24
  "peerDependencies": {
24
25
  "@tanstack/react-query": "^5.0.0",
@@ -29,8 +30,8 @@
29
30
  },
30
31
  "dependencies": {
31
32
  "@base-ui/react": "^1.8.0",
32
- "@ploykit/client": "^0.5.0",
33
- "@ploykit/hooks": "^0.5.0",
33
+ "@ploykit/client": "^0.6.2",
34
+ "@ploykit/hooks": "^0.6.2",
34
35
  "class-variance-authority": "^0.7.1",
35
36
  "clsx": "^2.1.1",
36
37
  "cn": "^0.4.0",
@@ -41,7 +42,7 @@
41
42
  },
42
43
  "description": "React 前端壳:登录/工作区/计费的 Headless Hook + 默认页面。产物为 ESM(相对导入无扩展名,消费方需经 vite/esbuild 等打包器解析);exports 的 development 条件指向源码,供 monorepo 开发期直出消费。",
43
44
  "scripts": {
44
- "build": "tsc -p tsconfig.json",
45
+ "build": "tsc -p tsconfig.json && node ../../tools/fix-esm-extensions.mjs dist",
45
46
  "test": "vitest run",
46
47
  "prepublishOnly": "npm run build"
47
48
  },
@@ -0,0 +1,29 @@
1
+
2
+ import type { ReactNode } from 'react'
3
+ import type { QueryClient } from '@tanstack/react-query'
4
+ import { PloykitProvider } from '@ploykit/hooks'
5
+ import { ConfirmProvider } from './components/ConfirmDialog'
6
+ import { Toaster } from './components/toast'
7
+
8
+ /**
9
+ * 框架级全局 Provider 一步到位组合件:PloykitProvider > ConfirmProvider > Toaster。
10
+ *
11
+ * 产品侧用它替换"逐个手挂三层 Provider"的样板(example/web/src/routes.tsx 的
12
+ * AppProviders 即此组合的 historically hand-written 版本)。嵌套顺序即依赖顺序:
13
+ * confirm 与 toast 均不依赖 auth/workspace 上下文,但统一挂在最外层可保证任何
14
+ * 页面(含登录前页面)都能调用 useConfirm / toast。
15
+ */
16
+ export function AppProviders({ children, queryClient }: {
17
+ children: ReactNode
18
+ /** 透传给 PloykitProvider;不传时由其内部创建默认 QueryClient。 */
19
+ queryClient?: QueryClient
20
+ }) {
21
+ return (
22
+ <PloykitProvider queryClient={queryClient}>
23
+ <ConfirmProvider>
24
+ {children}
25
+ <Toaster />
26
+ </ConfirmProvider>
27
+ </PloykitProvider>
28
+ )
29
+ }
@@ -0,0 +1,77 @@
1
+
2
+ import { createContext, useCallback, useContext, useState, type ReactNode } from 'react'
3
+ import {
4
+ AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle,
5
+ AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction,
6
+ } from './ui/alert-dialog'
7
+
8
+ interface ConfirmOptions {
9
+ title: string
10
+ description?: string
11
+ confirmText?: string
12
+ cancelText?: string
13
+ danger?: boolean
14
+ }
15
+
16
+ // 缺省值必须是 null + useConfirm fail-fast(对齐 hooks 包 useAuthCtx 的行为):
17
+ // 曾经的缺省值是 `async () => false`,产品忘挂 ConfirmProvider 时 confirm 静默返回
18
+ // false,"重置 Key"之类的按钮点了没反应且无任何报错,排查损耗极大。
19
+ const ConfirmContext = createContext<((opts: ConfirmOptions) => Promise<boolean>) | null>(null)
20
+
21
+ export function ConfirmProvider({ children }: { children: ReactNode }) {
22
+ const [state, setState] = useState<(ConfirmOptions & { resolve: (v: boolean) => void }) | null>(null)
23
+
24
+ const confirm = useCallback((opts: ConfirmOptions) => {
25
+
26
+
27
+
28
+
29
+ return new Promise<boolean>((resolve) => {
30
+ let settled = false
31
+ setState({
32
+ ...opts,
33
+ resolve: (v: boolean) => {
34
+ if (settled) return
35
+ settled = true
36
+ resolve(v)
37
+ },
38
+ })
39
+ })
40
+ }, [])
41
+
42
+ const handleClose = (result: boolean) => {
43
+ state?.resolve(result)
44
+ setState(null)
45
+ }
46
+
47
+ return (
48
+ <ConfirmContext.Provider value={confirm}>
49
+ {children}
50
+ <AlertDialog open={!!state} onOpenChange={(open: boolean) => !open && handleClose(false)}>
51
+ <AlertDialogContent>
52
+ <AlertDialogHeader>
53
+ <AlertDialogTitle>{state?.title}</AlertDialogTitle>
54
+ {state?.description && <AlertDialogDescription>{state.description}</AlertDialogDescription>}
55
+ </AlertDialogHeader>
56
+ <AlertDialogFooter>
57
+ <AlertDialogCancel onClick={() => handleClose(false)}>
58
+ {state?.cancelText ?? '取消'}
59
+ </AlertDialogCancel>
60
+ <AlertDialogAction
61
+ variant={state?.danger ? 'destructive' : 'default'}
62
+ onClick={() => handleClose(true)}
63
+ >
64
+ {state?.confirmText ?? '确认'}
65
+ </AlertDialogAction>
66
+ </AlertDialogFooter>
67
+ </AlertDialogContent>
68
+ </AlertDialog>
69
+ </ConfirmContext.Provider>
70
+ )
71
+ }
72
+
73
+ export function useConfirm() {
74
+ const confirm = useContext(ConfirmContext)
75
+ if (!confirm) throw new Error('useConfirm must be used within ConfirmProvider')
76
+ return confirm
77
+ }