@cfast/ui 0.0.1 → 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.
Files changed (40) hide show
  1. package/llms.txt +159 -0
  2. package/package.json +26 -18
  3. package/LICENSE +0 -21
  4. package/dist/chunk-755IRYDN.js +0 -941
  5. package/dist/chunk-7SNK37GF.js +0 -418
  6. package/dist/chunk-ASMYTWTR.js +0 -356
  7. package/dist/chunk-B2XXH5V4.js +0 -66
  8. package/dist/chunk-BQMXYYEV.js +0 -348
  9. package/dist/chunk-DTKBXCTU.js +0 -211
  10. package/dist/chunk-EYIBATYR.js +0 -33
  11. package/dist/chunk-FPZAQ2YQ.js +0 -474
  12. package/dist/chunk-G2OU4BYC.js +0 -205
  13. package/dist/chunk-JUNLQJ6H.js +0 -1013
  14. package/dist/chunk-NRGMW3JA.js +0 -906
  15. package/dist/chunk-Q6FPL2OJ.js +0 -1086
  16. package/dist/chunk-QHWAGKNW.js +0 -456
  17. package/dist/chunk-QZT62CGJ.js +0 -924
  18. package/dist/chunk-RESL4IJJ.js +0 -112
  19. package/dist/chunk-UDCWQUTR.js +0 -221
  20. package/dist/chunk-UE7PZOIJ.js +0 -11
  21. package/dist/chunk-UTZTHGNE.js +0 -84
  22. package/dist/chunk-UVRXMOX5.js +0 -439
  23. package/dist/chunk-XFD3N2D4.js +0 -161
  24. package/dist/client-CXIHCQtA.d.ts +0 -274
  25. package/dist/permission-gate-apt9T9Mu.d.ts +0 -1256
  26. package/dist/types-1bAiH2uK.d.ts +0 -392
  27. package/dist/types-BX6u5sAd.d.ts +0 -403
  28. package/dist/types-BpdY7w5l.d.ts +0 -403
  29. package/dist/types-BrepeVp8.d.ts +0 -403
  30. package/dist/types-BvAqMZhn.d.ts +0 -403
  31. package/dist/types-C74nSscq.d.ts +0 -403
  32. package/dist/types-DD1Cpx8F.d.ts +0 -403
  33. package/dist/types-DHUhQwJn.d.ts +0 -403
  34. package/dist/types-DZSJNt_M.d.ts +0 -392
  35. package/dist/types-DaaJiIjW.d.ts +0 -391
  36. package/dist/types-LUpWJwps.d.ts +0 -403
  37. package/dist/types-a7zVU6WE.d.ts +0 -394
  38. package/dist/types-biJTHMcH.d.ts +0 -403
  39. package/dist/types-ow_qSEYJ.d.ts +0 -392
  40. package/dist/types-wnLasZaB.d.ts +0 -1234
