@pactor-app/ui 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/chunk-57NRUZ5G.js +95 -0
- package/dist/chunk-DMK6RSTK.js +746 -0
- package/dist/chunk-OH3U6PCM.js +536 -0
- package/dist/chunk-OUTSIJMO.js +442 -0
- package/dist/chunk-QDTVOJ5P.js +147 -0
- package/dist/chunk-QWZ23QLS.js +68 -0
- package/dist/chunk-RQHJBTEU.js +10 -0
- package/dist/chunk-SNFDI77B.js +136 -0
- package/dist/chunk-XGOTHOI6.js +619 -0
- package/dist/components/index.cjs +1111 -0
- package/dist/components/index.d.cts +307 -0
- package/dist/components/index.d.ts +307 -0
- package/dist/components/index.js +40 -0
- package/dist/index.cjs +2626 -0
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +87 -0
- package/dist/interaction/index.cjs +752 -0
- package/dist/interaction/index.d.cts +178 -0
- package/dist/interaction/index.d.ts +178 -0
- package/dist/interaction/index.js +19 -0
- package/dist/layout/index.cjs +938 -0
- package/dist/layout/index.d.cts +158 -0
- package/dist/layout/index.d.ts +158 -0
- package/dist/layout/index.js +25 -0
- package/dist/ui/index.cjs +1076 -0
- package/dist/ui/index.d.cts +166 -0
- package/dist/ui/index.d.ts +166 -0
- package/dist/ui/index.js +233 -0
- package/package.json +127 -0
- package/styles.css +1672 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2626 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
Alert: () => Alert2,
|
|
34
|
+
Button: () => Button2,
|
|
35
|
+
Card: () => Card2,
|
|
36
|
+
Flex: () => Flex,
|
|
37
|
+
Form: () => Form,
|
|
38
|
+
Grid: () => Grid,
|
|
39
|
+
Input: () => Input2,
|
|
40
|
+
OVERLAY_CANCEL_PAYLOAD: () => OVERLAY_CANCEL_PAYLOAD,
|
|
41
|
+
OverlayManager: () => OverlayManager,
|
|
42
|
+
Page: () => Page,
|
|
43
|
+
Select: () => Select2,
|
|
44
|
+
ShadcnAdminLayout: () => ShadcnAdminLayout,
|
|
45
|
+
ShadcnBlankLayout: () => ShadcnBlankLayout,
|
|
46
|
+
ShadcnInteractionProvider: () => ShadcnInteractionProvider,
|
|
47
|
+
ShadcnLandingLayout: () => ShadcnLandingLayout,
|
|
48
|
+
ShadcnLoginLayout: () => ShadcnLoginLayout,
|
|
49
|
+
ShadcnOverlayHost: () => ShadcnOverlayHost,
|
|
50
|
+
Statistic: () => Statistic,
|
|
51
|
+
Table: () => Table2,
|
|
52
|
+
Tabs: () => Tabs2,
|
|
53
|
+
collectDefaultOpenKeys: () => collectDefaultOpenKeys,
|
|
54
|
+
createShadcnComponentRegistry: () => createShadcnComponentRegistry,
|
|
55
|
+
createShadcnLayoutRegistry: () => createShadcnLayoutRegistry,
|
|
56
|
+
createUiBridge: () => createUiBridge,
|
|
57
|
+
findMenuChain: () => findMenuChain,
|
|
58
|
+
registerInteractionActions: () => registerInteractionActions,
|
|
59
|
+
registerShadcnComponents: () => registerShadcnComponents,
|
|
60
|
+
registerShadcnLayouts: () => registerShadcnLayouts,
|
|
61
|
+
resolveLayout: () => resolveLayout,
|
|
62
|
+
shadcnComponents: () => shadcnComponents,
|
|
63
|
+
shadcnUiKit: () => shadcnUiKit,
|
|
64
|
+
useFormContext: () => useFormContext
|
|
65
|
+
});
|
|
66
|
+
module.exports = __toCommonJS(index_exports);
|
|
67
|
+
|
|
68
|
+
// src/components/register.ts
|
|
69
|
+
var import_core = require("@pactor-app/core");
|
|
70
|
+
|
|
71
|
+
// src/ui/alert.tsx
|
|
72
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
73
|
+
|
|
74
|
+
// src/lib/utils.ts
|
|
75
|
+
var import_clsx = require("clsx");
|
|
76
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
77
|
+
function cn(...inputs) {
|
|
78
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/ui/alert.tsx
|
|
82
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
83
|
+
var alertVariants = (0, import_class_variance_authority.cva)(
|
|
84
|
+
"relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border border-border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
|
|
85
|
+
{
|
|
86
|
+
variants: {
|
|
87
|
+
variant: {
|
|
88
|
+
default: "bg-card text-card-foreground",
|
|
89
|
+
destructive: "border-destructive/50 text-destructive bg-card [&>svg]:text-current",
|
|
90
|
+
success: "border-success/50 text-success bg-card [&>svg]:text-current",
|
|
91
|
+
warning: "border-warning/50 text-warning bg-card [&>svg]:text-current",
|
|
92
|
+
info: "border-info/50 text-info bg-card [&>svg]:text-current"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
defaultVariants: {
|
|
96
|
+
variant: "default"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
function Alert({
|
|
101
|
+
className,
|
|
102
|
+
variant,
|
|
103
|
+
...props
|
|
104
|
+
}) {
|
|
105
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
106
|
+
"div",
|
|
107
|
+
{
|
|
108
|
+
"data-slot": "alert",
|
|
109
|
+
role: "alert",
|
|
110
|
+
className: cn(alertVariants({ variant }), className),
|
|
111
|
+
...props
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
function AlertTitle({ className, ...props }) {
|
|
116
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
117
|
+
"div",
|
|
118
|
+
{
|
|
119
|
+
"data-slot": "alert-title",
|
|
120
|
+
className: cn(
|
|
121
|
+
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
|
|
122
|
+
className
|
|
123
|
+
),
|
|
124
|
+
...props
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
function AlertDescription({
|
|
129
|
+
className,
|
|
130
|
+
...props
|
|
131
|
+
}) {
|
|
132
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
133
|
+
"div",
|
|
134
|
+
{
|
|
135
|
+
"data-slot": "alert-description",
|
|
136
|
+
className: cn(
|
|
137
|
+
"col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground [&_p]:leading-relaxed",
|
|
138
|
+
className
|
|
139
|
+
),
|
|
140
|
+
...props
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/components/components/Alert/index.tsx
|
|
146
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
147
|
+
var variantMap = {
|
|
148
|
+
success: "success",
|
|
149
|
+
info: "info",
|
|
150
|
+
warning: "warning",
|
|
151
|
+
error: "destructive"
|
|
152
|
+
};
|
|
153
|
+
function Alert2({ message, description, variant = "info" }) {
|
|
154
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Alert, { variant: variantMap[variant], children: [
|
|
155
|
+
message ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AlertTitle, { children: message }) : null,
|
|
156
|
+
description ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AlertDescription, { children: description }) : null
|
|
157
|
+
] });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/components/components/Button/index.tsx
|
|
161
|
+
var import_lucide_react = require("lucide-react");
|
|
162
|
+
|
|
163
|
+
// src/ui/button.tsx
|
|
164
|
+
var import_button = require("@base-ui/react/button");
|
|
165
|
+
var import_class_variance_authority2 = require("class-variance-authority");
|
|
166
|
+
var React = __toESM(require("react"), 1);
|
|
167
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
168
|
+
var buttonVariants = (0, import_class_variance_authority2.cva)(
|
|
169
|
+
"inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium outline-none transition-colors focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
170
|
+
{
|
|
171
|
+
variants: {
|
|
172
|
+
variant: {
|
|
173
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
174
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/20",
|
|
175
|
+
outline: "border border-border bg-background hover:bg-accent hover:text-accent-foreground",
|
|
176
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
177
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
178
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
179
|
+
},
|
|
180
|
+
size: {
|
|
181
|
+
default: "h-9 px-4 py-2",
|
|
182
|
+
sm: "h-8 gap-1.5 rounded-md px-3 text-xs",
|
|
183
|
+
lg: "h-10 rounded-md px-6",
|
|
184
|
+
icon: "size-9"
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
defaultVariants: {
|
|
188
|
+
variant: "default",
|
|
189
|
+
size: "default"
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
function Button({
|
|
194
|
+
className,
|
|
195
|
+
variant,
|
|
196
|
+
size,
|
|
197
|
+
asChild = false,
|
|
198
|
+
children,
|
|
199
|
+
...props
|
|
200
|
+
}) {
|
|
201
|
+
if (asChild && React.isValidElement(children)) {
|
|
202
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
203
|
+
import_button.Button,
|
|
204
|
+
{
|
|
205
|
+
"data-slot": "button",
|
|
206
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
207
|
+
render: children,
|
|
208
|
+
...props
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
213
|
+
import_button.Button,
|
|
214
|
+
{
|
|
215
|
+
"data-slot": "button",
|
|
216
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
217
|
+
...props,
|
|
218
|
+
children
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/components/components/Button/index.tsx
|
|
224
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
225
|
+
var variantMap2 = {
|
|
226
|
+
default: "outline",
|
|
227
|
+
primary: "default",
|
|
228
|
+
dashed: "outline",
|
|
229
|
+
link: "link",
|
|
230
|
+
text: "ghost"
|
|
231
|
+
};
|
|
232
|
+
var sizeMap = {
|
|
233
|
+
small: "sm",
|
|
234
|
+
middle: "default",
|
|
235
|
+
large: "lg"
|
|
236
|
+
};
|
|
237
|
+
function Button2({
|
|
238
|
+
text,
|
|
239
|
+
variant = "default",
|
|
240
|
+
danger,
|
|
241
|
+
size = "middle",
|
|
242
|
+
loading,
|
|
243
|
+
disabled,
|
|
244
|
+
submit,
|
|
245
|
+
onClick,
|
|
246
|
+
children
|
|
247
|
+
}) {
|
|
248
|
+
const textual = variant === "link" || variant === "text";
|
|
249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
250
|
+
Button,
|
|
251
|
+
{
|
|
252
|
+
type: submit ? "submit" : "button",
|
|
253
|
+
variant: danger && !textual ? "destructive" : variantMap2[variant],
|
|
254
|
+
size: sizeMap[size],
|
|
255
|
+
disabled: disabled ?? loading,
|
|
256
|
+
"aria-busy": loading || void 0,
|
|
257
|
+
onClick: () => onClick?.(),
|
|
258
|
+
className: cn(
|
|
259
|
+
variant === "dashed" && "border-dashed",
|
|
260
|
+
danger && textual && "text-destructive hover:text-destructive"
|
|
261
|
+
),
|
|
262
|
+
children: [
|
|
263
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.Loader2, { "aria-hidden": true, className: "animate-spin" }) : null,
|
|
264
|
+
text ?? children
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// src/ui/card.tsx
|
|
271
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
272
|
+
function Card({ className, ...props }) {
|
|
273
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
274
|
+
"div",
|
|
275
|
+
{
|
|
276
|
+
"data-slot": "card",
|
|
277
|
+
className: cn(
|
|
278
|
+
"flex flex-col gap-6 rounded-xl border border-border bg-card py-6 text-card-foreground shadow-sm",
|
|
279
|
+
className
|
|
280
|
+
),
|
|
281
|
+
...props
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
function CardHeader({ className, ...props }) {
|
|
286
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
287
|
+
"div",
|
|
288
|
+
{
|
|
289
|
+
"data-slot": "card-header",
|
|
290
|
+
className: cn(
|
|
291
|
+
"grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
|
292
|
+
className
|
|
293
|
+
),
|
|
294
|
+
...props
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
function CardTitle({ className, ...props }) {
|
|
299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
300
|
+
"div",
|
|
301
|
+
{
|
|
302
|
+
"data-slot": "card-title",
|
|
303
|
+
className: cn("leading-none font-semibold", className),
|
|
304
|
+
...props
|
|
305
|
+
}
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
function CardContent({ className, ...props }) {
|
|
309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
310
|
+
"div",
|
|
311
|
+
{
|
|
312
|
+
"data-slot": "card-content",
|
|
313
|
+
className: cn("px-6", className),
|
|
314
|
+
...props
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/components/components/Card/index.tsx
|
|
320
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
321
|
+
function Card2({ title, bordered = true, children }) {
|
|
322
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
323
|
+
Card,
|
|
324
|
+
{
|
|
325
|
+
className: cn("gap-4 py-4", !bordered && "border-transparent shadow-none"),
|
|
326
|
+
children: [
|
|
327
|
+
title ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardHeader, { className: "px-4", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardTitle, { children: title }) }) : null,
|
|
328
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardContent, { className: "px-4", children })
|
|
329
|
+
]
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/components/components/Flex/index.tsx
|
|
335
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
336
|
+
var gapClass = {
|
|
337
|
+
small: "gap-2",
|
|
338
|
+
middle: "gap-4",
|
|
339
|
+
large: "gap-6"
|
|
340
|
+
};
|
|
341
|
+
var justifyClass = {
|
|
342
|
+
start: "justify-start",
|
|
343
|
+
center: "justify-center",
|
|
344
|
+
end: "justify-end",
|
|
345
|
+
"space-between": "justify-between",
|
|
346
|
+
"space-around": "justify-around",
|
|
347
|
+
"space-evenly": "justify-evenly"
|
|
348
|
+
};
|
|
349
|
+
var alignClass = {
|
|
350
|
+
start: "items-start",
|
|
351
|
+
center: "items-center",
|
|
352
|
+
end: "items-end",
|
|
353
|
+
baseline: "items-baseline",
|
|
354
|
+
stretch: "items-stretch"
|
|
355
|
+
};
|
|
356
|
+
function Flex({
|
|
357
|
+
direction = "horizontal",
|
|
358
|
+
gap,
|
|
359
|
+
justify,
|
|
360
|
+
align,
|
|
361
|
+
children
|
|
362
|
+
}) {
|
|
363
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
364
|
+
"div",
|
|
365
|
+
{
|
|
366
|
+
"data-slot": "flex",
|
|
367
|
+
className: cn(
|
|
368
|
+
"flex",
|
|
369
|
+
direction === "vertical" && "flex-col",
|
|
370
|
+
typeof gap === "string" && gapClass[gap],
|
|
371
|
+
justify && justifyClass[justify],
|
|
372
|
+
align && alignClass[align]
|
|
373
|
+
),
|
|
374
|
+
style: typeof gap === "number" ? { gap } : void 0,
|
|
375
|
+
children
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// src/components/components/Form/index.tsx
|
|
381
|
+
var import_runtime = require("@pactor-app/runtime");
|
|
382
|
+
var import_react2 = require("react");
|
|
383
|
+
|
|
384
|
+
// src/components/components/Form/context.ts
|
|
385
|
+
var import_react = require("react");
|
|
386
|
+
var FormReactContext = (0, import_react.createContext)(null);
|
|
387
|
+
var FormContextProvider = FormReactContext.Provider;
|
|
388
|
+
function useFormContext() {
|
|
389
|
+
return (0, import_react.useContext)(FormReactContext);
|
|
390
|
+
}
|
|
391
|
+
function formItemClass(layout) {
|
|
392
|
+
switch (layout) {
|
|
393
|
+
case "horizontal":
|
|
394
|
+
return "mb-4 flex items-baseline gap-2";
|
|
395
|
+
case "inline":
|
|
396
|
+
return "flex items-center gap-2";
|
|
397
|
+
default:
|
|
398
|
+
return "mb-4 flex flex-col gap-1.5";
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/components/components/Form/index.tsx
|
|
403
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
404
|
+
function isEmpty(value) {
|
|
405
|
+
return value === void 0 || value === null || value === "";
|
|
406
|
+
}
|
|
407
|
+
function Form({
|
|
408
|
+
name = "default",
|
|
409
|
+
layout = "vertical",
|
|
410
|
+
initialValues,
|
|
411
|
+
children,
|
|
412
|
+
onSubmit,
|
|
413
|
+
onValuesChange
|
|
414
|
+
}) {
|
|
415
|
+
const { context } = (0, import_runtime.useRenderer)();
|
|
416
|
+
const [values, setValues] = (0, import_react2.useState)(() => ({
|
|
417
|
+
...initialValues
|
|
418
|
+
}));
|
|
419
|
+
const [errors, setErrors] = (0, import_react2.useState)({});
|
|
420
|
+
const fieldRulesRef = (0, import_react2.useRef)(/* @__PURE__ */ new Map());
|
|
421
|
+
const mergedInitialFieldsRef = (0, import_react2.useRef)(/* @__PURE__ */ new Set());
|
|
422
|
+
const setValuesBatch = (0, import_react2.useCallback)((partial) => {
|
|
423
|
+
setValues((prev) => ({ ...prev, ...partial }));
|
|
424
|
+
}, []);
|
|
425
|
+
(0, import_react2.useEffect)(() => {
|
|
426
|
+
context.forms.register(name, { setValues: setValuesBatch });
|
|
427
|
+
return () => {
|
|
428
|
+
context.forms.unregister(name);
|
|
429
|
+
};
|
|
430
|
+
}, [context, name, setValuesBatch]);
|
|
431
|
+
const formContext = (0, import_react2.useMemo)(
|
|
432
|
+
() => ({
|
|
433
|
+
inForm: true,
|
|
434
|
+
layout,
|
|
435
|
+
values,
|
|
436
|
+
errors,
|
|
437
|
+
setValue(name2, value) {
|
|
438
|
+
const next = { ...values, [name2]: value };
|
|
439
|
+
setValues(next);
|
|
440
|
+
setErrors((prev) => {
|
|
441
|
+
if (!(name2 in prev)) {
|
|
442
|
+
return prev;
|
|
443
|
+
}
|
|
444
|
+
const rest = { ...prev };
|
|
445
|
+
delete rest[name2];
|
|
446
|
+
return rest;
|
|
447
|
+
});
|
|
448
|
+
onValuesChange?.({ [name2]: value }, next);
|
|
449
|
+
},
|
|
450
|
+
setValues: setValuesBatch,
|
|
451
|
+
registerField(name2, rules, initialValue) {
|
|
452
|
+
fieldRulesRef.current.set(name2, rules);
|
|
453
|
+
if (initialValue !== void 0 && !mergedInitialFieldsRef.current.has(name2)) {
|
|
454
|
+
mergedInitialFieldsRef.current.add(name2);
|
|
455
|
+
setValues((prev) => ({ ...prev, [name2]: initialValue }));
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
unregisterField(name2) {
|
|
459
|
+
fieldRulesRef.current.delete(name2);
|
|
460
|
+
}
|
|
461
|
+
}),
|
|
462
|
+
[layout, values, errors, onValuesChange, setValuesBatch]
|
|
463
|
+
);
|
|
464
|
+
const handleSubmit = (event) => {
|
|
465
|
+
event.preventDefault();
|
|
466
|
+
const nextErrors = {};
|
|
467
|
+
for (const [name2, rules] of fieldRulesRef.current) {
|
|
468
|
+
for (const rule of rules ?? []) {
|
|
469
|
+
if (rule.required && isEmpty(values[name2])) {
|
|
470
|
+
nextErrors[name2] = rule.message ?? context.i18n.t("pactor.form.required");
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
setErrors(nextErrors);
|
|
476
|
+
if (Object.keys(nextErrors).length > 0) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
context.state.set("form", values);
|
|
480
|
+
onSubmit?.(values);
|
|
481
|
+
};
|
|
482
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FormContextProvider, { value: formContext, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
483
|
+
"form",
|
|
484
|
+
{
|
|
485
|
+
"data-slot": "form",
|
|
486
|
+
className: cn(layout === "inline" && "flex flex-wrap items-center gap-3"),
|
|
487
|
+
onSubmit: handleSubmit,
|
|
488
|
+
children
|
|
489
|
+
}
|
|
490
|
+
) });
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// src/components/components/Grid/index.tsx
|
|
494
|
+
var import_react3 = require("react");
|
|
495
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
496
|
+
function Grid({ columns = 1, gap, children }) {
|
|
497
|
+
const cols = Math.max(1, columns);
|
|
498
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
499
|
+
"div",
|
|
500
|
+
{
|
|
501
|
+
"data-slot": "grid",
|
|
502
|
+
"data-columns": cols,
|
|
503
|
+
className: "grid",
|
|
504
|
+
style: {
|
|
505
|
+
gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
|
|
506
|
+
...gap !== void 0 ? { gap } : {}
|
|
507
|
+
},
|
|
508
|
+
children: import_react3.Children.map(children, (child, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { "data-slot": "grid-item", children: child }, index))
|
|
509
|
+
}
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/components/components/Input/index.tsx
|
|
514
|
+
var import_react4 = require("react");
|
|
515
|
+
|
|
516
|
+
// src/ui/input.tsx
|
|
517
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
518
|
+
function Input({ className, type, ...props }) {
|
|
519
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
520
|
+
"input",
|
|
521
|
+
{
|
|
522
|
+
type,
|
|
523
|
+
"data-slot": "input",
|
|
524
|
+
className: cn(
|
|
525
|
+
"flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50",
|
|
526
|
+
className
|
|
527
|
+
),
|
|
528
|
+
...props
|
|
529
|
+
}
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/components/components/Input/index.tsx
|
|
534
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
535
|
+
function Input2({
|
|
536
|
+
name,
|
|
537
|
+
label,
|
|
538
|
+
rules,
|
|
539
|
+
value,
|
|
540
|
+
type = "text",
|
|
541
|
+
placeholder,
|
|
542
|
+
disabled,
|
|
543
|
+
onChange
|
|
544
|
+
}) {
|
|
545
|
+
const form = useFormContext();
|
|
546
|
+
const controlId = (0, import_react4.useId)();
|
|
547
|
+
const inForm = form?.inForm === true && typeof name === "string" && name !== "";
|
|
548
|
+
(0, import_react4.useEffect)(() => {
|
|
549
|
+
if (inForm && form && name) {
|
|
550
|
+
form.registerField(name, rules, value);
|
|
551
|
+
return () => form.unregisterField(name);
|
|
552
|
+
}
|
|
553
|
+
return void 0;
|
|
554
|
+
});
|
|
555
|
+
if (inForm && form && name) {
|
|
556
|
+
const fieldValue = form.values[name];
|
|
557
|
+
const error = form.errors[name];
|
|
558
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-slot": "form-item", className: formItemClass(form.layout), children: [
|
|
559
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
560
|
+
"label",
|
|
561
|
+
{
|
|
562
|
+
htmlFor: controlId,
|
|
563
|
+
className: "shrink-0 text-sm leading-none font-medium whitespace-nowrap",
|
|
564
|
+
children: label
|
|
565
|
+
}
|
|
566
|
+
) : null,
|
|
567
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
568
|
+
Input,
|
|
569
|
+
{
|
|
570
|
+
id: controlId,
|
|
571
|
+
type,
|
|
572
|
+
value: typeof fieldValue === "string" ? fieldValue : "",
|
|
573
|
+
placeholder,
|
|
574
|
+
disabled,
|
|
575
|
+
onChange: (event) => {
|
|
576
|
+
form.setValue(name, event.target.value);
|
|
577
|
+
onChange?.(event.target.value);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
),
|
|
581
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { "data-slot": "form-error", className: "text-sm text-destructive", children: error }) : null
|
|
582
|
+
] });
|
|
583
|
+
}
|
|
584
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
585
|
+
Input,
|
|
586
|
+
{
|
|
587
|
+
type,
|
|
588
|
+
value: value ?? "",
|
|
589
|
+
placeholder,
|
|
590
|
+
disabled,
|
|
591
|
+
onChange: (event) => onChange?.(event.target.value)
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// src/components/components/Page/index.tsx
|
|
597
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
598
|
+
function Page({ title, children }) {
|
|
599
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { "data-slot": "page", className: "p-6", children: [
|
|
600
|
+
title ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { "data-slot": "page-title", className: "mb-5 text-xl font-semibold", children: title }) : null,
|
|
601
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { "data-slot": "page-content", className: "space-y-5", children })
|
|
602
|
+
] });
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// src/components/components/Select/index.tsx
|
|
606
|
+
var import_runtime2 = require("@pactor-app/runtime");
|
|
607
|
+
var import_react5 = require("react");
|
|
608
|
+
|
|
609
|
+
// src/ui/select.tsx
|
|
610
|
+
var import_select = require("@base-ui/react/select");
|
|
611
|
+
var import_lucide_react2 = require("lucide-react");
|
|
612
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
613
|
+
var Select = import_select.Select.Root;
|
|
614
|
+
function SelectValue({
|
|
615
|
+
...props
|
|
616
|
+
}) {
|
|
617
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_select.Select.Value, { "data-slot": "select-value", ...props });
|
|
618
|
+
}
|
|
619
|
+
function SelectTrigger({
|
|
620
|
+
className,
|
|
621
|
+
size = "default",
|
|
622
|
+
children,
|
|
623
|
+
...props
|
|
624
|
+
}) {
|
|
625
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
626
|
+
import_select.Select.Trigger,
|
|
627
|
+
{
|
|
628
|
+
"data-slot": "select-trigger",
|
|
629
|
+
"data-size": size,
|
|
630
|
+
className: cn(
|
|
631
|
+
"flex w-fit cursor-pointer items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-colors outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 data-[placeholder]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
632
|
+
className
|
|
633
|
+
),
|
|
634
|
+
...props,
|
|
635
|
+
children: [
|
|
636
|
+
children,
|
|
637
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
638
|
+
import_select.Select.Icon,
|
|
639
|
+
{
|
|
640
|
+
render: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react2.ChevronDownIcon, { className: "size-4 opacity-50" })
|
|
641
|
+
}
|
|
642
|
+
)
|
|
643
|
+
]
|
|
644
|
+
}
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
function SelectContent({
|
|
648
|
+
className,
|
|
649
|
+
children,
|
|
650
|
+
side = "bottom",
|
|
651
|
+
sideOffset = 4,
|
|
652
|
+
align = "center",
|
|
653
|
+
alignItemWithTrigger = false,
|
|
654
|
+
...props
|
|
655
|
+
}) {
|
|
656
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_select.Select.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
657
|
+
import_select.Select.Positioner,
|
|
658
|
+
{
|
|
659
|
+
side,
|
|
660
|
+
sideOffset,
|
|
661
|
+
align,
|
|
662
|
+
alignItemWithTrigger,
|
|
663
|
+
className: "isolate z-50",
|
|
664
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
665
|
+
import_select.Select.Popup,
|
|
666
|
+
{
|
|
667
|
+
"data-slot": "select-content",
|
|
668
|
+
className: cn(
|
|
669
|
+
"relative z-50 max-h-96 min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border border-border bg-popover text-popover-foreground shadow-md duration-200 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
670
|
+
className
|
|
671
|
+
),
|
|
672
|
+
...props,
|
|
673
|
+
children: [
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectScrollUpButton, {}),
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_select.Select.List, { className: "p-1", children }),
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectScrollDownButton, {})
|
|
677
|
+
]
|
|
678
|
+
}
|
|
679
|
+
)
|
|
680
|
+
}
|
|
681
|
+
) });
|
|
682
|
+
}
|
|
683
|
+
function SelectItem({
|
|
684
|
+
className,
|
|
685
|
+
children,
|
|
686
|
+
...props
|
|
687
|
+
}) {
|
|
688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
689
|
+
import_select.Select.Item,
|
|
690
|
+
{
|
|
691
|
+
"data-slot": "select-item",
|
|
692
|
+
className: cn(
|
|
693
|
+
"relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-none select-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
694
|
+
className
|
|
695
|
+
),
|
|
696
|
+
...props,
|
|
697
|
+
children: [
|
|
698
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_select.Select.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react2.CheckIcon, { className: "size-4" }) }) }),
|
|
699
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_select.Select.ItemText, { children })
|
|
700
|
+
]
|
|
701
|
+
}
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
function SelectScrollUpButton({
|
|
705
|
+
className,
|
|
706
|
+
...props
|
|
707
|
+
}) {
|
|
708
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
709
|
+
import_select.Select.ScrollUpArrow,
|
|
710
|
+
{
|
|
711
|
+
"data-slot": "select-scroll-up-button",
|
|
712
|
+
className: cn(
|
|
713
|
+
"flex cursor-default items-center justify-center py-1",
|
|
714
|
+
className
|
|
715
|
+
),
|
|
716
|
+
...props,
|
|
717
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react2.ChevronUpIcon, { className: "size-4" })
|
|
718
|
+
}
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
function SelectScrollDownButton({
|
|
722
|
+
className,
|
|
723
|
+
...props
|
|
724
|
+
}) {
|
|
725
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
726
|
+
import_select.Select.ScrollDownArrow,
|
|
727
|
+
{
|
|
728
|
+
"data-slot": "select-scroll-down-button",
|
|
729
|
+
className: cn(
|
|
730
|
+
"flex cursor-default items-center justify-center py-1",
|
|
731
|
+
className
|
|
732
|
+
),
|
|
733
|
+
...props,
|
|
734
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react2.ChevronDownIcon, { className: "size-4" })
|
|
735
|
+
}
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// src/components/components/Select/index.tsx
|
|
740
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
741
|
+
function Select2({
|
|
742
|
+
name,
|
|
743
|
+
label,
|
|
744
|
+
rules,
|
|
745
|
+
options = [],
|
|
746
|
+
value,
|
|
747
|
+
placeholder,
|
|
748
|
+
disabled,
|
|
749
|
+
allowClear,
|
|
750
|
+
onChange
|
|
751
|
+
}) {
|
|
752
|
+
const form = useFormContext();
|
|
753
|
+
const { t } = (0, import_runtime2.useI18n)();
|
|
754
|
+
const controlId = (0, import_react5.useId)();
|
|
755
|
+
const inForm = form?.inForm === true && typeof name === "string" && name !== "";
|
|
756
|
+
(0, import_react5.useEffect)(() => {
|
|
757
|
+
if (inForm && form && name) {
|
|
758
|
+
form.registerField(name, rules, value);
|
|
759
|
+
return () => form.unregisterField(name);
|
|
760
|
+
}
|
|
761
|
+
return void 0;
|
|
762
|
+
});
|
|
763
|
+
const current = inForm && form && name ? form.values[name] : value;
|
|
764
|
+
const selectedValue = current === void 0 || current === null || current === "" ? null : current;
|
|
765
|
+
const handleChange = (next) => {
|
|
766
|
+
if (inForm && form && name) {
|
|
767
|
+
form.setValue(name, next ?? void 0);
|
|
768
|
+
}
|
|
769
|
+
onChange?.(next ?? void 0);
|
|
770
|
+
};
|
|
771
|
+
const select = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
772
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
773
|
+
Select,
|
|
774
|
+
{
|
|
775
|
+
items: options,
|
|
776
|
+
value: selectedValue,
|
|
777
|
+
onValueChange: handleChange,
|
|
778
|
+
disabled,
|
|
779
|
+
name: inForm ? name : void 0,
|
|
780
|
+
children: [
|
|
781
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SelectTrigger, { id: controlId, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SelectValue, { placeholder }) }),
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SelectContent, { children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SelectItem, { value: option.value, children: option.label }, String(option.value))) })
|
|
783
|
+
]
|
|
784
|
+
}
|
|
785
|
+
),
|
|
786
|
+
allowClear && selectedValue !== null && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
787
|
+
"button",
|
|
788
|
+
{
|
|
789
|
+
type: "button",
|
|
790
|
+
"aria-label": t("pactor.select.clear"),
|
|
791
|
+
className: "cursor-pointer text-muted-foreground hover:text-foreground",
|
|
792
|
+
onClick: () => {
|
|
793
|
+
if (inForm && form && name) {
|
|
794
|
+
form.setValue(name, void 0);
|
|
795
|
+
}
|
|
796
|
+
onChange?.(void 0);
|
|
797
|
+
},
|
|
798
|
+
children: "\xD7"
|
|
799
|
+
}
|
|
800
|
+
) : null
|
|
801
|
+
] });
|
|
802
|
+
if (inForm && form && name) {
|
|
803
|
+
const error = form.errors[name];
|
|
804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { "data-slot": "form-item", className: formItemClass(form.layout), children: [
|
|
805
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
806
|
+
"label",
|
|
807
|
+
{
|
|
808
|
+
htmlFor: controlId,
|
|
809
|
+
className: "shrink-0 text-sm leading-none font-medium whitespace-nowrap",
|
|
810
|
+
children: label
|
|
811
|
+
}
|
|
812
|
+
) : null,
|
|
813
|
+
select,
|
|
814
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { "data-slot": "form-error", className: "text-sm text-destructive", children: error }) : null
|
|
815
|
+
] });
|
|
816
|
+
}
|
|
817
|
+
return select;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// src/components/components/Statistic/index.tsx
|
|
821
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
822
|
+
function Statistic({ title, value, precision, suffix }) {
|
|
823
|
+
const display = typeof value === "number" && precision !== void 0 ? value.toFixed(precision) : value;
|
|
824
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { "data-slot": "statistic", children: [
|
|
825
|
+
title ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { "data-slot": "statistic-title", className: "text-sm text-muted-foreground", children: title }) : null,
|
|
826
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { "data-slot": "statistic-value", className: "text-2xl font-bold tabular-nums", children: [
|
|
827
|
+
display,
|
|
828
|
+
suffix ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ml-1 text-sm font-normal text-muted-foreground", children: suffix }) : null
|
|
829
|
+
] })
|
|
830
|
+
] });
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// src/components/components/Table/index.tsx
|
|
834
|
+
var import_runtime3 = require("@pactor-app/runtime");
|
|
835
|
+
var import_react6 = require("react");
|
|
836
|
+
|
|
837
|
+
// src/ui/table.tsx
|
|
838
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
839
|
+
function Table({ className, ...props }) {
|
|
840
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
841
|
+
"div",
|
|
842
|
+
{
|
|
843
|
+
"data-slot": "table-container",
|
|
844
|
+
className: "relative w-full overflow-x-auto",
|
|
845
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
846
|
+
"table",
|
|
847
|
+
{
|
|
848
|
+
"data-slot": "table",
|
|
849
|
+
className: cn("w-full caption-bottom text-sm", className),
|
|
850
|
+
...props
|
|
851
|
+
}
|
|
852
|
+
)
|
|
853
|
+
}
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
function TableHeader({ className, ...props }) {
|
|
857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
858
|
+
"thead",
|
|
859
|
+
{
|
|
860
|
+
"data-slot": "table-header",
|
|
861
|
+
className: cn("[&_tr]:border-b [&_tr]:border-border", className),
|
|
862
|
+
...props
|
|
863
|
+
}
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
function TableBody({ className, ...props }) {
|
|
867
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
868
|
+
"tbody",
|
|
869
|
+
{
|
|
870
|
+
"data-slot": "table-body",
|
|
871
|
+
className: cn("[&_tr:last-child]:border-0", className),
|
|
872
|
+
...props
|
|
873
|
+
}
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
function TableRow({ className, ...props }) {
|
|
877
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
878
|
+
"tr",
|
|
879
|
+
{
|
|
880
|
+
"data-slot": "table-row",
|
|
881
|
+
className: cn(
|
|
882
|
+
"border-b border-border transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
|
883
|
+
className
|
|
884
|
+
),
|
|
885
|
+
...props
|
|
886
|
+
}
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
function TableHead({ className, ...props }) {
|
|
890
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
891
|
+
"th",
|
|
892
|
+
{
|
|
893
|
+
"data-slot": "table-head",
|
|
894
|
+
className: cn(
|
|
895
|
+
"h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
|
|
896
|
+
className
|
|
897
|
+
),
|
|
898
|
+
...props
|
|
899
|
+
}
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
function TableCell({ className, ...props }) {
|
|
903
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
904
|
+
"td",
|
|
905
|
+
{
|
|
906
|
+
"data-slot": "table-cell",
|
|
907
|
+
className: cn(
|
|
908
|
+
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
|
|
909
|
+
className
|
|
910
|
+
),
|
|
911
|
+
...props
|
|
912
|
+
}
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// src/components/components/Table/index.tsx
|
|
917
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
918
|
+
function renderCellValue(value) {
|
|
919
|
+
if (value === void 0 || value === null) {
|
|
920
|
+
return "";
|
|
921
|
+
}
|
|
922
|
+
if (typeof value === "object") {
|
|
923
|
+
return JSON.stringify(value);
|
|
924
|
+
}
|
|
925
|
+
return String(value);
|
|
926
|
+
}
|
|
927
|
+
function Table2({
|
|
928
|
+
columns = [],
|
|
929
|
+
dataSource = [],
|
|
930
|
+
rowKey = "id",
|
|
931
|
+
loading,
|
|
932
|
+
pagination,
|
|
933
|
+
onChange
|
|
934
|
+
}) {
|
|
935
|
+
const { renderChildren } = (0, import_runtime3.useRenderer)();
|
|
936
|
+
const { t } = (0, import_runtime3.useI18n)();
|
|
937
|
+
const [current, setCurrent] = (0, import_react6.useState)(1);
|
|
938
|
+
const pageSize = pagination === false ? void 0 : pagination?.pageSize;
|
|
939
|
+
const total = dataSource.length;
|
|
940
|
+
const pageCount = pageSize !== void 0 && pageSize > 0 ? Math.max(1, Math.ceil(total / pageSize)) : 1;
|
|
941
|
+
const pageRows = pageSize !== void 0 && pageSize > 0 ? dataSource.slice((current - 1) * pageSize, current * pageSize) : dataSource;
|
|
942
|
+
const goToPage = (page) => {
|
|
943
|
+
setCurrent(page);
|
|
944
|
+
onChange?.({ current: page, pageSize, total });
|
|
945
|
+
};
|
|
946
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { "data-slot": "dsl-table", className: "relative", children: [
|
|
947
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
948
|
+
"div",
|
|
949
|
+
{
|
|
950
|
+
"data-slot": "table-loading",
|
|
951
|
+
className: "absolute inset-0 z-10 flex items-center justify-center bg-background/60 text-sm text-muted-foreground",
|
|
952
|
+
children: t("pactor.table.loading")
|
|
953
|
+
}
|
|
954
|
+
) : null,
|
|
955
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Table, { children: [
|
|
956
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TableRow, { className: "hover:bg-transparent", children: columns.map((column, index) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
957
|
+
TableHead,
|
|
958
|
+
{
|
|
959
|
+
style: column.width !== void 0 ? { width: column.width } : void 0,
|
|
960
|
+
children: column.title
|
|
961
|
+
},
|
|
962
|
+
column.dataIndex ?? String(index)
|
|
963
|
+
)) }) }),
|
|
964
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TableBody, { children: pageRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TableCell, { colSpan: Math.max(1, columns.length), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
965
|
+
"div",
|
|
966
|
+
{
|
|
967
|
+
"data-slot": "table-empty",
|
|
968
|
+
className: "py-8 text-center text-muted-foreground",
|
|
969
|
+
children: t("pactor.table.empty")
|
|
970
|
+
}
|
|
971
|
+
) }) }) : pageRows.map((row, rowIndex) => {
|
|
972
|
+
const key = row[rowKey];
|
|
973
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
974
|
+
TableRow,
|
|
975
|
+
{
|
|
976
|
+
children: columns.map((column, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TableCell, { children: column.cell ? renderChildren([column.cell], { row, rowIndex }) : renderCellValue(
|
|
977
|
+
column.dataIndex === void 0 ? void 0 : row[column.dataIndex]
|
|
978
|
+
) }, column.dataIndex ?? String(columnIndex)))
|
|
979
|
+
},
|
|
980
|
+
key === void 0 || key === null ? rowIndex : String(key)
|
|
981
|
+
);
|
|
982
|
+
}) })
|
|
983
|
+
] }),
|
|
984
|
+
pageSize !== void 0 && pageSize > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { "data-slot": "table-pagination", className: "mt-3 flex justify-end gap-1", children: Array.from({ length: pageCount }, (_, index) => index + 1).map(
|
|
985
|
+
(page) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
986
|
+
Button,
|
|
987
|
+
{
|
|
988
|
+
type: "button",
|
|
989
|
+
size: "sm",
|
|
990
|
+
variant: page === current ? "default" : "outline",
|
|
991
|
+
"aria-current": page === current ? "page" : void 0,
|
|
992
|
+
onClick: () => goToPage(page),
|
|
993
|
+
children: page
|
|
994
|
+
},
|
|
995
|
+
page
|
|
996
|
+
)
|
|
997
|
+
) }) : null
|
|
998
|
+
] });
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// src/components/components/Tabs/index.tsx
|
|
1002
|
+
var import_runtime4 = require("@pactor-app/runtime");
|
|
1003
|
+
|
|
1004
|
+
// src/ui/tabs.tsx
|
|
1005
|
+
var import_tabs = require("@base-ui/react/tabs");
|
|
1006
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1007
|
+
function Tabs({
|
|
1008
|
+
className,
|
|
1009
|
+
...props
|
|
1010
|
+
}) {
|
|
1011
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1012
|
+
import_tabs.Tabs.Root,
|
|
1013
|
+
{
|
|
1014
|
+
"data-slot": "tabs",
|
|
1015
|
+
className: cn("flex flex-col gap-2", className),
|
|
1016
|
+
...props
|
|
1017
|
+
}
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
function TabsList({
|
|
1021
|
+
className,
|
|
1022
|
+
...props
|
|
1023
|
+
}) {
|
|
1024
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1025
|
+
import_tabs.Tabs.List,
|
|
1026
|
+
{
|
|
1027
|
+
"data-slot": "tabs-list",
|
|
1028
|
+
className: cn(
|
|
1029
|
+
"inline-flex h-9 w-fit items-center justify-center rounded-lg bg-muted p-[3px] text-muted-foreground",
|
|
1030
|
+
className
|
|
1031
|
+
),
|
|
1032
|
+
...props
|
|
1033
|
+
}
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
function TabsTrigger({
|
|
1037
|
+
className,
|
|
1038
|
+
...props
|
|
1039
|
+
}) {
|
|
1040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1041
|
+
import_tabs.Tabs.Tab,
|
|
1042
|
+
{
|
|
1043
|
+
"data-slot": "tabs-trigger",
|
|
1044
|
+
className: cn(
|
|
1045
|
+
"inline-flex h-[calc(100%-1px)] flex-1 cursor-pointer items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground transition-colors focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-active:border-border data-active:bg-background data-active:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1046
|
+
className
|
|
1047
|
+
),
|
|
1048
|
+
...props
|
|
1049
|
+
}
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
function TabsContent({
|
|
1053
|
+
className,
|
|
1054
|
+
...props
|
|
1055
|
+
}) {
|
|
1056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1057
|
+
import_tabs.Tabs.Panel,
|
|
1058
|
+
{
|
|
1059
|
+
"data-slot": "tabs-content",
|
|
1060
|
+
className: cn("flex-1 outline-none", className),
|
|
1061
|
+
...props
|
|
1062
|
+
}
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// src/components/components/Tabs/index.tsx
|
|
1067
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1068
|
+
function Tabs2({ items = [], activeKey, onChange }) {
|
|
1069
|
+
const { renderChildren } = (0, import_runtime4.useRenderer)();
|
|
1070
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1071
|
+
Tabs,
|
|
1072
|
+
{
|
|
1073
|
+
value: activeKey,
|
|
1074
|
+
defaultValue: activeKey === void 0 ? items[0]?.key : void 0,
|
|
1075
|
+
onValueChange: (key) => onChange?.(key),
|
|
1076
|
+
children: [
|
|
1077
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TabsList, { children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TabsTrigger, { value: item.key, children: item.label }, item.key)) }),
|
|
1078
|
+
items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TabsContent, { value: item.key, children: renderChildren(item.children) }, item.key))
|
|
1079
|
+
]
|
|
1080
|
+
}
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
// src/components/register.ts
|
|
1085
|
+
var shadcnComponents = {
|
|
1086
|
+
Page,
|
|
1087
|
+
Grid,
|
|
1088
|
+
Flex,
|
|
1089
|
+
Card: Card2,
|
|
1090
|
+
Button: Button2,
|
|
1091
|
+
Alert: Alert2,
|
|
1092
|
+
Statistic,
|
|
1093
|
+
Tabs: Tabs2,
|
|
1094
|
+
Table: Table2,
|
|
1095
|
+
Form,
|
|
1096
|
+
Input: Input2,
|
|
1097
|
+
Select: Select2
|
|
1098
|
+
};
|
|
1099
|
+
function registerShadcnComponents(registry) {
|
|
1100
|
+
for (const [type, component] of Object.entries(shadcnComponents)) {
|
|
1101
|
+
registry.register(type, component);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
function createShadcnComponentRegistry() {
|
|
1105
|
+
const registry = new import_core.Registry("ComponentRegistry");
|
|
1106
|
+
registerShadcnComponents(registry);
|
|
1107
|
+
return registry;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// src/layout/admin/menu-chain.ts
|
|
1111
|
+
function findMenuChain(registry, menuId) {
|
|
1112
|
+
const walk = (menus, ancestors) => {
|
|
1113
|
+
for (const menu of menus) {
|
|
1114
|
+
const chain = [...ancestors, menu];
|
|
1115
|
+
if (menu.id === menuId) {
|
|
1116
|
+
return chain;
|
|
1117
|
+
}
|
|
1118
|
+
if (menu.children !== void 0) {
|
|
1119
|
+
const hit = walk(menu.children, chain);
|
|
1120
|
+
if (hit !== null) {
|
|
1121
|
+
return hit;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
return null;
|
|
1126
|
+
};
|
|
1127
|
+
return walk(registry.tree(), []) ?? [];
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// src/layout/admin/menu-items.ts
|
|
1131
|
+
function collectDefaultOpenKeys(registry, activeMenuId) {
|
|
1132
|
+
const keys = [];
|
|
1133
|
+
const walk = (menus) => {
|
|
1134
|
+
for (const menu of menus) {
|
|
1135
|
+
if (menu.type === "group" && menu.defaultOpen === true) {
|
|
1136
|
+
keys.push(menu.id);
|
|
1137
|
+
}
|
|
1138
|
+
if (menu.children !== void 0) {
|
|
1139
|
+
walk(menu.children);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1143
|
+
walk(registry.tree());
|
|
1144
|
+
if (activeMenuId !== void 0) {
|
|
1145
|
+
for (const menu of findMenuChain(registry, activeMenuId)) {
|
|
1146
|
+
if (menu.type === "group" && !keys.includes(menu.id)) {
|
|
1147
|
+
keys.push(menu.id);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
return keys;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// src/layout/admin/ShadcnAdminLayout.tsx
|
|
1155
|
+
var import_permission = require("@pactor-app/permission");
|
|
1156
|
+
var import_router = require("@pactor-app/router");
|
|
1157
|
+
var import_runtime5 = require("@pactor-app/runtime");
|
|
1158
|
+
var import_react8 = require("react");
|
|
1159
|
+
|
|
1160
|
+
// src/ui/accordion.tsx
|
|
1161
|
+
var import_accordion = require("@base-ui/react/accordion");
|
|
1162
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1163
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1164
|
+
function toArray(value) {
|
|
1165
|
+
if (value === void 0) {
|
|
1166
|
+
return void 0;
|
|
1167
|
+
}
|
|
1168
|
+
return Array.isArray(value) ? value : [value];
|
|
1169
|
+
}
|
|
1170
|
+
function Accordion({
|
|
1171
|
+
type = "single",
|
|
1172
|
+
value,
|
|
1173
|
+
defaultValue,
|
|
1174
|
+
onValueChange,
|
|
1175
|
+
...props
|
|
1176
|
+
}) {
|
|
1177
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1178
|
+
import_accordion.Accordion.Root,
|
|
1179
|
+
{
|
|
1180
|
+
"data-slot": "accordion",
|
|
1181
|
+
multiple: type === "multiple",
|
|
1182
|
+
value: toArray(value),
|
|
1183
|
+
defaultValue: toArray(defaultValue),
|
|
1184
|
+
onValueChange: onValueChange === void 0 ? void 0 : (next) => onValueChange(type === "multiple" ? next : next[0] ?? ""),
|
|
1185
|
+
...props
|
|
1186
|
+
}
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
function AccordionItem({
|
|
1190
|
+
className,
|
|
1191
|
+
...props
|
|
1192
|
+
}) {
|
|
1193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1194
|
+
import_accordion.Accordion.Item,
|
|
1195
|
+
{
|
|
1196
|
+
"data-slot": "accordion-item",
|
|
1197
|
+
className: cn("border-b border-border last:border-b-0", className),
|
|
1198
|
+
...props
|
|
1199
|
+
}
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
function AccordionTrigger({
|
|
1203
|
+
className,
|
|
1204
|
+
children,
|
|
1205
|
+
...props
|
|
1206
|
+
}) {
|
|
1207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_accordion.Accordion.Header, { className: "flex", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1208
|
+
import_accordion.Accordion.Trigger,
|
|
1209
|
+
{
|
|
1210
|
+
"data-slot": "accordion-trigger",
|
|
1211
|
+
className: cn(
|
|
1212
|
+
"flex flex-1 cursor-pointer items-center justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-colors outline-none hover:bg-accent hover:text-accent-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&[aria-expanded=true]>svg]:rotate-180",
|
|
1213
|
+
className
|
|
1214
|
+
),
|
|
1215
|
+
...props,
|
|
1216
|
+
children: [
|
|
1217
|
+
children,
|
|
1218
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react3.ChevronDownIcon, { className: "pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200" })
|
|
1219
|
+
]
|
|
1220
|
+
}
|
|
1221
|
+
) });
|
|
1222
|
+
}
|
|
1223
|
+
function AccordionContent({
|
|
1224
|
+
className,
|
|
1225
|
+
children,
|
|
1226
|
+
...props
|
|
1227
|
+
}) {
|
|
1228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1229
|
+
import_accordion.Accordion.Panel,
|
|
1230
|
+
{
|
|
1231
|
+
"data-slot": "accordion-content",
|
|
1232
|
+
className: "overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up",
|
|
1233
|
+
...props,
|
|
1234
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("pt-0 pb-4", className), children })
|
|
1235
|
+
}
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// src/ui/popover.tsx
|
|
1240
|
+
var import_popover = require("@base-ui/react/popover");
|
|
1241
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1242
|
+
function Popover({
|
|
1243
|
+
...props
|
|
1244
|
+
}) {
|
|
1245
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_popover.Popover.Root, { "data-slot": "popover", ...props });
|
|
1246
|
+
}
|
|
1247
|
+
function PopoverTrigger({
|
|
1248
|
+
...props
|
|
1249
|
+
}) {
|
|
1250
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_popover.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
1251
|
+
}
|
|
1252
|
+
function PopoverContent({
|
|
1253
|
+
className,
|
|
1254
|
+
align = "center",
|
|
1255
|
+
side = "bottom",
|
|
1256
|
+
sideOffset = 4,
|
|
1257
|
+
anchor,
|
|
1258
|
+
...props
|
|
1259
|
+
}) {
|
|
1260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_popover.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1261
|
+
import_popover.Popover.Positioner,
|
|
1262
|
+
{
|
|
1263
|
+
align,
|
|
1264
|
+
side,
|
|
1265
|
+
sideOffset,
|
|
1266
|
+
anchor,
|
|
1267
|
+
className: "isolate z-50",
|
|
1268
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1269
|
+
import_popover.Popover.Popup,
|
|
1270
|
+
{
|
|
1271
|
+
"data-slot": "popover-content",
|
|
1272
|
+
className: cn(
|
|
1273
|
+
"z-50 w-72 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none duration-200 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
1274
|
+
className
|
|
1275
|
+
),
|
|
1276
|
+
...props
|
|
1277
|
+
}
|
|
1278
|
+
)
|
|
1279
|
+
}
|
|
1280
|
+
) });
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// src/layout/admin/use-media-query.ts
|
|
1284
|
+
var import_react7 = require("react");
|
|
1285
|
+
var BREAKPOINT_PX = {
|
|
1286
|
+
xs: 480,
|
|
1287
|
+
sm: 576,
|
|
1288
|
+
md: 768,
|
|
1289
|
+
lg: 992,
|
|
1290
|
+
xl: 1200,
|
|
1291
|
+
xxl: 1600
|
|
1292
|
+
};
|
|
1293
|
+
function useMediaQuery(query) {
|
|
1294
|
+
const [matches, setMatches] = (0, import_react7.useState)(
|
|
1295
|
+
() => typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia(query).matches : false
|
|
1296
|
+
);
|
|
1297
|
+
(0, import_react7.useEffect)(() => {
|
|
1298
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
const mql = window.matchMedia(query);
|
|
1302
|
+
const onChange = (event) => setMatches(event.matches);
|
|
1303
|
+
setMatches(mql.matches);
|
|
1304
|
+
mql.addEventListener("change", onChange);
|
|
1305
|
+
return () => mql.removeEventListener("change", onChange);
|
|
1306
|
+
}, [query]);
|
|
1307
|
+
return matches;
|
|
1308
|
+
}
|
|
1309
|
+
function useBreakpointBelow(breakpoint) {
|
|
1310
|
+
const matches = useMediaQuery(
|
|
1311
|
+
breakpoint ? `(max-width: ${BREAKPOINT_PX[breakpoint] - 1}px)` : "(min-width: 0px)"
|
|
1312
|
+
);
|
|
1313
|
+
return breakpoint !== void 0 && matches;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// src/layout/admin/ShadcnAdminLayout.tsx
|
|
1317
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1318
|
+
function buildVisibleMenuTree(registry, permissionChecker) {
|
|
1319
|
+
const tree = registry.tree();
|
|
1320
|
+
return permissionChecker === void 0 ? [...tree] : (0, import_permission.filterMenusByPermission)(tree, permissionChecker);
|
|
1321
|
+
}
|
|
1322
|
+
function navigateMenuItem(menu, bridge) {
|
|
1323
|
+
if (menu === void 0 || menu.type === "group" || menu.path === void 0) {
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
if (menu.external === true || menu.type === "link") {
|
|
1327
|
+
window.open(menu.path, menu.target ?? "_blank");
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
bridge.push(menu.path);
|
|
1331
|
+
}
|
|
1332
|
+
var menuItemClass = "flex w-full cursor-pointer items-center rounded-md px-3 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50";
|
|
1333
|
+
function CollapsedGroupFlyout({
|
|
1334
|
+
menu,
|
|
1335
|
+
registry,
|
|
1336
|
+
bridge,
|
|
1337
|
+
activeMenuId,
|
|
1338
|
+
defaultOpenKeys
|
|
1339
|
+
}) {
|
|
1340
|
+
const [open, setOpen] = (0, import_react8.useState)(false);
|
|
1341
|
+
const closeTimer = (0, import_react8.useRef)(void 0);
|
|
1342
|
+
const openNow = () => {
|
|
1343
|
+
window.clearTimeout(closeTimer.current);
|
|
1344
|
+
setOpen(true);
|
|
1345
|
+
};
|
|
1346
|
+
const closeLater = () => {
|
|
1347
|
+
window.clearTimeout(closeTimer.current);
|
|
1348
|
+
closeTimer.current = window.setTimeout(() => setOpen(false), 200);
|
|
1349
|
+
};
|
|
1350
|
+
(0, import_react8.useEffect)(() => () => window.clearTimeout(closeTimer.current), []);
|
|
1351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Popover, { open, onOpenChange: setOpen, children: [
|
|
1352
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1353
|
+
PopoverTrigger,
|
|
1354
|
+
{
|
|
1355
|
+
render: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1356
|
+
"button",
|
|
1357
|
+
{
|
|
1358
|
+
type: "button",
|
|
1359
|
+
"data-slot": "menu-item",
|
|
1360
|
+
className: cn(
|
|
1361
|
+
menuItemClass,
|
|
1362
|
+
"mx-auto size-10 justify-center px-0 font-semibold"
|
|
1363
|
+
),
|
|
1364
|
+
disabled: menu.disabled,
|
|
1365
|
+
title: menu.title,
|
|
1366
|
+
onMouseEnter: openNow,
|
|
1367
|
+
onMouseLeave: closeLater,
|
|
1368
|
+
children: menu.title.slice(0, 1)
|
|
1369
|
+
}
|
|
1370
|
+
)
|
|
1371
|
+
}
|
|
1372
|
+
),
|
|
1373
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1374
|
+
PopoverContent,
|
|
1375
|
+
{
|
|
1376
|
+
"data-slot": "menu-flyout",
|
|
1377
|
+
side: "right",
|
|
1378
|
+
align: "start",
|
|
1379
|
+
sideOffset: 8,
|
|
1380
|
+
className: "max-h-[70vh] w-40 overflow-auto p-1",
|
|
1381
|
+
initialFocus: false,
|
|
1382
|
+
onMouseEnter: openNow,
|
|
1383
|
+
onMouseLeave: closeLater,
|
|
1384
|
+
onClick: (event) => {
|
|
1385
|
+
if (event.target.closest("[data-slot=menu-item]")) {
|
|
1386
|
+
setOpen(false);
|
|
1387
|
+
}
|
|
1388
|
+
},
|
|
1389
|
+
children: [
|
|
1390
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "px-3 pt-2 pb-1 text-xs font-semibold text-muted-foreground", children: menu.title }),
|
|
1391
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1392
|
+
MenuTree,
|
|
1393
|
+
{
|
|
1394
|
+
menus: menu.children ?? [],
|
|
1395
|
+
registry,
|
|
1396
|
+
bridge,
|
|
1397
|
+
activeMenuId,
|
|
1398
|
+
defaultOpenKeys
|
|
1399
|
+
}
|
|
1400
|
+
)
|
|
1401
|
+
]
|
|
1402
|
+
}
|
|
1403
|
+
)
|
|
1404
|
+
] });
|
|
1405
|
+
}
|
|
1406
|
+
function MenuTree({
|
|
1407
|
+
menus,
|
|
1408
|
+
registry,
|
|
1409
|
+
bridge,
|
|
1410
|
+
activeMenuId,
|
|
1411
|
+
defaultOpenKeys,
|
|
1412
|
+
collapsed = false
|
|
1413
|
+
}) {
|
|
1414
|
+
if (collapsed) {
|
|
1415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "data-slot": "menu", "data-collapsed": "true", className: "flex flex-col gap-1", children: menus.map((menu) => {
|
|
1416
|
+
if (menu.type === "group") {
|
|
1417
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1418
|
+
CollapsedGroupFlyout,
|
|
1419
|
+
{
|
|
1420
|
+
menu,
|
|
1421
|
+
registry,
|
|
1422
|
+
bridge,
|
|
1423
|
+
activeMenuId,
|
|
1424
|
+
defaultOpenKeys
|
|
1425
|
+
},
|
|
1426
|
+
menu.id
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1429
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1430
|
+
"button",
|
|
1431
|
+
{
|
|
1432
|
+
type: "button",
|
|
1433
|
+
"data-slot": "menu-item",
|
|
1434
|
+
"data-active": menu.id === activeMenuId || void 0,
|
|
1435
|
+
className: cn(
|
|
1436
|
+
menuItemClass,
|
|
1437
|
+
"mx-auto size-10 justify-center px-0 font-semibold",
|
|
1438
|
+
menu.id === activeMenuId && "bg-accent font-semibold text-accent-foreground"
|
|
1439
|
+
),
|
|
1440
|
+
disabled: menu.disabled,
|
|
1441
|
+
title: menu.title,
|
|
1442
|
+
onClick: () => navigateMenuItem(registry.findById(menu.id), bridge),
|
|
1443
|
+
children: menu.title.slice(0, 1)
|
|
1444
|
+
},
|
|
1445
|
+
menu.id
|
|
1446
|
+
);
|
|
1447
|
+
}) });
|
|
1448
|
+
}
|
|
1449
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1450
|
+
Accordion,
|
|
1451
|
+
{
|
|
1452
|
+
type: "multiple",
|
|
1453
|
+
defaultValue: defaultOpenKeys,
|
|
1454
|
+
"data-slot": "menu",
|
|
1455
|
+
className: "flex flex-col gap-0.5 px-2",
|
|
1456
|
+
children: menus.map((menu) => {
|
|
1457
|
+
if (menu.type === "group") {
|
|
1458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1459
|
+
AccordionItem,
|
|
1460
|
+
{
|
|
1461
|
+
value: menu.id,
|
|
1462
|
+
"data-slot": "menu-group",
|
|
1463
|
+
className: "border-b-0",
|
|
1464
|
+
children: [
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1466
|
+
AccordionTrigger,
|
|
1467
|
+
{
|
|
1468
|
+
"data-slot": "menu-group-trigger",
|
|
1469
|
+
className: cn(menuItemClass, "py-2 font-medium"),
|
|
1470
|
+
disabled: menu.disabled,
|
|
1471
|
+
title: menu.title,
|
|
1472
|
+
children: menu.title
|
|
1473
|
+
}
|
|
1474
|
+
),
|
|
1475
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(AccordionContent, { "data-slot": "menu-group-content", className: "pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-col gap-0.5 pl-3", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1476
|
+
MenuTree,
|
|
1477
|
+
{
|
|
1478
|
+
menus: menu.children ?? [],
|
|
1479
|
+
registry,
|
|
1480
|
+
bridge,
|
|
1481
|
+
activeMenuId,
|
|
1482
|
+
defaultOpenKeys
|
|
1483
|
+
}
|
|
1484
|
+
) }) })
|
|
1485
|
+
]
|
|
1486
|
+
},
|
|
1487
|
+
menu.id
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1491
|
+
"button",
|
|
1492
|
+
{
|
|
1493
|
+
type: "button",
|
|
1494
|
+
"data-slot": "menu-item",
|
|
1495
|
+
"data-active": menu.id === activeMenuId || void 0,
|
|
1496
|
+
className: cn(
|
|
1497
|
+
menuItemClass,
|
|
1498
|
+
menu.id === activeMenuId && "bg-accent font-semibold text-accent-foreground"
|
|
1499
|
+
),
|
|
1500
|
+
disabled: menu.disabled,
|
|
1501
|
+
title: menu.title,
|
|
1502
|
+
onClick: () => navigateMenuItem(registry.findById(menu.id), bridge),
|
|
1503
|
+
children: menu.title
|
|
1504
|
+
},
|
|
1505
|
+
menu.id
|
|
1506
|
+
);
|
|
1507
|
+
})
|
|
1508
|
+
}
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
function ShadcnAdminLayout({
|
|
1512
|
+
config = {},
|
|
1513
|
+
brand,
|
|
1514
|
+
registry,
|
|
1515
|
+
bridge,
|
|
1516
|
+
route: routeProp,
|
|
1517
|
+
permissionChecker,
|
|
1518
|
+
headerExtra,
|
|
1519
|
+
children
|
|
1520
|
+
}) {
|
|
1521
|
+
const { t } = (0, import_runtime5.useI18n)();
|
|
1522
|
+
const mode = config.mode ?? "top-side";
|
|
1523
|
+
const showHeader = config.header ?? true;
|
|
1524
|
+
const showSidebar = (config.sidebar ?? true) && mode !== "top-bottom";
|
|
1525
|
+
const showTabs = config.tabs ?? false;
|
|
1526
|
+
const showBreadcrumb = config.breadcrumb ?? false;
|
|
1527
|
+
const showFooter = config.footer ?? false;
|
|
1528
|
+
const [collapsed, setCollapsed] = (0, import_react8.useState)(config.collapsed ?? false);
|
|
1529
|
+
const broken = useBreakpointBelow(config.breakpoint);
|
|
1530
|
+
const effectiveCollapsed = collapsed || broken;
|
|
1531
|
+
const [bridgeRoute, setBridgeRoute] = (0, import_react8.useState)(
|
|
1532
|
+
() => (0, import_router.resolveRoute)(registry, bridge.getLocation())
|
|
1533
|
+
);
|
|
1534
|
+
const [tabs, setTabs] = (0, import_react8.useState)([]);
|
|
1535
|
+
const tabsRef = (0, import_react8.useRef)(tabs);
|
|
1536
|
+
tabsRef.current = tabs;
|
|
1537
|
+
(0, import_react8.useEffect)(() => {
|
|
1538
|
+
const handleLocation = (location) => {
|
|
1539
|
+
const next = (0, import_router.resolveRoute)(registry, location);
|
|
1540
|
+
setBridgeRoute(next);
|
|
1541
|
+
if (next?.menuId !== void 0) {
|
|
1542
|
+
const menu = registry.findById(next.menuId);
|
|
1543
|
+
if (menu !== void 0 && menu.type === "page" && menu.path !== void 0) {
|
|
1544
|
+
setTabs((prev) => {
|
|
1545
|
+
if (prev.some((tab) => tab.key === location.pathname)) {
|
|
1546
|
+
return prev;
|
|
1547
|
+
}
|
|
1548
|
+
return [...prev, { key: location.pathname, title: menu.title }];
|
|
1549
|
+
});
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
handleLocation(bridge.getLocation());
|
|
1554
|
+
return bridge.subscribe(handleLocation);
|
|
1555
|
+
}, [registry, bridge]);
|
|
1556
|
+
const route = routeProp ?? bridgeRoute;
|
|
1557
|
+
const activeMenuId = route?.activeMenu;
|
|
1558
|
+
const visibleMenus = (0, import_react8.useMemo)(
|
|
1559
|
+
() => buildVisibleMenuTree(registry, permissionChecker),
|
|
1560
|
+
[registry, permissionChecker]
|
|
1561
|
+
);
|
|
1562
|
+
const defaultOpenKeysRef = (0, import_react8.useRef)(null);
|
|
1563
|
+
if (defaultOpenKeysRef.current === null) {
|
|
1564
|
+
defaultOpenKeysRef.current = collectDefaultOpenKeys(registry, activeMenuId);
|
|
1565
|
+
}
|
|
1566
|
+
const defaultOpenKeys = defaultOpenKeysRef.current;
|
|
1567
|
+
const activeTopId = (0, import_react8.useMemo)(() => {
|
|
1568
|
+
if (activeMenuId !== void 0) {
|
|
1569
|
+
const chain = findMenuChain(registry, activeMenuId);
|
|
1570
|
+
if (chain.length > 0) {
|
|
1571
|
+
return chain[0].id;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
return void 0;
|
|
1575
|
+
}, [registry, activeMenuId]);
|
|
1576
|
+
const [selectedTopId, setSelectedTopId] = (0, import_react8.useState)();
|
|
1577
|
+
const secondaryTopId = selectedTopId ?? activeTopId ?? visibleMenus.find((m) => m.type === "group")?.id ?? visibleMenus[0]?.id;
|
|
1578
|
+
const secondaryTop = visibleMenus.find((m) => m.id === secondaryTopId);
|
|
1579
|
+
const hasSecondary = (secondaryTop?.children?.length ?? 0) > 0;
|
|
1580
|
+
const breadcrumbItems = (0, import_react8.useMemo)(() => {
|
|
1581
|
+
if (!showBreadcrumb || activeMenuId === void 0) {
|
|
1582
|
+
return [];
|
|
1583
|
+
}
|
|
1584
|
+
return findMenuChain(registry, activeMenuId).map((menu) => menu.title);
|
|
1585
|
+
}, [showBreadcrumb, registry, activeMenuId]);
|
|
1586
|
+
const currentPath = route?.path;
|
|
1587
|
+
const closeTab = (targetKey) => {
|
|
1588
|
+
const remaining = tabsRef.current.filter((tab) => tab.key !== targetKey);
|
|
1589
|
+
setTabs(remaining);
|
|
1590
|
+
if (targetKey === currentPath && remaining.length > 0) {
|
|
1591
|
+
bridge.push(remaining[remaining.length - 1].key);
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
const fixedHeader = config.fixedHeader ?? true;
|
|
1595
|
+
const fixedSider = config.fixedSider ?? true;
|
|
1596
|
+
const header = showHeader ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1597
|
+
"header",
|
|
1598
|
+
{
|
|
1599
|
+
"data-slot": "admin-header",
|
|
1600
|
+
className: cn(
|
|
1601
|
+
"flex h-14 items-center gap-4 border-b border-border bg-background px-6",
|
|
1602
|
+
fixedHeader && "sticky top-0 z-20"
|
|
1603
|
+
),
|
|
1604
|
+
children: [
|
|
1605
|
+
mode !== "side-full" && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
1606
|
+
brand.logo,
|
|
1607
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "data-slot": "admin-brand", className: "text-lg font-semibold", children: brand.title })
|
|
1608
|
+
] }),
|
|
1609
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex-1" }),
|
|
1610
|
+
headerExtra
|
|
1611
|
+
]
|
|
1612
|
+
}
|
|
1613
|
+
) : null;
|
|
1614
|
+
const primaryColumn = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1615
|
+
"div",
|
|
1616
|
+
{
|
|
1617
|
+
"data-slot": "admin-primary-col",
|
|
1618
|
+
className: "flex w-12 shrink-0 flex-col items-center gap-1 border-r border-border py-2",
|
|
1619
|
+
children: visibleMenus.map((menu) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1620
|
+
"button",
|
|
1621
|
+
{
|
|
1622
|
+
type: "button",
|
|
1623
|
+
"data-slot": "admin-primary-item",
|
|
1624
|
+
"data-active": menu.id === secondaryTopId || menu.id === activeTopId || void 0,
|
|
1625
|
+
className: cn(
|
|
1626
|
+
menuItemClass,
|
|
1627
|
+
"size-10 justify-center px-0 font-semibold",
|
|
1628
|
+
(menu.id === secondaryTopId || menu.id === activeTopId) && "bg-accent text-accent-foreground"
|
|
1629
|
+
),
|
|
1630
|
+
disabled: menu.disabled,
|
|
1631
|
+
title: menu.title,
|
|
1632
|
+
onClick: () => {
|
|
1633
|
+
if (menu.type === "group") {
|
|
1634
|
+
setSelectedTopId(menu.id);
|
|
1635
|
+
} else {
|
|
1636
|
+
navigateMenuItem(menu, bridge);
|
|
1637
|
+
}
|
|
1638
|
+
},
|
|
1639
|
+
children: menu.title.slice(0, 1)
|
|
1640
|
+
},
|
|
1641
|
+
menu.id
|
|
1642
|
+
))
|
|
1643
|
+
}
|
|
1644
|
+
);
|
|
1645
|
+
const showTrigger = config.collapsible && mode !== "two-column";
|
|
1646
|
+
const sidebar = showSidebar ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1647
|
+
"aside",
|
|
1648
|
+
{
|
|
1649
|
+
"data-slot": "admin-sidebar",
|
|
1650
|
+
"data-collapsed": effectiveCollapsed || void 0,
|
|
1651
|
+
className: cn(
|
|
1652
|
+
"shrink-0 overflow-auto border-r border-border bg-background py-2",
|
|
1653
|
+
effectiveCollapsed ? "w-16 px-1.5" : "w-52",
|
|
1654
|
+
fixedSider && (mode === "side-full" ? "sticky top-0 h-screen" : "sticky top-14 h-[calc(100vh-3.5rem)]")
|
|
1655
|
+
),
|
|
1656
|
+
style: mode === "two-column" && !hasSecondary ? { width: 56 } : void 0,
|
|
1657
|
+
children: [
|
|
1658
|
+
mode === "side-full" && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1659
|
+
"div",
|
|
1660
|
+
{
|
|
1661
|
+
"data-slot": "admin-sidebar-brand",
|
|
1662
|
+
className: "flex items-center gap-2 border-b border-border px-4 py-4 font-semibold",
|
|
1663
|
+
children: [
|
|
1664
|
+
brand.logo,
|
|
1665
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: brand.title })
|
|
1666
|
+
]
|
|
1667
|
+
}
|
|
1668
|
+
),
|
|
1669
|
+
mode === "two-column" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "data-slot": "admin-two-col", className: "flex h-full", children: [
|
|
1670
|
+
primaryColumn,
|
|
1671
|
+
hasSecondary && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "data-slot": "admin-secondary-col", className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1672
|
+
MenuTree,
|
|
1673
|
+
{
|
|
1674
|
+
menus: secondaryTop?.children ?? [],
|
|
1675
|
+
registry,
|
|
1676
|
+
bridge,
|
|
1677
|
+
activeMenuId,
|
|
1678
|
+
defaultOpenKeys
|
|
1679
|
+
}
|
|
1680
|
+
) })
|
|
1681
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1682
|
+
MenuTree,
|
|
1683
|
+
{
|
|
1684
|
+
menus: visibleMenus,
|
|
1685
|
+
registry,
|
|
1686
|
+
bridge,
|
|
1687
|
+
activeMenuId,
|
|
1688
|
+
defaultOpenKeys,
|
|
1689
|
+
collapsed: effectiveCollapsed
|
|
1690
|
+
}
|
|
1691
|
+
),
|
|
1692
|
+
showTrigger && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1693
|
+
"button",
|
|
1694
|
+
{
|
|
1695
|
+
type: "button",
|
|
1696
|
+
"data-slot": "admin-collapse-trigger",
|
|
1697
|
+
"aria-label": effectiveCollapsed ? t("pactor.layout.expandSidebar") : t("pactor.layout.collapseSidebar"),
|
|
1698
|
+
"aria-expanded": !effectiveCollapsed,
|
|
1699
|
+
className: "sticky bottom-0 flex w-full cursor-pointer items-center justify-center border-t border-border bg-background py-2 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
1700
|
+
onClick: () => setCollapsed((value) => !value),
|
|
1701
|
+
children: effectiveCollapsed ? "\xBB" : "\xAB"
|
|
1702
|
+
}
|
|
1703
|
+
)
|
|
1704
|
+
]
|
|
1705
|
+
}
|
|
1706
|
+
) : null;
|
|
1707
|
+
const body = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "data-slot": "admin-body", className: "flex min-w-0 flex-1 flex-col", children: [
|
|
1708
|
+
showTabs && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1709
|
+
"div",
|
|
1710
|
+
{
|
|
1711
|
+
"data-slot": "admin-tabs",
|
|
1712
|
+
role: "tablist",
|
|
1713
|
+
className: "flex items-center gap-1 border-b border-border bg-background px-4 pt-2",
|
|
1714
|
+
children: tabs.map((tab, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1715
|
+
"div",
|
|
1716
|
+
{
|
|
1717
|
+
"data-slot": "admin-tab",
|
|
1718
|
+
"data-active": tab.key === currentPath || void 0,
|
|
1719
|
+
role: "presentation",
|
|
1720
|
+
className: cn(
|
|
1721
|
+
"inline-flex items-center gap-1 rounded-t-md border border-b-0 border-border px-3 py-1.5 text-sm",
|
|
1722
|
+
tab.key === currentPath ? "bg-background font-medium text-foreground" : "bg-muted text-muted-foreground"
|
|
1723
|
+
),
|
|
1724
|
+
children: [
|
|
1725
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1726
|
+
"button",
|
|
1727
|
+
{
|
|
1728
|
+
type: "button",
|
|
1729
|
+
role: "tab",
|
|
1730
|
+
"aria-selected": tab.key === currentPath,
|
|
1731
|
+
className: "cursor-pointer",
|
|
1732
|
+
onClick: () => bridge.push(tab.key),
|
|
1733
|
+
children: tab.title
|
|
1734
|
+
}
|
|
1735
|
+
),
|
|
1736
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1737
|
+
"button",
|
|
1738
|
+
{
|
|
1739
|
+
type: "button",
|
|
1740
|
+
"data-slot": "admin-tab-close",
|
|
1741
|
+
"aria-label": t("pactor.layout.closeTab", { title: tab.title }),
|
|
1742
|
+
className: "cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1743
|
+
onClick: () => closeTab(tab.key),
|
|
1744
|
+
children: "\xD7"
|
|
1745
|
+
}
|
|
1746
|
+
)
|
|
1747
|
+
]
|
|
1748
|
+
},
|
|
1749
|
+
tab.key
|
|
1750
|
+
))
|
|
1751
|
+
}
|
|
1752
|
+
),
|
|
1753
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1754
|
+
"main",
|
|
1755
|
+
{
|
|
1756
|
+
"data-slot": "admin-content",
|
|
1757
|
+
className: "flex-1 bg-muted/40 p-6",
|
|
1758
|
+
children: [
|
|
1759
|
+
showBreadcrumb && breadcrumbItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1760
|
+
"nav",
|
|
1761
|
+
{
|
|
1762
|
+
"data-slot": "admin-breadcrumb",
|
|
1763
|
+
"aria-label": t("pactor.layout.breadcrumb"),
|
|
1764
|
+
className: "mb-4",
|
|
1765
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ol", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: breadcrumbItems.map((title, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("li", { className: "flex items-center gap-2", children: [
|
|
1766
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, children: "/" }),
|
|
1767
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "data-slot": "breadcrumb-link", children: title })
|
|
1768
|
+
] }, index)) })
|
|
1769
|
+
}
|
|
1770
|
+
),
|
|
1771
|
+
children
|
|
1772
|
+
]
|
|
1773
|
+
}
|
|
1774
|
+
)
|
|
1775
|
+
] });
|
|
1776
|
+
const footer = showFooter ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1777
|
+
"footer",
|
|
1778
|
+
{
|
|
1779
|
+
"data-slot": "admin-footer",
|
|
1780
|
+
className: "bg-muted p-4 text-center text-sm text-muted-foreground",
|
|
1781
|
+
children: brand.title
|
|
1782
|
+
}
|
|
1783
|
+
) : null;
|
|
1784
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1785
|
+
"div",
|
|
1786
|
+
{
|
|
1787
|
+
"data-slot": "admin-layout",
|
|
1788
|
+
"data-mode": mode,
|
|
1789
|
+
"data-fixed-header": fixedHeader || void 0,
|
|
1790
|
+
"data-fixed-sider": fixedSider || void 0,
|
|
1791
|
+
className: "flex min-h-screen flex-col bg-background text-foreground",
|
|
1792
|
+
children: mode === "side-full" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "data-slot": "admin-side-full", className: "flex min-h-screen flex-1", children: [
|
|
1793
|
+
sidebar,
|
|
1794
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1795
|
+
"div",
|
|
1796
|
+
{
|
|
1797
|
+
"data-slot": "admin-side-full-main",
|
|
1798
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
1799
|
+
children: [
|
|
1800
|
+
header,
|
|
1801
|
+
body,
|
|
1802
|
+
footer
|
|
1803
|
+
]
|
|
1804
|
+
}
|
|
1805
|
+
)
|
|
1806
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
1807
|
+
header,
|
|
1808
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "data-slot": "admin-main", className: "flex min-h-0 flex-1", children: [
|
|
1809
|
+
sidebar,
|
|
1810
|
+
body
|
|
1811
|
+
] }),
|
|
1812
|
+
footer
|
|
1813
|
+
] })
|
|
1814
|
+
}
|
|
1815
|
+
);
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
// src/layout/basic/ShadcnBlankLayout.tsx
|
|
1819
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1820
|
+
function ShadcnBlankLayout({ children }) {
|
|
1821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1822
|
+
"div",
|
|
1823
|
+
{
|
|
1824
|
+
"data-slot": "blank-layout",
|
|
1825
|
+
className: "min-h-screen bg-background text-foreground",
|
|
1826
|
+
children
|
|
1827
|
+
}
|
|
1828
|
+
);
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
// src/layout/basic/ShadcnLoginLayout.tsx
|
|
1832
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1833
|
+
function ShadcnLoginLayout({
|
|
1834
|
+
variant = "center",
|
|
1835
|
+
brand,
|
|
1836
|
+
children
|
|
1837
|
+
}) {
|
|
1838
|
+
const brandBlock = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { "data-slot": "login-brand", className: "flex flex-col items-center gap-2", children: [
|
|
1839
|
+
brand.logo,
|
|
1840
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h1", { className: "text-xl font-semibold", children: brand.title }),
|
|
1841
|
+
brand.description !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "text-sm text-muted-foreground", children: brand.description })
|
|
1842
|
+
] });
|
|
1843
|
+
if (variant === "split") {
|
|
1844
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
1845
|
+
"div",
|
|
1846
|
+
{
|
|
1847
|
+
"data-slot": "login-layout",
|
|
1848
|
+
"data-variant": "split",
|
|
1849
|
+
className: "grid min-h-screen grid-cols-2 bg-background text-foreground",
|
|
1850
|
+
children: [
|
|
1851
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1852
|
+
"div",
|
|
1853
|
+
{
|
|
1854
|
+
"data-slot": "login-brand-panel",
|
|
1855
|
+
className: "flex items-center justify-center bg-muted/40 p-10",
|
|
1856
|
+
children: brandBlock
|
|
1857
|
+
}
|
|
1858
|
+
),
|
|
1859
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1860
|
+
"div",
|
|
1861
|
+
{
|
|
1862
|
+
"data-slot": "login-form-panel",
|
|
1863
|
+
className: "flex items-center justify-center p-10",
|
|
1864
|
+
children
|
|
1865
|
+
}
|
|
1866
|
+
)
|
|
1867
|
+
]
|
|
1868
|
+
}
|
|
1869
|
+
);
|
|
1870
|
+
}
|
|
1871
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1872
|
+
"div",
|
|
1873
|
+
{
|
|
1874
|
+
"data-slot": "login-layout",
|
|
1875
|
+
"data-variant": "center",
|
|
1876
|
+
className: "flex min-h-screen items-center justify-center bg-muted/40 text-foreground",
|
|
1877
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(Card, { "data-slot": "login-card", className: "w-full max-w-sm gap-4 py-6", children: [
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CardHeader, { className: "px-6", children: [
|
|
1879
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CardTitle, { className: "sr-only", children: brand.title }),
|
|
1880
|
+
brandBlock
|
|
1881
|
+
] }),
|
|
1882
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CardContent, { className: "flex flex-col gap-4 px-6", children })
|
|
1883
|
+
] })
|
|
1884
|
+
}
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
// src/layout/basic/ShadcnLandingLayout.tsx
|
|
1889
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1890
|
+
function ShadcnLandingLayout({
|
|
1891
|
+
navbar,
|
|
1892
|
+
footer,
|
|
1893
|
+
children
|
|
1894
|
+
}) {
|
|
1895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1896
|
+
"div",
|
|
1897
|
+
{
|
|
1898
|
+
"data-slot": "landing-layout",
|
|
1899
|
+
className: "flex min-h-screen flex-col bg-background text-foreground",
|
|
1900
|
+
children: [
|
|
1901
|
+
navbar !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1902
|
+
"header",
|
|
1903
|
+
{
|
|
1904
|
+
"data-slot": "landing-navbar",
|
|
1905
|
+
className: "border-b border-border bg-background",
|
|
1906
|
+
children: navbar
|
|
1907
|
+
}
|
|
1908
|
+
),
|
|
1909
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("main", { "data-slot": "landing-content", className: "flex-1", children }),
|
|
1910
|
+
footer !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1911
|
+
"footer",
|
|
1912
|
+
{
|
|
1913
|
+
"data-slot": "landing-footer",
|
|
1914
|
+
className: "border-t border-border text-sm text-muted-foreground",
|
|
1915
|
+
children: footer
|
|
1916
|
+
}
|
|
1917
|
+
)
|
|
1918
|
+
]
|
|
1919
|
+
}
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
// src/layout/registry.ts
|
|
1924
|
+
var import_core2 = require("@pactor-app/core");
|
|
1925
|
+
function registerShadcnLayouts(registry) {
|
|
1926
|
+
registry.register("admin", ShadcnAdminLayout);
|
|
1927
|
+
registry.register("blank", ShadcnBlankLayout);
|
|
1928
|
+
registry.register("login", ShadcnLoginLayout);
|
|
1929
|
+
registry.register("landing", ShadcnLandingLayout);
|
|
1930
|
+
}
|
|
1931
|
+
function createShadcnLayoutRegistry() {
|
|
1932
|
+
const registry = new import_core2.Registry("LayoutRegistry");
|
|
1933
|
+
registerShadcnLayouts(registry);
|
|
1934
|
+
return registry;
|
|
1935
|
+
}
|
|
1936
|
+
function resolveLayout(registry, type) {
|
|
1937
|
+
const component = registry.get(type);
|
|
1938
|
+
if (component === void 0) {
|
|
1939
|
+
console.warn(
|
|
1940
|
+
`[pactor-layout] unknown layout type "${type}", fallback to BlankLayout`
|
|
1941
|
+
);
|
|
1942
|
+
return ShadcnBlankLayout;
|
|
1943
|
+
}
|
|
1944
|
+
return component;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
// src/interaction/manager.ts
|
|
1948
|
+
var OVERLAY_CANCEL_PAYLOAD = { success: false };
|
|
1949
|
+
var OverlayManager = class {
|
|
1950
|
+
constructor() {
|
|
1951
|
+
this.pending = [];
|
|
1952
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
1953
|
+
this.counter = 0;
|
|
1954
|
+
/** 缓存的堆栈快照:变化时才更换引用,供 useSyncExternalStore 使用 */
|
|
1955
|
+
this.snapshot = Object.freeze([]);
|
|
1956
|
+
}
|
|
1957
|
+
/**
|
|
1958
|
+
* 打开 overlay:入栈、通知,返回 Promise——close 时以 payload
|
|
1959
|
+
* resolve;取消关闭(无 payload)resolve `{ success: false }`。
|
|
1960
|
+
* `options.parentScope` 记录打开时刻的父作用域浅快照。
|
|
1961
|
+
*/
|
|
1962
|
+
open(config, options = {}) {
|
|
1963
|
+
if (!config || config.type !== "modal" && config.type !== "drawer") {
|
|
1964
|
+
return Promise.reject(
|
|
1965
|
+
new Error(
|
|
1966
|
+
'[pactor-interaction] overlay.open \u9700\u8981 type \u4E3A "modal" \u6216 "drawer" \u7684\u914D\u7F6E'
|
|
1967
|
+
)
|
|
1968
|
+
);
|
|
1969
|
+
}
|
|
1970
|
+
this.counter += 1;
|
|
1971
|
+
const entry = { ...config, id: `overlay-${this.counter}` };
|
|
1972
|
+
return new Promise((resolve) => {
|
|
1973
|
+
this.pending.push({
|
|
1974
|
+
entry,
|
|
1975
|
+
parentScope: options.parentScope ? { ...options.parentScope } : void 0,
|
|
1976
|
+
resolve
|
|
1977
|
+
});
|
|
1978
|
+
this.commit();
|
|
1979
|
+
});
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* 关闭 overlay 并以 payload resolve 对应的 open Promise:
|
|
1983
|
+
* - `close(id, payload)`:关闭指定条目,原样 resolve payload
|
|
1984
|
+
* (payload 缺省为取消语义 `{ success: false }`)
|
|
1985
|
+
* - `close(payload)`:关闭栈顶,原样 resolve payload
|
|
1986
|
+
* - `close()`:关闭栈顶,取消语义
|
|
1987
|
+
* 未命中任何条目时为受控 no-op,不抛错。
|
|
1988
|
+
*/
|
|
1989
|
+
close(idOrPayload, payload) {
|
|
1990
|
+
let index;
|
|
1991
|
+
let resolvedPayload;
|
|
1992
|
+
if (typeof idOrPayload === "string") {
|
|
1993
|
+
index = this.pending.findIndex((p) => p.entry.id === idOrPayload);
|
|
1994
|
+
if (index === -1) {
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
resolvedPayload = payload;
|
|
1998
|
+
} else {
|
|
1999
|
+
index = this.pending.length - 1;
|
|
2000
|
+
if (index === -1) {
|
|
2001
|
+
return;
|
|
2002
|
+
}
|
|
2003
|
+
resolvedPayload = idOrPayload === void 0 ? payload : idOrPayload;
|
|
2004
|
+
}
|
|
2005
|
+
const [target] = this.pending.splice(index, 1);
|
|
2006
|
+
this.commit();
|
|
2007
|
+
target?.resolve(
|
|
2008
|
+
resolvedPayload === void 0 ? OVERLAY_CANCEL_PAYLOAD : resolvedPayload
|
|
2009
|
+
);
|
|
2010
|
+
}
|
|
2011
|
+
/** 当前堆栈快照(打开顺序,栈顶在末尾);引用在堆栈不变时保持稳定 */
|
|
2012
|
+
stack() {
|
|
2013
|
+
return this.snapshot;
|
|
2014
|
+
}
|
|
2015
|
+
/** 打开时记录的父作用域浅快照(只读约定);未知 id 返回 undefined */
|
|
2016
|
+
parentScopeOf(id) {
|
|
2017
|
+
return this.pending.find((p) => p.entry.id === id)?.parentScope;
|
|
2018
|
+
}
|
|
2019
|
+
/** 订阅堆栈变化(open / close 时通知),返回退订函数 */
|
|
2020
|
+
subscribe(listener) {
|
|
2021
|
+
this.listeners.add(listener);
|
|
2022
|
+
return () => {
|
|
2023
|
+
this.listeners.delete(listener);
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
/** 重建快照并通知订阅者 */
|
|
2027
|
+
commit() {
|
|
2028
|
+
this.snapshot = Object.freeze(this.pending.map((p) => p.entry));
|
|
2029
|
+
for (const listener of [...this.listeners]) {
|
|
2030
|
+
listener(this.snapshot);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
};
|
|
2034
|
+
|
|
2035
|
+
// src/interaction/actions.ts
|
|
2036
|
+
var import_runtime6 = require("@pactor-app/runtime");
|
|
2037
|
+
function createUiBridge() {
|
|
2038
|
+
return {};
|
|
2039
|
+
}
|
|
2040
|
+
function registerInteractionActions(actions, manager, ui) {
|
|
2041
|
+
const register = (name, handler) => {
|
|
2042
|
+
if (!actions.has(name)) {
|
|
2043
|
+
actions.register(name, handler);
|
|
2044
|
+
}
|
|
2045
|
+
};
|
|
2046
|
+
register("overlay.open", async (action, ctx) => {
|
|
2047
|
+
const overlay = action.params?.["overlay"];
|
|
2048
|
+
if (!isRecord(overlay)) {
|
|
2049
|
+
return failure("[pactor-interaction] overlay.open \u7F3A\u5C11 overlay \u914D\u7F6E\u53C2\u6570");
|
|
2050
|
+
}
|
|
2051
|
+
const { content, ...rest } = overlay;
|
|
2052
|
+
const resolved = (0, import_runtime6.resolveDeep)(rest, ctx.scope);
|
|
2053
|
+
const config = { ...resolved, content };
|
|
2054
|
+
const data = await manager.open(config, {
|
|
2055
|
+
parentScope: { ...ctx.scope }
|
|
2056
|
+
});
|
|
2057
|
+
return { ok: true, data };
|
|
2058
|
+
});
|
|
2059
|
+
register("overlay.close", (action) => {
|
|
2060
|
+
const id = action.params?.["id"];
|
|
2061
|
+
const payload = action.params?.["payload"];
|
|
2062
|
+
if (typeof id === "string" && id) {
|
|
2063
|
+
manager.close(id, payload);
|
|
2064
|
+
} else if (payload !== void 0) {
|
|
2065
|
+
manager.close(payload);
|
|
2066
|
+
} else {
|
|
2067
|
+
manager.close();
|
|
2068
|
+
}
|
|
2069
|
+
return { ok: true };
|
|
2070
|
+
});
|
|
2071
|
+
register("confirm", async (action) => {
|
|
2072
|
+
const modal = ui.modal;
|
|
2073
|
+
if (!modal) {
|
|
2074
|
+
return failure(
|
|
2075
|
+
"[pactor-interaction] confirm \u52A8\u4F5C\u9700\u8981 <InteractionProvider> \u6CE8\u5165 modal \u5B9E\u4F8B"
|
|
2076
|
+
);
|
|
2077
|
+
}
|
|
2078
|
+
const params = action.params ?? {};
|
|
2079
|
+
const data = await new Promise((resolve) => {
|
|
2080
|
+
modal.confirm({
|
|
2081
|
+
title: params["title"],
|
|
2082
|
+
content: params["content"],
|
|
2083
|
+
onOk: () => resolve(true),
|
|
2084
|
+
onCancel: () => resolve(false)
|
|
2085
|
+
});
|
|
2086
|
+
});
|
|
2087
|
+
return { ok: true, data };
|
|
2088
|
+
});
|
|
2089
|
+
register("message", (action) => {
|
|
2090
|
+
const message = ui.message;
|
|
2091
|
+
if (!message) {
|
|
2092
|
+
return failure(
|
|
2093
|
+
"[pactor-interaction] message \u52A8\u4F5C\u9700\u8981 <InteractionProvider> \u6CE8\u5165 message \u5B9E\u4F8B"
|
|
2094
|
+
);
|
|
2095
|
+
}
|
|
2096
|
+
const params = action.params ?? {};
|
|
2097
|
+
const type = params["type"];
|
|
2098
|
+
const text = params["text"];
|
|
2099
|
+
if (type === "success" || type === "error" || type === "warning") {
|
|
2100
|
+
message[type](text);
|
|
2101
|
+
} else {
|
|
2102
|
+
message.info(text);
|
|
2103
|
+
}
|
|
2104
|
+
return { ok: true };
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
function failure(message) {
|
|
2108
|
+
return { ok: false, error: new Error(message) };
|
|
2109
|
+
}
|
|
2110
|
+
function isRecord(value) {
|
|
2111
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
// src/interaction/provider.tsx
|
|
2115
|
+
var import_react9 = require("react");
|
|
2116
|
+
var import_react_dom = require("react-dom");
|
|
2117
|
+
|
|
2118
|
+
// src/ui/dialog.tsx
|
|
2119
|
+
var import_dialog = require("@base-ui/react/dialog");
|
|
2120
|
+
var import_lucide_react4 = require("lucide-react");
|
|
2121
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2122
|
+
function Dialog({
|
|
2123
|
+
...props
|
|
2124
|
+
}) {
|
|
2125
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_dialog.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
2126
|
+
}
|
|
2127
|
+
function DialogPortal({
|
|
2128
|
+
...props
|
|
2129
|
+
}) {
|
|
2130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_dialog.Dialog.Portal, { "data-slot": "dialog-portal", ...props });
|
|
2131
|
+
}
|
|
2132
|
+
function DialogClose({
|
|
2133
|
+
...props
|
|
2134
|
+
}) {
|
|
2135
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_dialog.Dialog.Close, { "data-slot": "dialog-close", ...props });
|
|
2136
|
+
}
|
|
2137
|
+
function DialogOverlay({
|
|
2138
|
+
className,
|
|
2139
|
+
...props
|
|
2140
|
+
}) {
|
|
2141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2142
|
+
import_dialog.Dialog.Backdrop,
|
|
2143
|
+
{
|
|
2144
|
+
"data-slot": "dialog-overlay",
|
|
2145
|
+
className: cn(
|
|
2146
|
+
"fixed inset-0 z-50 bg-black/50 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
2147
|
+
className
|
|
2148
|
+
),
|
|
2149
|
+
...props
|
|
2150
|
+
}
|
|
2151
|
+
);
|
|
2152
|
+
}
|
|
2153
|
+
function DialogContent({
|
|
2154
|
+
className,
|
|
2155
|
+
children,
|
|
2156
|
+
showCloseButton = true,
|
|
2157
|
+
...props
|
|
2158
|
+
}) {
|
|
2159
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
2160
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DialogOverlay, {}),
|
|
2161
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
2162
|
+
import_dialog.Dialog.Popup,
|
|
2163
|
+
{
|
|
2164
|
+
"data-slot": "dialog-content",
|
|
2165
|
+
className: cn(
|
|
2166
|
+
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-border bg-background p-6 shadow-lg duration-200 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 sm:max-w-lg",
|
|
2167
|
+
className
|
|
2168
|
+
),
|
|
2169
|
+
...props,
|
|
2170
|
+
children: [
|
|
2171
|
+
children,
|
|
2172
|
+
showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
2173
|
+
import_dialog.Dialog.Close,
|
|
2174
|
+
{
|
|
2175
|
+
"data-slot": "dialog-close",
|
|
2176
|
+
render: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2177
|
+
"button",
|
|
2178
|
+
{
|
|
2179
|
+
type: "button",
|
|
2180
|
+
className: "absolute top-4 right-4 cursor-pointer rounded-xs opacity-70 transition-opacity hover:opacity-100 focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-none disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
2181
|
+
}
|
|
2182
|
+
),
|
|
2183
|
+
children: [
|
|
2184
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react4.XIcon, {}),
|
|
2185
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "sr-only", children: "Close" })
|
|
2186
|
+
]
|
|
2187
|
+
}
|
|
2188
|
+
)
|
|
2189
|
+
]
|
|
2190
|
+
}
|
|
2191
|
+
)
|
|
2192
|
+
] });
|
|
2193
|
+
}
|
|
2194
|
+
function DialogHeader({ className, ...props }) {
|
|
2195
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2196
|
+
"div",
|
|
2197
|
+
{
|
|
2198
|
+
"data-slot": "dialog-header",
|
|
2199
|
+
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
2200
|
+
...props
|
|
2201
|
+
}
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
function DialogFooter({ className, ...props }) {
|
|
2205
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2206
|
+
"div",
|
|
2207
|
+
{
|
|
2208
|
+
"data-slot": "dialog-footer",
|
|
2209
|
+
className: cn(
|
|
2210
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
2211
|
+
className
|
|
2212
|
+
),
|
|
2213
|
+
...props
|
|
2214
|
+
}
|
|
2215
|
+
);
|
|
2216
|
+
}
|
|
2217
|
+
function DialogTitle({
|
|
2218
|
+
className,
|
|
2219
|
+
...props
|
|
2220
|
+
}) {
|
|
2221
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2222
|
+
import_dialog.Dialog.Title,
|
|
2223
|
+
{
|
|
2224
|
+
"data-slot": "dialog-title",
|
|
2225
|
+
className: cn("text-lg leading-none font-semibold", className),
|
|
2226
|
+
...props
|
|
2227
|
+
}
|
|
2228
|
+
);
|
|
2229
|
+
}
|
|
2230
|
+
function DialogDescription({
|
|
2231
|
+
className,
|
|
2232
|
+
...props
|
|
2233
|
+
}) {
|
|
2234
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2235
|
+
import_dialog.Dialog.Description,
|
|
2236
|
+
{
|
|
2237
|
+
"data-slot": "dialog-description",
|
|
2238
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
2239
|
+
...props
|
|
2240
|
+
}
|
|
2241
|
+
);
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
// src/interaction/provider.tsx
|
|
2245
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2246
|
+
var TOAST_DURATION = 3e3;
|
|
2247
|
+
var toastTypeClass = {
|
|
2248
|
+
success: "border-l-4 border-l-success",
|
|
2249
|
+
error: "border-l-4 border-l-destructive",
|
|
2250
|
+
info: "border-l-4 border-l-info",
|
|
2251
|
+
warning: "border-l-4 border-l-warning"
|
|
2252
|
+
};
|
|
2253
|
+
function ShadcnInteractionProvider({
|
|
2254
|
+
bridge,
|
|
2255
|
+
children
|
|
2256
|
+
}) {
|
|
2257
|
+
const [confirmState, setConfirmState] = (0, import_react9.useState)(null);
|
|
2258
|
+
const [toasts, setToasts] = (0, import_react9.useState)([]);
|
|
2259
|
+
const { modal, message } = (0, import_react9.useMemo)(() => {
|
|
2260
|
+
const pushToast = (type, content) => {
|
|
2261
|
+
const id = Date.now() + Math.random();
|
|
2262
|
+
setToasts((prev) => [...prev, { id, type, content }]);
|
|
2263
|
+
setTimeout(() => {
|
|
2264
|
+
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
|
2265
|
+
}, TOAST_DURATION);
|
|
2266
|
+
};
|
|
2267
|
+
const modalImpl = {
|
|
2268
|
+
confirm(config) {
|
|
2269
|
+
setConfirmState({ ...config });
|
|
2270
|
+
}
|
|
2271
|
+
};
|
|
2272
|
+
const messageImpl = {
|
|
2273
|
+
success: (content) => pushToast("success", content),
|
|
2274
|
+
error: (content) => pushToast("error", content),
|
|
2275
|
+
info: (content) => pushToast("info", content),
|
|
2276
|
+
warning: (content) => pushToast("warning", content)
|
|
2277
|
+
};
|
|
2278
|
+
return { modal: modalImpl, message: messageImpl };
|
|
2279
|
+
}, []);
|
|
2280
|
+
(0, import_react9.useEffect)(() => {
|
|
2281
|
+
bridge.modal = modal;
|
|
2282
|
+
bridge.message = message;
|
|
2283
|
+
return () => {
|
|
2284
|
+
bridge.modal = void 0;
|
|
2285
|
+
bridge.message = void 0;
|
|
2286
|
+
};
|
|
2287
|
+
}, [bridge, modal, message]);
|
|
2288
|
+
const handleOk = () => {
|
|
2289
|
+
const state = confirmState;
|
|
2290
|
+
setConfirmState(null);
|
|
2291
|
+
state?.onOk?.();
|
|
2292
|
+
};
|
|
2293
|
+
const handleCancel = () => {
|
|
2294
|
+
const state = confirmState;
|
|
2295
|
+
setConfirmState(null);
|
|
2296
|
+
state?.onCancel?.();
|
|
2297
|
+
};
|
|
2298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
2299
|
+
children,
|
|
2300
|
+
typeof document !== "undefined" && (0, import_react_dom.createPortal)(
|
|
2301
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
2302
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2303
|
+
Dialog,
|
|
2304
|
+
{
|
|
2305
|
+
open: confirmState !== null,
|
|
2306
|
+
onOpenChange: (open) => {
|
|
2307
|
+
if (!open) {
|
|
2308
|
+
handleCancel();
|
|
2309
|
+
}
|
|
2310
|
+
},
|
|
2311
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DialogContent, { "data-slot": "confirm-dialog", className: "sm:max-w-sm", children: [
|
|
2312
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DialogHeader, { children: [
|
|
2313
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(DialogTitle, { children: confirmState?.title ?? "" }),
|
|
2314
|
+
confirmState?.content !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2315
|
+
DialogDescription,
|
|
2316
|
+
{
|
|
2317
|
+
render: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { children: confirmState.content })
|
|
2318
|
+
}
|
|
2319
|
+
)
|
|
2320
|
+
] }),
|
|
2321
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DialogFooter, { children: [
|
|
2322
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Button, { type: "button", variant: "outline", onClick: handleCancel, children: "\u53D6\u6D88" }),
|
|
2323
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Button, { type: "button", onClick: handleOk, children: "\u786E\u5B9A" })
|
|
2324
|
+
] })
|
|
2325
|
+
] })
|
|
2326
|
+
}
|
|
2327
|
+
),
|
|
2328
|
+
toasts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2329
|
+
"div",
|
|
2330
|
+
{
|
|
2331
|
+
"data-slot": "toast-container",
|
|
2332
|
+
className: "fixed top-4 right-4 z-[100] flex w-80 flex-col gap-2",
|
|
2333
|
+
children: toasts.map((toast) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2334
|
+
"div",
|
|
2335
|
+
{
|
|
2336
|
+
"data-slot": "toast",
|
|
2337
|
+
"data-type": toast.type,
|
|
2338
|
+
role: "status",
|
|
2339
|
+
className: cn(
|
|
2340
|
+
"rounded-md border border-border bg-popover px-4 py-3 text-sm text-popover-foreground shadow-md",
|
|
2341
|
+
toastTypeClass[toast.type]
|
|
2342
|
+
),
|
|
2343
|
+
children: toast.content
|
|
2344
|
+
},
|
|
2345
|
+
toast.id
|
|
2346
|
+
))
|
|
2347
|
+
}
|
|
2348
|
+
)
|
|
2349
|
+
] }),
|
|
2350
|
+
document.body
|
|
2351
|
+
)
|
|
2352
|
+
] });
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
// src/interaction/host.tsx
|
|
2356
|
+
var import_lucide_react5 = require("lucide-react");
|
|
2357
|
+
var import_runtime7 = require("@pactor-app/runtime");
|
|
2358
|
+
var import_react10 = require("react");
|
|
2359
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
2360
|
+
function toCssWidth(width) {
|
|
2361
|
+
if (width === void 0) {
|
|
2362
|
+
return void 0;
|
|
2363
|
+
}
|
|
2364
|
+
return typeof width === "number" ? `${width}px` : width;
|
|
2365
|
+
}
|
|
2366
|
+
function ShadcnOverlayHost({ manager, resolvePage }) {
|
|
2367
|
+
const renderer = (0, import_runtime7.useRenderer)();
|
|
2368
|
+
const stack = (0, import_react10.useSyncExternalStore)(
|
|
2369
|
+
(onChange) => manager.subscribe(onChange),
|
|
2370
|
+
() => manager.stack()
|
|
2371
|
+
);
|
|
2372
|
+
(0, import_react10.useSyncExternalStore)(
|
|
2373
|
+
(onChange) => {
|
|
2374
|
+
const offState = renderer.context.state.subscribe(onChange);
|
|
2375
|
+
const offData = renderer.context.data.subscribe(onChange);
|
|
2376
|
+
return () => {
|
|
2377
|
+
offState();
|
|
2378
|
+
offData();
|
|
2379
|
+
};
|
|
2380
|
+
},
|
|
2381
|
+
() => `${renderer.context.state.getVersion()}:${renderer.context.data.getVersion()}`
|
|
2382
|
+
);
|
|
2383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children: stack.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2384
|
+
OverlayEntryView,
|
|
2385
|
+
{
|
|
2386
|
+
entry,
|
|
2387
|
+
manager,
|
|
2388
|
+
renderer,
|
|
2389
|
+
resolvePage
|
|
2390
|
+
},
|
|
2391
|
+
entry.id
|
|
2392
|
+
)) });
|
|
2393
|
+
}
|
|
2394
|
+
function OverlayEntryView({
|
|
2395
|
+
entry,
|
|
2396
|
+
manager,
|
|
2397
|
+
renderer,
|
|
2398
|
+
resolvePage
|
|
2399
|
+
}) {
|
|
2400
|
+
const handleCancel = () => manager.close(entry.id);
|
|
2401
|
+
let body = null;
|
|
2402
|
+
if (entry.content) {
|
|
2403
|
+
body = renderer.renderChildren([entry.content], {
|
|
2404
|
+
params: entry.params ?? {},
|
|
2405
|
+
parent: manager.parentScopeOf(entry.id)
|
|
2406
|
+
});
|
|
2407
|
+
} else if (entry.page) {
|
|
2408
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2409
|
+
PageOverlayBody,
|
|
2410
|
+
{
|
|
2411
|
+
entry,
|
|
2412
|
+
renderer,
|
|
2413
|
+
resolvePage
|
|
2414
|
+
}
|
|
2415
|
+
);
|
|
2416
|
+
}
|
|
2417
|
+
if (entry.type === "drawer") {
|
|
2418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ShadcnDrawerView, { entry, onCancel: handleCancel, children: body });
|
|
2419
|
+
}
|
|
2420
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2421
|
+
Dialog,
|
|
2422
|
+
{
|
|
2423
|
+
open: true,
|
|
2424
|
+
onOpenChange: (open) => {
|
|
2425
|
+
if (!open) {
|
|
2426
|
+
handleCancel();
|
|
2427
|
+
}
|
|
2428
|
+
},
|
|
2429
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2430
|
+
DialogContent,
|
|
2431
|
+
{
|
|
2432
|
+
"data-slot": "overlay-modal",
|
|
2433
|
+
className: cn(entry.width !== void 0 && "sm:max-w-none"),
|
|
2434
|
+
style: entry.width === void 0 ? void 0 : { width: toCssWidth(entry.width) },
|
|
2435
|
+
showCloseButton: false,
|
|
2436
|
+
children: [
|
|
2437
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DialogHeader, { children: [
|
|
2438
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DialogTitle, { children: entry.title ?? "" }),
|
|
2439
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2440
|
+
DialogClose,
|
|
2441
|
+
{
|
|
2442
|
+
render: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2443
|
+
"button",
|
|
2444
|
+
{
|
|
2445
|
+
type: "button",
|
|
2446
|
+
"data-slot": "overlay-modal-close",
|
|
2447
|
+
"aria-label": "\u5173\u95ED",
|
|
2448
|
+
className: "absolute top-4 right-4 cursor-pointer rounded-xs opacity-70 transition-opacity hover:opacity-100 focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-none",
|
|
2449
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react5.XIcon, { className: "size-4" })
|
|
2450
|
+
}
|
|
2451
|
+
)
|
|
2452
|
+
}
|
|
2453
|
+
)
|
|
2454
|
+
] }),
|
|
2455
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { "data-slot": "overlay-modal-body", children: body })
|
|
2456
|
+
]
|
|
2457
|
+
}
|
|
2458
|
+
)
|
|
2459
|
+
}
|
|
2460
|
+
);
|
|
2461
|
+
}
|
|
2462
|
+
function ShadcnDrawerView({
|
|
2463
|
+
entry,
|
|
2464
|
+
onCancel,
|
|
2465
|
+
children
|
|
2466
|
+
}) {
|
|
2467
|
+
(0, import_react10.useEffect)(() => {
|
|
2468
|
+
const handleKeyDown = (event) => {
|
|
2469
|
+
if (event.key === "Escape") {
|
|
2470
|
+
onCancel();
|
|
2471
|
+
}
|
|
2472
|
+
};
|
|
2473
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2474
|
+
return () => {
|
|
2475
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
2476
|
+
};
|
|
2477
|
+
}, [onCancel]);
|
|
2478
|
+
const panelStyle = entry.width === void 0 ? void 0 : { width: toCssWidth(entry.width) };
|
|
2479
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { "data-slot": "drawer-root", children: [
|
|
2480
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2481
|
+
"div",
|
|
2482
|
+
{
|
|
2483
|
+
"data-slot": "drawer-mask",
|
|
2484
|
+
"data-testid": "drawer-mask",
|
|
2485
|
+
className: "fixed inset-0 z-50 bg-black/50",
|
|
2486
|
+
onClick: onCancel
|
|
2487
|
+
}
|
|
2488
|
+
),
|
|
2489
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2490
|
+
"div",
|
|
2491
|
+
{
|
|
2492
|
+
"data-slot": "drawer-panel",
|
|
2493
|
+
role: "dialog",
|
|
2494
|
+
"aria-modal": "true",
|
|
2495
|
+
"aria-label": entry.title,
|
|
2496
|
+
style: panelStyle,
|
|
2497
|
+
className: "fixed inset-y-0 right-0 z-50 flex w-96 max-w-full flex-col border-l border-border bg-background shadow-lg",
|
|
2498
|
+
children: [
|
|
2499
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2500
|
+
"div",
|
|
2501
|
+
{
|
|
2502
|
+
"data-slot": "drawer-header",
|
|
2503
|
+
className: "flex items-center justify-between border-b border-border px-6 py-4",
|
|
2504
|
+
children: [
|
|
2505
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-lg font-semibold", children: entry.title ?? "" }),
|
|
2506
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2507
|
+
"button",
|
|
2508
|
+
{
|
|
2509
|
+
type: "button",
|
|
2510
|
+
"data-slot": "drawer-close",
|
|
2511
|
+
"aria-label": "\u5173\u95ED",
|
|
2512
|
+
className: "cursor-pointer rounded-xs opacity-70 transition-opacity hover:opacity-100 focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-none",
|
|
2513
|
+
onClick: onCancel,
|
|
2514
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react5.XIcon, { className: "size-4" })
|
|
2515
|
+
}
|
|
2516
|
+
)
|
|
2517
|
+
]
|
|
2518
|
+
}
|
|
2519
|
+
),
|
|
2520
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { "data-slot": "drawer-body", className: "flex-1 overflow-auto p-6", children })
|
|
2521
|
+
]
|
|
2522
|
+
}
|
|
2523
|
+
)
|
|
2524
|
+
] });
|
|
2525
|
+
}
|
|
2526
|
+
function PageOverlayBody({
|
|
2527
|
+
entry,
|
|
2528
|
+
renderer,
|
|
2529
|
+
resolvePage
|
|
2530
|
+
}) {
|
|
2531
|
+
const [child, setChild] = (0, import_react10.useState)(null);
|
|
2532
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
2533
|
+
(0, import_react10.useEffect)(() => {
|
|
2534
|
+
if (!resolvePage) {
|
|
2535
|
+
setError(
|
|
2536
|
+
new Error(
|
|
2537
|
+
`[@pactor-app/ui] page overlay\uFF08pageId: "${entry.page?.pageId}"\uFF09\u9700\u8981 ShadcnOverlayHost \u6CE8\u5165 resolvePage`
|
|
2538
|
+
)
|
|
2539
|
+
);
|
|
2540
|
+
return;
|
|
2541
|
+
}
|
|
2542
|
+
let cancelled = false;
|
|
2543
|
+
let created = null;
|
|
2544
|
+
void (async () => {
|
|
2545
|
+
try {
|
|
2546
|
+
const pageDsl = await resolvePage(entry.page?.pageId ?? "");
|
|
2547
|
+
if (cancelled) {
|
|
2548
|
+
return;
|
|
2549
|
+
}
|
|
2550
|
+
const host = renderer.context;
|
|
2551
|
+
created = (0, import_runtime7.createPageRuntime)(pageDsl, {
|
|
2552
|
+
app: host.app,
|
|
2553
|
+
user: host.user,
|
|
2554
|
+
components: host.components,
|
|
2555
|
+
services: host.services,
|
|
2556
|
+
actions: host.actions,
|
|
2557
|
+
permission: host.permission,
|
|
2558
|
+
capabilities: host.capabilities,
|
|
2559
|
+
http: host.http,
|
|
2560
|
+
route: { params: entry.params ?? {} }
|
|
2561
|
+
});
|
|
2562
|
+
setChild(created);
|
|
2563
|
+
} catch (cause) {
|
|
2564
|
+
if (!cancelled) {
|
|
2565
|
+
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
})();
|
|
2569
|
+
return () => {
|
|
2570
|
+
cancelled = true;
|
|
2571
|
+
void created?.destroy();
|
|
2572
|
+
};
|
|
2573
|
+
}, [entry.id]);
|
|
2574
|
+
if (error) {
|
|
2575
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { role: "alert", children: error.message });
|
|
2576
|
+
}
|
|
2577
|
+
if (!child) {
|
|
2578
|
+
return null;
|
|
2579
|
+
}
|
|
2580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_runtime7.PageRuntimeView, { runtime: child });
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
// src/index.ts
|
|
2584
|
+
var shadcnUiKit = {
|
|
2585
|
+
componentRegistry: createShadcnComponentRegistry,
|
|
2586
|
+
layoutRegistry: createShadcnLayoutRegistry,
|
|
2587
|
+
interactionKit: {
|
|
2588
|
+
Provider: ShadcnInteractionProvider,
|
|
2589
|
+
OverlayHost: ShadcnOverlayHost
|
|
2590
|
+
}
|
|
2591
|
+
};
|
|
2592
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2593
|
+
0 && (module.exports = {
|
|
2594
|
+
Alert,
|
|
2595
|
+
Button,
|
|
2596
|
+
Card,
|
|
2597
|
+
Flex,
|
|
2598
|
+
Form,
|
|
2599
|
+
Grid,
|
|
2600
|
+
Input,
|
|
2601
|
+
OVERLAY_CANCEL_PAYLOAD,
|
|
2602
|
+
OverlayManager,
|
|
2603
|
+
Page,
|
|
2604
|
+
Select,
|
|
2605
|
+
ShadcnAdminLayout,
|
|
2606
|
+
ShadcnBlankLayout,
|
|
2607
|
+
ShadcnInteractionProvider,
|
|
2608
|
+
ShadcnLandingLayout,
|
|
2609
|
+
ShadcnLoginLayout,
|
|
2610
|
+
ShadcnOverlayHost,
|
|
2611
|
+
Statistic,
|
|
2612
|
+
Table,
|
|
2613
|
+
Tabs,
|
|
2614
|
+
collectDefaultOpenKeys,
|
|
2615
|
+
createShadcnComponentRegistry,
|
|
2616
|
+
createShadcnLayoutRegistry,
|
|
2617
|
+
createUiBridge,
|
|
2618
|
+
findMenuChain,
|
|
2619
|
+
registerInteractionActions,
|
|
2620
|
+
registerShadcnComponents,
|
|
2621
|
+
registerShadcnLayouts,
|
|
2622
|
+
resolveLayout,
|
|
2623
|
+
shadcnComponents,
|
|
2624
|
+
shadcnUiKit,
|
|
2625
|
+
useFormContext
|
|
2626
|
+
});
|