@cfast/ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +727 -0
  3. package/dist/chunk-755IRYDN.js +941 -0
  4. package/dist/chunk-7SNK37GF.js +418 -0
  5. package/dist/chunk-ASMYTWTR.js +356 -0
  6. package/dist/chunk-B2XXH5V4.js +66 -0
  7. package/dist/chunk-BQMXYYEV.js +348 -0
  8. package/dist/chunk-DTKBXCTU.js +211 -0
  9. package/dist/chunk-EYIBATYR.js +33 -0
  10. package/dist/chunk-FPZAQ2YQ.js +474 -0
  11. package/dist/chunk-G2OU4BYC.js +205 -0
  12. package/dist/chunk-JEGEIQ3R.js +925 -0
  13. package/dist/chunk-JUNLQJ6H.js +1013 -0
  14. package/dist/chunk-NRGMW3JA.js +906 -0
  15. package/dist/chunk-Q6FPL2OJ.js +1086 -0
  16. package/dist/chunk-QHWAGKNW.js +456 -0
  17. package/dist/chunk-QZT62CGJ.js +924 -0
  18. package/dist/chunk-RDTUEOLK.js +486 -0
  19. package/dist/chunk-RESL4IJJ.js +112 -0
  20. package/dist/chunk-UDCWQUTR.js +221 -0
  21. package/dist/chunk-UE7PZOIJ.js +11 -0
  22. package/dist/chunk-UTZTHGNE.js +84 -0
  23. package/dist/chunk-UVRXMOX5.js +439 -0
  24. package/dist/chunk-XFD3N2D4.js +161 -0
  25. package/dist/client-CXIHCQtA.d.ts +274 -0
  26. package/dist/client.d.ts +617 -0
  27. package/dist/client.js +54 -0
  28. package/dist/index.d.ts +415 -0
  29. package/dist/index.js +296 -0
  30. package/dist/joy.d.ts +199 -0
  31. package/dist/joy.js +1150 -0
  32. package/dist/permission-gate-DVmY42oz.d.ts +1269 -0
  33. package/dist/permission-gate-apt9T9Mu.d.ts +1256 -0
  34. package/dist/types-1bAiH2uK.d.ts +392 -0
  35. package/dist/types-BX6u5sAd.d.ts +403 -0
  36. package/dist/types-BpdY7w5l.d.ts +403 -0
  37. package/dist/types-BrepeVp8.d.ts +403 -0
  38. package/dist/types-BvAqMZhn.d.ts +403 -0
  39. package/dist/types-C74nSscq.d.ts +403 -0
  40. package/dist/types-DD1Cpx8F.d.ts +403 -0
  41. package/dist/types-DHUhQwJn.d.ts +403 -0
  42. package/dist/types-DZSJNt_M.d.ts +392 -0
  43. package/dist/types-DaaJiIjW.d.ts +391 -0
  44. package/dist/types-LUpWJwps.d.ts +403 -0
  45. package/dist/types-a7zVU6WE.d.ts +394 -0
  46. package/dist/types-biJTHMcH.d.ts +403 -0
  47. package/dist/types-ow_qSEYJ.d.ts +392 -0
  48. package/dist/types-wnLasZaB.d.ts +1234 -0
  49. package/package.json +88 -0