@@ -1,348 +0,0 @@
1
- import {
2
- useActionStatus,
3
- useToast
4
- } from "./chunk-B2XXH5V4.js";
5
-
6
- // src/plugin.ts
7
- import { createContext, useContext, createElement as createElement2 } from "react";
8
-
9
- // src/headless-defaults.ts
10
- import { createElement } from "react";
11
- var headlessDefaults = {
12
- // Actions
13
- button: ({ children, onClick, disabled, loading, type }) => createElement(
14
- "button",
15
- { onClick, disabled: disabled || loading, type: type ?? "button" },
16
- loading ? "Loading..." : children
17
- ),
18
- tooltip: ({ children, title }) => createElement("span", { title }, children),
19
- confirmDialog: ({ open, onClose, onConfirm, title, description, confirmLabel, cancelLabel }) => open ? createElement(
20
- "dialog",
21
- { open: true },
22
- createElement("p", null, createElement("strong", null, title)),
23
- description ? createElement("p", null, description) : null,
24
- createElement(
25
- "div",
26
- null,
27
- createElement("button", { onClick: onClose }, cancelLabel ?? "Cancel"),
28
- createElement("button", { onClick: onConfirm }, confirmLabel ?? "Confirm")
29
- )
30
- ) : null,
31
- // Data display
32
- table: ({ children }) => createElement("table", null, children),
33
- tableHead: ({ children }) => createElement("thead", null, children),
34
- tableBody: ({ children }) => createElement("tbody", null, children),
35
- tableRow: ({ children, onClick }) => createElement("tr", { onClick }, children),
36
- tableCell: ({ children, header, sortable, sortDirection, onSort }) => createElement(
37
- header ? "th" : "td",
38
- {
39
- onClick: sortable ? onSort : void 0,
40
- style: sortable ? { cursor: "pointer" } : void 0
41
- },
42
- children,
43
- sortable && sortDirection ? sortDirection === "asc" ? " \u2191" : " \u2193" : null
44
- ),
45
- chip: ({ children, size }) => createElement(
46
- "span",
47
- {
48
- style: {
49
- display: "inline-block",
50
- padding: size === "sm" ? "1px 6px" : "2px 8px",
51
- borderRadius: "12px",
52
- fontSize: size === "sm" ? "12px" : "14px",
53
- backgroundColor: "#eee"
54
- }
55
- },
56
- children
57
- ),
58
- // Layout
59
- appShell: ({ children, sidebar, header }) => createElement(
60
- "div",
61
- { style: { display: "flex", minHeight: "100vh" } },
62
- sidebar ? createElement("nav", null, sidebar) : null,
63
- createElement(
64
- "div",
65
- { style: { flex: 1 } },
66
- header ?? null,
67
- createElement("main", null, children)
68
- )
69
- ),
70
- sidebar: ({ children }) => createElement(
71
- "aside",
72
- { style: { width: "240px", borderRight: "1px solid #ddd" } },
73
- children
74
- ),
75
- pageContainer: ({ children, title, actions }) => createElement(
76
- "div",
77
- null,
78
- title || actions ? createElement(
79
- "div",
80
- { style: { display: "flex", justifyContent: "space-between", alignItems: "center" } },
81
- title ? createElement("h1", null, title) : null,
82
- actions ?? null
83
- ) : null,
84
- children
85
- ),
86
- breadcrumb: ({ items }) => createElement(
87
- "nav",
88
- { "aria-label": "breadcrumb" },
89
- items.map(
90
- (item, i) => createElement(
91
- "span",
92
- { key: i },
93
- i > 0 ? " / " : null,
94
- item.to ? createElement("a", { href: item.to }, item.label) : item.label
95
- )
96
- )
97
- ),
98
- // Feedback
99
- toast: ({ children }) => createElement("div", null, children),
100
- alert: ({ children, color }) => createElement(
101
- "div",
102
- {
103
- role: "alert",
104
- style: {
105
- padding: "8px 12px",
106
- borderRadius: "4px",
107
- backgroundColor: color === "danger" ? "#fee" : color === "success" ? "#efe" : color === "warning" ? "#ffe" : "#f5f5f5"
108
- }
109
- },
110
- children
111
- ),
112
- // File
113
- dropZone: ({ children, isDragOver, onClick, onDrop, onDragOver, onDragLeave }) => createElement(
114
- "div",
115
- {
116
- onClick,
117
- onDrop: (e) => {
118
- e.preventDefault();
119
- onDrop(e.dataTransfer.files);
120
- },
121
- onDragOver: (e) => {
122
- e.preventDefault();
123
- onDragOver(e);
124
- },
125
- onDragLeave,
126
- style: {
127
- border: `2px dashed ${isDragOver ? "#4caf50" : "#ccc"}`,
128
- borderRadius: "8px",
129
- padding: "32px",
130
- textAlign: "center",
131
- cursor: "pointer"
132
- }
133
- },
134
- children
135
- )
136
- };
137
-
138
- // src/plugin.ts
139
- var UIPluginContext = createContext(null);
140
- function createUIPlugin(config) {
141
- return { components: config.components };
142
- }
143
- function UIPluginProvider({
144
- plugin,
145
- children
146
- }) {
147
- return createElement2(UIPluginContext.Provider, { value: plugin }, children);
148
- }
149
- function useUIPlugin() {
150
- return useContext(UIPluginContext);
151
- }
152
- function useComponent(slot) {
153
- const plugin = useUIPlugin();
154
- const component = plugin?.components[slot];
155
- if (component) {
156
- return component;
157
- }
158
- return headlessDefaults[slot];
159
- }
160
-
161
- // src/hooks/use-confirm.ts
162
- import { createContext as createContext2, useContext as useContext2, useCallback } from "react";
163
- var ConfirmContext = createContext2(null);
164
- function useConfirm() {
165
- const ctx = useContext2(ConfirmContext);
166
- if (!ctx) {
167
- throw new Error("useConfirm must be used within a <ConfirmProvider>");
168
- }
169
- return useCallback(
170
- (options) => ctx.confirm(options),
171
- [ctx]
172
- );
173
- }
174
-
175
- // src/hooks/use-action-toast.ts
176
- import { useEffect, useRef } from "react";
177
- import { useActions } from "@cfast/actions/client";
178
- function useActionToast(descriptor, config) {
179
- const actions = useActions(descriptor);
180
- const toast = useToast();
181
- const prevDataRef = useRef({});
182
- useEffect(() => {
183
- for (const [name, cfg] of Object.entries(config)) {
184
- const actionFn = actions[name];
185
- if (!actionFn) continue;
186
- const result = actionFn();
187
- const prevData = prevDataRef.current[name];
188
- if (result.data !== void 0 && result.data !== prevData) {
189
- prevDataRef.current[name] = result.data;
190
- if (cfg.success) {
191
- toast.success(cfg.success);
192
- }
193
- }
194
- if (result.error !== void 0 && result.error !== prevData) {
195
- prevDataRef.current[name] = result.error;
196
- if (cfg.error) {
197
- toast.error(cfg.error);
198
- }
199
- }
200
- }
201
- });
202
- }
203
-
204
- // src/components/permission-gate.tsx
205
- import { createElement as createElement3, Fragment } from "react";
206
- function PermissionGate({
207
- action,
208
- actionName,
209
- input,
210
- children,
211
- fallback
212
- }) {
213
- const status = useActionStatus(action, actionName, input);
214
- if (status.invisible) {
215
- return null;
216
- }
217
- if (!status.permitted) {
218
- return fallback ? createElement3(Fragment, null, fallback) : null;
219
- }
220
- return createElement3(Fragment, null, children);
221
- }
222
-
223
- // src/components/action-button.tsx
224
- import { createElement as createElement4 } from "react";
225
- function ActionButton({
226
- action,
227
- actionName,
228
- input,
229
- children,
230
- whenForbidden = "disable",
231
- confirmation: _confirmation,
232
- variant,
233
- color,
234
- size,
235
- startDecorator
236
- }) {
237
- const status = useActionStatus(action, actionName, input);
238
- const Button = useComponent("button");
239
- if (status.invisible) {
240
- return null;
241
- }
242
- if (!status.permitted && whenForbidden === "hide") {
243
- return null;
244
- }
245
- const disabled = !status.permitted && whenForbidden === "disable";
246
- return createElement4(Button, {
247
- children,
248
- onClick: () => status.submit(),
249
- disabled,
250
- loading: status.pending,
251
- variant,
252
- color,
253
- size,
254
- startDecorator
255
- });
256
- }
257
-
258
- // src/components/confirm-provider.tsx
259
- import { createElement as createElement5, useState, useCallback as useCallback2, useRef as useRef2 } from "react";
260
- function ConfirmProvider({ children }) {
261
- const [state, setState] = useState(null);
262
- const ConfirmDialog = useComponent("confirmDialog");
263
- const resolveRef = useRef2(null);
264
- const confirm = useCallback2((options) => {
265
- return new Promise((resolve) => {
266
- resolveRef.current = resolve;
267
- setState({ ...options, resolve });
268
- });
269
- }, []);
270
- const handleClose = useCallback2(() => {
271
- resolveRef.current?.(false);
272
- resolveRef.current = null;
273
- setState(null);
274
- }, []);
275
- const handleConfirm = useCallback2(() => {
276
- resolveRef.current?.(true);
277
- resolveRef.current = null;
278
- setState(null);
279
- }, []);
280
- return createElement5(
281
- ConfirmContext.Provider,
282
- { value: { confirm } },
283
- children,
284
- state ? createElement5(ConfirmDialog, {
285
- open: true,
286
- onClose: handleClose,
287
- onConfirm: handleConfirm,
288
- title: state.title,
289
- description: state.description,
290
- confirmLabel: state.confirmLabel,
291
- cancelLabel: state.cancelLabel,
292
- variant: state.variant
293
- }) : null
294
- );
295
- }
296
-
297
- // src/components/form-status.tsx
298
- import { createElement as createElement6 } from "react";
299
- function FormStatus({ data }) {
300
- const Alert = useComponent("alert");
301
- if (!data) return null;
302
- const elements = [];
303
- if (data.success) {
304
- elements.push(
305
- createElement6(Alert, { key: "success", color: "success", children: data.success })
306
- );
307
- }
308
- if (data.error) {
309
- elements.push(
310
- createElement6(Alert, { key: "error", color: "danger", children: data.error })
311
- );
312
- }
313
- if (data.fieldErrors) {
314
- const errorMessages = Object.entries(data.fieldErrors).flatMap(
315
- ([field, errors]) => errors.map((err) => `${field}: ${err}`)
316
- );
317
- if (errorMessages.length > 0) {
318
- elements.push(
319
- createElement6(Alert, {
320
- key: "field-errors",
321
- color: "danger",
322
- children: createElement6(
323
- "ul",
324
- { style: { margin: 0, paddingLeft: "16px" } },
325
- ...errorMessages.map(
326
- (msg, i) => createElement6("li", { key: i }, msg)
327
- )
328
- )
329
- })
330
- );
331
- }
332
- }
333
- if (elements.length === 0) return null;
334
- return createElement6("div", { style: { display: "flex", flexDirection: "column", gap: "8px" } }, ...elements);
335
- }
336
-
337
- export {
338
- createUIPlugin,
339
- UIPluginProvider,
340
- useUIPlugin,
341
- useComponent,
342
- useConfirm,
343
- useActionToast,
344
- PermissionGate,
345
- ActionButton,
346
- ConfirmProvider,
347
- FormStatus
348
- };
@@ -1,211 +0,0 @@
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
- // src/components/permission-gate.tsx
157
- import { createElement as createElement3, Fragment } from "react";
158
- function PermissionGate({
159
- action,
160
- children,
161
- fallback
162
- }) {
163
- if (action.invisible) {
164
- return null;
165
- }
166
- if (!action.permitted) {
167
- return fallback ? createElement3(Fragment, null, fallback) : null;
168
- }
169
- return createElement3(Fragment, null, children);
170
- }
171
-
172
- // src/components/action-button.tsx
173
- import { createElement as createElement4 } from "react";
174
- function ActionButton({
175
- action,
176
- children,
177
- whenForbidden = "disable",
178
- confirmation: _confirmation,
179
- variant,
180
- color,
181
- size,
182
- startDecorator
183
- }) {
184
- const Button = useComponent("button");
185
- if (action.invisible) {
186
- return null;
187
- }
188
- if (!action.permitted && whenForbidden === "hide") {
189
- return null;
190
- }
191
- const disabled = !action.permitted && whenForbidden === "disable";
192
- return createElement4(Button, {
193
- children,
194
- onClick: () => action.submit(),
195
- disabled,
196
- loading: action.pending,
197
- variant,
198
- color,
199
- size,
200
- startDecorator
201
- });
202
- }
203
-
204
- export {
205
- createUIPlugin,
206
- UIPluginProvider,
207
- useUIPlugin,
208
- useComponent,
209
- PermissionGate,
210
- ActionButton
211
- };
@@ -1,33 +0,0 @@
1
- // src/hooks/use-action-status.ts
2
- import { useActions } from "@cfast/actions/client";
3
- function useActionStatus(descriptor, actionName, input) {
4
- const actions = useActions(descriptor);
5
- const name = actionName ?? descriptor.actionNames[0];
6
- const actionFn = actions[name];
7
- if (!actionFn) {
8
- return {
9
- permitted: false,
10
- invisible: true,
11
- reason: `Action "${name}" not found in descriptor`,
12
- submit: () => {
13
- },
14
- pending: false,
15
- data: void 0,
16
- error: void 0
17
- };
18
- }
19
- const result = actionFn(input);
20
- return {
21
- permitted: result.permitted,
22
- invisible: result.invisible,
23
- reason: result.reason,
24
- submit: result.submit,
25
- pending: result.pending,
26
- data: result.data,
27
- error: result.error
28
- };
29
- }
30
-
31
- export {
32
- useActionStatus
33
- };