@@ -0,0 +1,439 @@
1
+ // src/plugin.tsx
2
+ import { createContext, useContext } from "react";
3
+
4
+ // src/headless-defaults.tsx
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ var headlessDefaults = {
7
+ // Actions
8
+ button: ({ children, onClick, disabled, loading, type }) => /* @__PURE__ */ jsx("button", { onClick, disabled: disabled || loading, type: type ?? "button", children: loading ? "Loading..." : children }),
9
+ tooltip: ({ children, title }) => /* @__PURE__ */ jsx("span", { title, children }),
10
+ confirmDialog: ({ open, onClose, onConfirm, title, description, confirmLabel, cancelLabel }) => open ? /* @__PURE__ */ jsxs("dialog", { open: true, children: [
11
+ /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("strong", { children: title }) }),
12
+ description ? /* @__PURE__ */ jsx("p", { children: description }) : null,
13
+ /* @__PURE__ */ jsxs("div", { children: [
14
+ /* @__PURE__ */ jsx("button", { onClick: onClose, children: cancelLabel ?? "Cancel" }),
15
+ /* @__PURE__ */ jsx("button", { onClick: onConfirm, children: confirmLabel ?? "Confirm" })
16
+ ] })
17
+ ] }) : null,
18
+ // Data display
19
+ table: ({ children }) => /* @__PURE__ */ jsx("table", { children }),
20
+ tableHead: ({ children }) => /* @__PURE__ */ jsx("thead", { children }),
21
+ tableBody: ({ children }) => /* @__PURE__ */ jsx("tbody", { children }),
22
+ tableRow: ({ children, onClick }) => /* @__PURE__ */ jsx("tr", { onClick, children }),
23
+ tableCell: ({ children, header, sortable, sortDirection, onSort }) => {
24
+ const Tag = header ? "th" : "td";
25
+ return /* @__PURE__ */ jsxs(
26
+ Tag,
27
+ {
28
+ onClick: sortable ? onSort : void 0,
29
+ style: sortable ? { cursor: "pointer" } : void 0,
30
+ children: [
31
+ children,
32
+ sortable && sortDirection ? sortDirection === "asc" ? " \u2191" : " \u2193" : null
33
+ ]
34
+ }
35
+ );
36
+ },
37
+ chip: ({ children, size }) => /* @__PURE__ */ jsx(
38
+ "span",
39
+ {
40
+ style: {
41
+ display: "inline-block",
42
+ padding: size === "sm" ? "1px 6px" : "2px 8px",
43
+ borderRadius: "12px",
44
+ fontSize: size === "sm" ? "12px" : "14px",
45
+ backgroundColor: "#eee"
46
+ },
47
+ children
48
+ }
49
+ ),
50
+ // Layout
51
+ appShell: ({ children, sidebar, header }) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", minHeight: "100vh" }, children: [
52
+ sidebar ? /* @__PURE__ */ jsx("nav", { children: sidebar }) : null,
53
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
54
+ header ?? null,
55
+ /* @__PURE__ */ jsx("main", { children })
56
+ ] })
57
+ ] }),
58
+ sidebar: ({ children }) => /* @__PURE__ */ jsx("aside", { style: { width: "240px", borderRight: "1px solid #ddd" }, children }),
59
+ pageContainer: ({ children, title, actions }) => /* @__PURE__ */ jsxs("div", { children: [
60
+ title || actions ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
61
+ title ? /* @__PURE__ */ jsx("h1", { children: title }) : null,
62
+ actions ?? null
63
+ ] }) : null,
64
+ children
65
+ ] }),
66
+ breadcrumb: ({ items }) => /* @__PURE__ */ jsx("nav", { "aria-label": "breadcrumb", children: items.map((item, i) => /* @__PURE__ */ jsxs("span", { children: [
67
+ i > 0 ? " / " : null,
68
+ item.to ? /* @__PURE__ */ jsx("a", { href: item.to, children: item.label }) : item.label
69
+ ] }, i)) }),
70
+ // Feedback
71
+ toast: ({ children }) => /* @__PURE__ */ jsx("div", { children }),
72
+ alert: ({ children, color }) => /* @__PURE__ */ jsx(
73
+ "div",
74
+ {
75
+ role: "alert",
76
+ style: {
77
+ padding: "8px 12px",
78
+ borderRadius: "4px",
79
+ backgroundColor: color === "danger" ? "#fee" : color === "success" ? "#efe" : color === "warning" ? "#ffe" : "#f5f5f5"
80
+ },
81
+ children
82
+ }
83
+ ),
84
+ // File
85
+ dropZone: ({ children, isDragOver, onClick, onDrop, onDragOver, onDragLeave }) => /* @__PURE__ */ jsx(
86
+ "div",
87
+ {
88
+ onClick,
89
+ onDrop: (e) => {
90
+ e.preventDefault();
91
+ onDrop(e.dataTransfer.files);
92
+ },
93
+ onDragOver: (e) => {
94
+ e.preventDefault();
95
+ onDragOver(e);
96
+ },
97
+ onDragLeave,
98
+ style: {
99
+ border: `2px dashed ${isDragOver ? "#4caf50" : "#ccc"}`,
100
+ borderRadius: "8px",
101
+ padding: "32px",
102
+ textAlign: "center",
103
+ cursor: "pointer"
104
+ },
105
+ children
106
+ }
107
+ )
108
+ };
109
+
110
+ // src/plugin.tsx
111
+ import { jsx as jsx2 } from "react/jsx-runtime";
112
+ var UIPluginContext = createContext(null);
113
+ function createUIPlugin(config) {
114
+ return { components: config.components };
115
+ }
116
+ function UIPluginProvider({
117
+ plugin,
118
+ children
119
+ }) {
120
+ return /* @__PURE__ */ jsx2(UIPluginContext.Provider, { value: plugin, children });
121
+ }
122
+ function useUIPlugin() {
123
+ return useContext(UIPluginContext);
124
+ }
125
+ function useComponent(slot) {
126
+ const plugin = useUIPlugin();
127
+ const component = plugin?.components[slot];
128
+ if (component) {
129
+ return component;
130
+ }
131
+ return headlessDefaults[slot];
132
+ }
133
+
134
+ // src/hooks/use-toast.ts
135
+ import { createContext as createContext2, useContext as useContext2, useCallback } from "react";
136
+ var ToastContext = createContext2(null);
137
+ function useToast() {
138
+ const ctx = useContext2(ToastContext);
139
+ if (!ctx) {
140
+ throw new Error("useToast must be used within a <ToastProvider>");
141
+ }
142
+ const show = useCallback(
143
+ (options) => ctx.show(options),
144
+ [ctx]
145
+ );
146
+ const success = useCallback(
147
+ (message, description) => ctx.show({ message, type: "success", description }),
148
+ [ctx]
149
+ );
150
+ const error = useCallback(
151
+ (message, description) => ctx.show({ message, type: "error", description }),
152
+ [ctx]
153
+ );
154
+ const info = useCallback(
155
+ (message, description) => ctx.show({ message, type: "info", description }),
156
+ [ctx]
157
+ );
158
+ const warning = useCallback(
159
+ (message, description) => ctx.show({ message, type: "warning", description }),
160
+ [ctx]
161
+ );
162
+ return { show, success, error, info, warning };
163
+ }
164
+
165
+ // src/components/avatar-with-initials.tsx
166
+ import { jsx as jsx3 } from "react/jsx-runtime";
167
+ function getInitials(name) {
168
+ return name.split(" ").map((part) => part[0]).join("").toUpperCase().slice(0, 2);
169
+ }
170
+ var sizeMap = { sm: 32, md: 40, lg: 56 };
171
+ function AvatarWithInitials({
172
+ src,
173
+ name,
174
+ size = "md"
175
+ }) {
176
+ const px = sizeMap[size];
177
+ if (src) {
178
+ return /* @__PURE__ */ jsx3(
179
+ "img",
180
+ {
181
+ src,
182
+ alt: name,
183
+ style: {
184
+ width: px,
185
+ height: px,
186
+ borderRadius: "50%",
187
+ objectFit: "cover"
188
+ }
189
+ }
190
+ );
191
+ }
192
+ return /* @__PURE__ */ jsx3(
193
+ "span",
194
+ {
195
+ "aria-label": name,
196
+ style: {
197
+ display: "inline-flex",
198
+ alignItems: "center",
199
+ justifyContent: "center",
200
+ width: px,
201
+ height: px,
202
+ borderRadius: "50%",
203
+ backgroundColor: "#ddd",
204
+ fontSize: px * 0.4,
205
+ fontWeight: "bold"
206
+ },
207
+ children: getInitials(name)
208
+ }
209
+ );
210
+ }
211
+
212
+ // src/fields/date-field.tsx
213
+ import { jsx as jsx4 } from "react/jsx-runtime";
214
+ var rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
215
+ function getRelativeTime(date) {
216
+ const now = Date.now();
217
+ const diffMs = date.getTime() - now;
218
+ const diffSec = Math.round(diffMs / 1e3);
219
+ const diffMin = Math.round(diffSec / 60);
220
+ const diffHour = Math.round(diffMin / 60);
221
+ const diffDay = Math.round(diffHour / 24);
222
+ if (Math.abs(diffSec) < 60) return rtf.format(diffSec, "second");
223
+ if (Math.abs(diffMin) < 60) return rtf.format(diffMin, "minute");
224
+ if (Math.abs(diffHour) < 24) return rtf.format(diffHour, "hour");
225
+ if (Math.abs(diffDay) < 30) return rtf.format(diffDay, "day");
226
+ const diffMonth = Math.round(diffDay / 30);
227
+ if (Math.abs(diffMonth) < 12) return rtf.format(diffMonth, "month");
228
+ return rtf.format(Math.round(diffDay / 365), "year");
229
+ }
230
+ function formatDate(date, format, locale) {
231
+ switch (format) {
232
+ case "relative":
233
+ return getRelativeTime(date);
234
+ case "long":
235
+ return new Intl.DateTimeFormat(locale, {
236
+ dateStyle: "long"
237
+ }).format(date);
238
+ case "datetime":
239
+ return new Intl.DateTimeFormat(locale, {
240
+ dateStyle: "medium",
241
+ timeStyle: "short"
242
+ }).format(date);
243
+ case "short":
244
+ default:
245
+ return new Intl.DateTimeFormat(locale, {
246
+ dateStyle: "medium"
247
+ }).format(date);
248
+ }
249
+ }
250
+ function DateField({
251
+ value,
252
+ format = "short",
253
+ locale = "en"
254
+ }) {
255
+ if (value == null) {
256
+ return /* @__PURE__ */ jsx4("span", { children: "\u2014" });
257
+ }
258
+ const date = value instanceof Date ? value : new Date(value);
259
+ if (Number.isNaN(date.getTime())) {
260
+ return /* @__PURE__ */ jsx4("span", { children: "Invalid date" });
261
+ }
262
+ return /* @__PURE__ */ jsx4("time", { dateTime: date.toISOString(), children: formatDate(date, format, locale) });
263
+ }
264
+
265
+ // src/fields/boolean-field.tsx
266
+ import { jsx as jsx5 } from "react/jsx-runtime";
267
+ function BooleanField({
268
+ value,
269
+ trueLabel = "Yes",
270
+ falseLabel = "No",
271
+ trueColor = "success",
272
+ falseColor = "neutral"
273
+ }) {
274
+ const Chip = useComponent("chip");
275
+ if (value == null) {
276
+ return /* @__PURE__ */ jsx5("span", { children: "\u2014" });
277
+ }
278
+ return /* @__PURE__ */ jsx5(
279
+ Chip,
280
+ {
281
+ color: value ? trueColor : falseColor,
282
+ variant: "soft",
283
+ size: "sm",
284
+ children: value ? trueLabel : falseLabel
285
+ }
286
+ );
287
+ }
288
+
289
+ // src/fields/number-field.tsx
290
+ import { jsx as jsx6 } from "react/jsx-runtime";
291
+ function NumberField({
292
+ value,
293
+ locale = "en",
294
+ currency,
295
+ decimals
296
+ }) {
297
+ if (value == null) {
298
+ return /* @__PURE__ */ jsx6("span", { children: "\u2014" });
299
+ }
300
+ const options = {};
301
+ if (currency) {
302
+ options.style = "currency";
303
+ options.currency = currency;
304
+ }
305
+ if (decimals !== void 0) {
306
+ options.minimumFractionDigits = decimals;
307
+ options.maximumFractionDigits = decimals;
308
+ }
309
+ const formatted = new Intl.NumberFormat(locale, options).format(value);
310
+ return /* @__PURE__ */ jsx6("span", { children: formatted });
311
+ }
312
+
313
+ // src/fields/text-field.tsx
314
+ import { jsx as jsx7 } from "react/jsx-runtime";
315
+ function TextField({
316
+ value,
317
+ maxLength
318
+ }) {
319
+ if (value == null) {
320
+ return /* @__PURE__ */ jsx7("span", { children: "\u2014" });
321
+ }
322
+ const display = maxLength && value.length > maxLength ? `${value.slice(0, maxLength)}\u2026` : value;
323
+ if (maxLength && value.length > maxLength) {
324
+ return /* @__PURE__ */ jsx7("span", { title: value, children: display });
325
+ }
326
+ return /* @__PURE__ */ jsx7("span", { children: display });
327
+ }
328
+
329
+ // src/fields/email-field.tsx
330
+ import { jsx as jsx8 } from "react/jsx-runtime";
331
+ function EmailField({ value }) {
332
+ if (value == null) {
333
+ return /* @__PURE__ */ jsx8("span", { children: "\u2014" });
334
+ }
335
+ return /* @__PURE__ */ jsx8("a", { href: `mailto:${value}`, children: value });
336
+ }
337
+
338
+ // src/fields/json-field.tsx
339
+ import { useState } from "react";
340
+ import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
341
+ function JsonField({
342
+ value,
343
+ collapsed = false
344
+ }) {
345
+ const [isCollapsed, setIsCollapsed] = useState(collapsed);
346
+ if (value == null) {
347
+ return /* @__PURE__ */ jsx9("span", { children: "\u2014" });
348
+ }
349
+ const formatted = JSON.stringify(value, null, 2);
350
+ if (isCollapsed) {
351
+ const preview = JSON.stringify(value);
352
+ const short = preview.length > 60 ? `${preview.slice(0, 60)}\u2026` : preview;
353
+ return /* @__PURE__ */ jsxs2("span", { children: [
354
+ /* @__PURE__ */ jsx9("code", { children: short }),
355
+ " ",
356
+ /* @__PURE__ */ jsx9(
357
+ "button",
358
+ {
359
+ onClick: () => setIsCollapsed(false),
360
+ style: { border: "none", background: "none", cursor: "pointer", color: "#666", fontSize: "12px" },
361
+ children: "expand"
362
+ }
363
+ )
364
+ ] });
365
+ }
366
+ return /* @__PURE__ */ jsx9(
367
+ "pre",
368
+ {
369
+ style: {
370
+ margin: 0,
371
+ fontSize: "13px",
372
+ backgroundColor: "#f5f5f5",
373
+ padding: "8px",
374
+ borderRadius: "4px",
375
+ overflow: "auto"
376
+ },
377
+ children: /* @__PURE__ */ jsx9("code", { children: formatted })
378
+ }
379
+ );
380
+ }
381
+
382
+ // src/fields/field-for-column.ts
383
+ function fieldForColumn(column) {
384
+ const { dataType, name } = column;
385
+ const dt = dataType.toLowerCase();
386
+ if (dt === "boolean" || dt === "integer" && name.startsWith("is")) {
387
+ return BooleanField;
388
+ }
389
+ if (dt.includes("timestamp") || dt.includes("date") || dt.includes("datetime")) {
390
+ return DateField;
391
+ }
392
+ if (dt === "integer" || dt === "real" || dt === "numeric" || dt.includes("int") || dt.includes("float") || dt.includes("double") || dt.includes("decimal")) {
393
+ return NumberField;
394
+ }
395
+ if (name === "email" || name.endsWith("Email")) {
396
+ return EmailField;
397
+ }
398
+ if (dt === "json" || dt === "jsonb" || dt === "blob") {
399
+ return JsonField;
400
+ }
401
+ return TextField;
402
+ }
403
+ function fieldsForTable(table) {
404
+ const result = {};
405
+ for (const [key, col] of Object.entries(table)) {
406
+ if (col && typeof col === "object" && "dataType" in col && "name" in col) {
407
+ result[key] = fieldForColumn(col);
408
+ }
409
+ }
410
+ return result;
411
+ }
412
+
413
+ // src/hooks/use-action-status.ts
414
+ import { useActions } from "@cfast/actions/client";
415
+ function useActionStatus(descriptor) {
416
+ const actions = useActions(descriptor);
417
+ const name = descriptor.actionNames[0];
418
+ return actions[name]();
419
+ }
420
+
421
+ export {
422
+ createUIPlugin,
423
+ UIPluginProvider,
424
+ useUIPlugin,
425
+ useComponent,
426
+ ToastContext,
427
+ useToast,
428
+ getInitials,
429
+ AvatarWithInitials,
430
+ DateField,
431
+ BooleanField,
432
+ NumberField,
433
+ TextField,
434
+ EmailField,
435
+ JsonField,
436
+ fieldForColumn,
437
+ fieldsForTable,
438
+ useActionStatus
439
+ };
@@ -0,0 +1,161 @@
1
+ // src/plugin.ts
2
+ import { createContext, useContext, createElement as createElement2 } from "react";
3
+
4
+ // src/headless-defaults.ts
5
+ import { createElement } from "react";
6
+ var headlessDefaults = {
7
+ // Actions
8
+ button: ({ children, onClick, disabled, loading, type }) => createElement(
9
+ "button",
10
+ { onClick, disabled: disabled || loading, type: type ?? "button" },
11
+ loading ? "Loading..." : children
12
+ ),
13
+ tooltip: ({ children, title }) => createElement("span", { title }, children),
14
+ confirmDialog: ({ open, onClose, onConfirm, title, description, confirmLabel, cancelLabel }) => open ? createElement(
15
+ "dialog",
16
+ { open: true },
17
+ createElement("p", null, createElement("strong", null, title)),
18
+ description ? createElement("p", null, description) : null,
19
+ createElement(
20
+ "div",
21
+ null,
22
+ createElement("button", { onClick: onClose }, cancelLabel ?? "Cancel"),
23
+ createElement("button", { onClick: onConfirm }, confirmLabel ?? "Confirm")
24
+ )
25
+ ) : null,
26
+ // Data display
27
+ table: ({ children }) => createElement("table", null, children),
28
+ tableHead: ({ children }) => createElement("thead", null, children),
29
+ tableBody: ({ children }) => createElement("tbody", null, children),
30
+ tableRow: ({ children, onClick }) => createElement("tr", { onClick }, children),
31
+ tableCell: ({ children, header, sortable, sortDirection, onSort }) => createElement(
32
+ header ? "th" : "td",
33
+ {
34
+ onClick: sortable ? onSort : void 0,
35
+ style: sortable ? { cursor: "pointer" } : void 0
36
+ },
37
+ children,
38
+ sortable && sortDirection ? sortDirection === "asc" ? " \u2191" : " \u2193" : null
39
+ ),
40
+ chip: ({ children, size }) => createElement(
41
+ "span",
42
+ {
43
+ style: {
44
+ display: "inline-block",
45
+ padding: size === "sm" ? "1px 6px" : "2px 8px",
46
+ borderRadius: "12px",
47
+ fontSize: size === "sm" ? "12px" : "14px",
48
+ backgroundColor: "#eee"
49
+ }
50
+ },
51
+ children
52
+ ),
53
+ // Layout
54
+ appShell: ({ children, sidebar, header }) => createElement(
55
+ "div",
56
+ { style: { display: "flex", minHeight: "100vh" } },
57
+ sidebar ? createElement("nav", null, sidebar) : null,
58
+ createElement(
59
+ "div",
60
+ { style: { flex: 1 } },
61
+ header ?? null,
62
+ createElement("main", null, children)
63
+ )
64
+ ),
65
+ sidebar: ({ children }) => createElement(
66
+ "aside",
67
+ { style: { width: "240px", borderRight: "1px solid #ddd" } },
68
+ children
69
+ ),
70
+ pageContainer: ({ children, title, actions }) => createElement(
71
+ "div",
72
+ null,
73
+ title || actions ? createElement(
74
+ "div",
75
+ { style: { display: "flex", justifyContent: "space-between", alignItems: "center" } },
76
+ title ? createElement("h1", null, title) : null,
77
+ actions ?? null
78
+ ) : null,
79
+ children
80
+ ),
81
+ breadcrumb: ({ items }) => createElement(
82
+ "nav",
83
+ { "aria-label": "breadcrumb" },
84
+ items.map(
85
+ (item, i) => createElement(
86
+ "span",
87
+ { key: i },
88
+ i > 0 ? " / " : null,
89
+ item.to ? createElement("a", { href: item.to }, item.label) : item.label
90
+ )
91
+ )
92
+ ),
93
+ // Feedback
94
+ toast: ({ children }) => createElement("div", null, children),
95
+ alert: ({ children, color }) => createElement(
96
+ "div",
97
+ {
98
+ role: "alert",
99
+ style: {
100
+ padding: "8px 12px",
101
+ borderRadius: "4px",
102
+ backgroundColor: color === "danger" ? "#fee" : color === "success" ? "#efe" : color === "warning" ? "#ffe" : "#f5f5f5"
103
+ }
104
+ },
105
+ children
106
+ ),
107
+ // File
108
+ dropZone: ({ children, isDragOver, onClick, onDrop, onDragOver, onDragLeave }) => createElement(
109
+ "div",
110
+ {
111
+ onClick,
112
+ onDrop: (e) => {
113
+ e.preventDefault();
114
+ onDrop(e.dataTransfer.files);
115
+ },
116
+ onDragOver: (e) => {
117
+ e.preventDefault();
118
+ onDragOver(e);
119
+ },
120
+ onDragLeave,
121
+ style: {
122
+ border: `2px dashed ${isDragOver ? "#4caf50" : "#ccc"}`,
123
+ borderRadius: "8px",
124
+ padding: "32px",
125
+ textAlign: "center",
126
+ cursor: "pointer"
127
+ }
128
+ },
129
+ children
130
+ )
131
+ };
132
+
133
+ // src/plugin.ts
134
+ var UIPluginContext = createContext(null);
135
+ function createUIPlugin(config) {
136
+ return { components: config.components };
137
+ }
138
+ function UIPluginProvider({
139
+ plugin,
140
+ children
141
+ }) {
142
+ return createElement2(UIPluginContext.Provider, { value: plugin }, children);
143
+ }
144
+ function useUIPlugin() {
145
+ return useContext(UIPluginContext);
146
+ }
147
+ function useComponent(slot) {
148
+ const plugin = useUIPlugin();
149
+ const component = plugin?.components[slot];
150
+ if (component) {
151
+ return component;
152
+ }
153
+ return headlessDefaults[slot];
154
+ }
155
+
156
+ export {
157
+ createUIPlugin,
158
+ UIPluginProvider,
159
+ useUIPlugin,
160
+ useComponent
161
+ };