@opensaas/stack-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.
Files changed (203) hide show
  1. package/.turbo/turbo-build.log +8 -0
  2. package/README.md +286 -0
  3. package/dist/components/AdminUI.d.ts +24 -0
  4. package/dist/components/AdminUI.d.ts.map +1 -0
  5. package/dist/components/AdminUI.js +48 -0
  6. package/dist/components/ConfirmDialog.d.ts +16 -0
  7. package/dist/components/ConfirmDialog.d.ts.map +1 -0
  8. package/dist/components/ConfirmDialog.js +11 -0
  9. package/dist/components/Dashboard.d.ts +12 -0
  10. package/dist/components/Dashboard.d.ts.map +1 -0
  11. package/dist/components/Dashboard.js +30 -0
  12. package/dist/components/ItemForm.d.ts +17 -0
  13. package/dist/components/ItemForm.d.ts.map +1 -0
  14. package/dist/components/ItemForm.js +97 -0
  15. package/dist/components/ItemFormClient.d.ts +22 -0
  16. package/dist/components/ItemFormClient.d.ts.map +1 -0
  17. package/dist/components/ItemFormClient.js +127 -0
  18. package/dist/components/ListView.d.ts +17 -0
  19. package/dist/components/ListView.d.ts.map +1 -0
  20. package/dist/components/ListView.js +76 -0
  21. package/dist/components/ListViewClient.d.ts +19 -0
  22. package/dist/components/ListViewClient.d.ts.map +1 -0
  23. package/dist/components/ListViewClient.js +108 -0
  24. package/dist/components/LoadingSpinner.d.ts +10 -0
  25. package/dist/components/LoadingSpinner.d.ts.map +1 -0
  26. package/dist/components/LoadingSpinner.js +14 -0
  27. package/dist/components/Navigation.d.ts +13 -0
  28. package/dist/components/Navigation.d.ts.map +1 -0
  29. package/dist/components/Navigation.js +20 -0
  30. package/dist/components/SkeletonLoader.d.ts +22 -0
  31. package/dist/components/SkeletonLoader.d.ts.map +1 -0
  32. package/dist/components/SkeletonLoader.js +25 -0
  33. package/dist/components/fields/CheckboxField.d.ts +11 -0
  34. package/dist/components/fields/CheckboxField.d.ts.map +1 -0
  35. package/dist/components/fields/CheckboxField.js +10 -0
  36. package/dist/components/fields/ComboboxField.d.ts +18 -0
  37. package/dist/components/fields/ComboboxField.d.ts.map +1 -0
  38. package/dist/components/fields/ComboboxField.js +32 -0
  39. package/dist/components/fields/FieldRenderer.d.ts +22 -0
  40. package/dist/components/fields/FieldRenderer.d.ts.map +1 -0
  41. package/dist/components/fields/FieldRenderer.js +81 -0
  42. package/dist/components/fields/IntegerField.d.ts +15 -0
  43. package/dist/components/fields/IntegerField.d.ts.map +1 -0
  44. package/dist/components/fields/IntegerField.js +14 -0
  45. package/dist/components/fields/PasswordField.d.ts +18 -0
  46. package/dist/components/fields/PasswordField.d.ts.map +1 -0
  47. package/dist/components/fields/PasswordField.js +42 -0
  48. package/dist/components/fields/RelationshipField.d.ts +20 -0
  49. package/dist/components/fields/RelationshipField.d.ts.map +1 -0
  50. package/dist/components/fields/RelationshipField.js +11 -0
  51. package/dist/components/fields/RelationshipManager.d.ts +19 -0
  52. package/dist/components/fields/RelationshipManager.d.ts.map +1 -0
  53. package/dist/components/fields/RelationshipManager.js +37 -0
  54. package/dist/components/fields/SelectField.d.ts +16 -0
  55. package/dist/components/fields/SelectField.d.ts.map +1 -0
  56. package/dist/components/fields/SelectField.js +11 -0
  57. package/dist/components/fields/TextField.d.ts +13 -0
  58. package/dist/components/fields/TextField.d.ts.map +1 -0
  59. package/dist/components/fields/TextField.js +11 -0
  60. package/dist/components/fields/TimestampField.d.ts +12 -0
  61. package/dist/components/fields/TimestampField.d.ts.map +1 -0
  62. package/dist/components/fields/TimestampField.js +12 -0
  63. package/dist/components/fields/index.d.ts +23 -0
  64. package/dist/components/fields/index.d.ts.map +1 -0
  65. package/dist/components/fields/index.js +13 -0
  66. package/dist/components/fields/registry.d.ts +43 -0
  67. package/dist/components/fields/registry.d.ts.map +1 -0
  68. package/dist/components/fields/registry.js +42 -0
  69. package/dist/components/standalone/DeleteButton.d.ts +35 -0
  70. package/dist/components/standalone/DeleteButton.d.ts.map +1 -0
  71. package/dist/components/standalone/DeleteButton.js +46 -0
  72. package/dist/components/standalone/ItemCreateForm.d.ts +34 -0
  73. package/dist/components/standalone/ItemCreateForm.d.ts.map +1 -0
  74. package/dist/components/standalone/ItemCreateForm.js +91 -0
  75. package/dist/components/standalone/ItemEditForm.d.ts +37 -0
  76. package/dist/components/standalone/ItemEditForm.d.ts.map +1 -0
  77. package/dist/components/standalone/ItemEditForm.js +112 -0
  78. package/dist/components/standalone/ListTable.d.ts +33 -0
  79. package/dist/components/standalone/ListTable.d.ts.map +1 -0
  80. package/dist/components/standalone/ListTable.js +94 -0
  81. package/dist/components/standalone/SearchBar.d.ts +29 -0
  82. package/dist/components/standalone/SearchBar.d.ts.map +1 -0
  83. package/dist/components/standalone/SearchBar.js +43 -0
  84. package/dist/components/standalone/index.d.ts +11 -0
  85. package/dist/components/standalone/index.d.ts.map +1 -0
  86. package/dist/components/standalone/index.js +6 -0
  87. package/dist/index.d.ts +27 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +19 -0
  90. package/dist/lib/serializeFieldConfig.d.ts +43 -0
  91. package/dist/lib/serializeFieldConfig.d.ts.map +1 -0
  92. package/dist/lib/serializeFieldConfig.js +48 -0
  93. package/dist/lib/theme.d.ts +17 -0
  94. package/dist/lib/theme.d.ts.map +1 -0
  95. package/dist/lib/theme.js +192 -0
  96. package/dist/lib/utils.d.ts +18 -0
  97. package/dist/lib/utils.d.ts.map +1 -0
  98. package/dist/lib/utils.js +76 -0
  99. package/dist/primitives/button.d.ts +12 -0
  100. package/dist/primitives/button.d.ts.map +1 -0
  101. package/dist/primitives/button.js +33 -0
  102. package/dist/primitives/calendar.d.ts +9 -0
  103. package/dist/primitives/calendar.d.ts.map +1 -0
  104. package/dist/primitives/calendar.js +48 -0
  105. package/dist/primitives/card.d.ts +9 -0
  106. package/dist/primitives/card.d.ts.map +1 -0
  107. package/dist/primitives/card.js +16 -0
  108. package/dist/primitives/checkbox.d.ts +5 -0
  109. package/dist/primitives/checkbox.d.ts.map +1 -0
  110. package/dist/primitives/checkbox.js +7 -0
  111. package/dist/primitives/combobox.d.ts +14 -0
  112. package/dist/primitives/combobox.d.ts.map +1 -0
  113. package/dist/primitives/combobox.js +20 -0
  114. package/dist/primitives/datetime-picker.d.ts +9 -0
  115. package/dist/primitives/datetime-picker.d.ts.map +1 -0
  116. package/dist/primitives/datetime-picker.js +42 -0
  117. package/dist/primitives/dialog.d.ts +20 -0
  118. package/dist/primitives/dialog.d.ts.map +1 -0
  119. package/dist/primitives/dialog.js +21 -0
  120. package/dist/primitives/index.d.ts +14 -0
  121. package/dist/primitives/index.d.ts.map +1 -0
  122. package/dist/primitives/index.js +14 -0
  123. package/dist/primitives/input.d.ts +5 -0
  124. package/dist/primitives/input.d.ts.map +1 -0
  125. package/dist/primitives/input.js +8 -0
  126. package/dist/primitives/label.d.ts +6 -0
  127. package/dist/primitives/label.d.ts.map +1 -0
  128. package/dist/primitives/label.js +9 -0
  129. package/dist/primitives/popover.d.ts +7 -0
  130. package/dist/primitives/popover.d.ts.map +1 -0
  131. package/dist/primitives/popover.js +10 -0
  132. package/dist/primitives/select.d.ts +14 -0
  133. package/dist/primitives/select.d.ts.map +1 -0
  134. package/dist/primitives/select.js +24 -0
  135. package/dist/primitives/table.d.ts +11 -0
  136. package/dist/primitives/table.d.ts.map +1 -0
  137. package/dist/primitives/table.js +20 -0
  138. package/dist/primitives/time-picker.d.ts +8 -0
  139. package/dist/primitives/time-picker.d.ts.map +1 -0
  140. package/dist/primitives/time-picker.js +27 -0
  141. package/dist/server/index.d.ts +2 -0
  142. package/dist/server/index.d.ts.map +1 -0
  143. package/dist/server/index.js +2 -0
  144. package/dist/server/types.d.ts +15 -0
  145. package/dist/server/types.d.ts.map +1 -0
  146. package/dist/server/types.js +1 -0
  147. package/dist/styles/globals.css +1896 -0
  148. package/package.json +91 -0
  149. package/postcss.config.cjs +5 -0
  150. package/src/components/AdminUI.tsx +112 -0
  151. package/src/components/ConfirmDialog.tsx +56 -0
  152. package/src/components/Dashboard.tsx +134 -0
  153. package/src/components/ItemForm.tsx +195 -0
  154. package/src/components/ItemFormClient.tsx +237 -0
  155. package/src/components/ListView.tsx +153 -0
  156. package/src/components/ListViewClient.tsx +282 -0
  157. package/src/components/LoadingSpinner.tsx +32 -0
  158. package/src/components/Navigation.tsx +117 -0
  159. package/src/components/SkeletonLoader.tsx +82 -0
  160. package/src/components/fields/CheckboxField.tsx +54 -0
  161. package/src/components/fields/ComboboxField.tsx +127 -0
  162. package/src/components/fields/FieldRenderer.tsx +132 -0
  163. package/src/components/fields/IntegerField.tsx +68 -0
  164. package/src/components/fields/PasswordField.tsx +159 -0
  165. package/src/components/fields/RelationshipField.tsx +71 -0
  166. package/src/components/fields/RelationshipManager.tsx +189 -0
  167. package/src/components/fields/SelectField.tsx +71 -0
  168. package/src/components/fields/TextField.tsx +59 -0
  169. package/src/components/fields/TimestampField.tsx +49 -0
  170. package/src/components/fields/index.ts +27 -0
  171. package/src/components/fields/registry.ts +72 -0
  172. package/src/components/standalone/DeleteButton.tsx +114 -0
  173. package/src/components/standalone/ItemCreateForm.tsx +161 -0
  174. package/src/components/standalone/ItemEditForm.tsx +193 -0
  175. package/src/components/standalone/ListTable.tsx +211 -0
  176. package/src/components/standalone/SearchBar.tsx +86 -0
  177. package/src/components/standalone/index.ts +13 -0
  178. package/src/index.ts +74 -0
  179. package/src/lib/serializeFieldConfig.ts +88 -0
  180. package/src/lib/theme.ts +202 -0
  181. package/src/lib/utils.ts +81 -0
  182. package/src/primitives/button.tsx +49 -0
  183. package/src/primitives/calendar.tsx +160 -0
  184. package/src/primitives/card.tsx +58 -0
  185. package/src/primitives/checkbox.tsx +27 -0
  186. package/src/primitives/combobox.tsx +159 -0
  187. package/src/primitives/datetime-picker.tsx +130 -0
  188. package/src/primitives/dialog.tsx +108 -0
  189. package/src/primitives/index.ts +54 -0
  190. package/src/primitives/input.tsx +24 -0
  191. package/src/primitives/label.tsx +19 -0
  192. package/src/primitives/popover.tsx +31 -0
  193. package/src/primitives/select.tsx +158 -0
  194. package/src/primitives/table.tsx +91 -0
  195. package/src/primitives/time-picker.tsx +65 -0
  196. package/src/server/index.ts +3 -0
  197. package/src/server/types.ts +15 -0
  198. package/src/styles/globals.css +123 -0
  199. package/tailwind.config.ts +3 -0
  200. package/tests/components/TextField.test.tsx +94 -0
  201. package/tests/setup.ts +11 -0
  202. package/tsconfig.json +26 -0
  203. package/vitest.config.ts +22 -0
@@ -0,0 +1,34 @@
1
+ import type { FieldConfig } from '@opensaas/stack-core';
2
+ export interface ItemCreateFormProps<TData = Record<string, unknown>> {
3
+ fields: Record<string, FieldConfig>;
4
+ onSubmit: (data: TData) => Promise<{
5
+ success: boolean;
6
+ error?: string;
7
+ }>;
8
+ onCancel?: () => void;
9
+ relationshipData?: Record<string, Array<{
10
+ id: string;
11
+ label: string;
12
+ }>>;
13
+ submitLabel?: string;
14
+ cancelLabel?: string;
15
+ className?: string;
16
+ }
17
+ /**
18
+ * Standalone form component for creating items
19
+ * Can be embedded in any custom page
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * <ItemCreateForm
24
+ * fields={config.lists.Post.fields}
25
+ * onSubmit={async (data) => {
26
+ * const result = await createPost(data);
27
+ * return { success: !!result };
28
+ * }}
29
+ * onCancel={() => router.back()}
30
+ * />
31
+ * ```
32
+ */
33
+ export declare function ItemCreateForm<TData = Record<string, unknown>>({ fields, onSubmit, onCancel, relationshipData, submitLabel, cancelLabel, className, }: ItemCreateFormProps<TData>): import("react/jsx-runtime").JSX.Element;
34
+ //# sourceMappingURL=ItemCreateForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemCreateForm.d.ts","sourceRoot":"","sources":["../../../src/components/standalone/ItemCreateForm.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGvD,MAAM,WAAW,mBAAmB,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACnC,QAAQ,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;IACvE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC9D,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,gBAAqB,EACrB,WAAsB,EACtB,WAAsB,EACtB,SAAS,GACV,EAAE,mBAAmB,CAAC,KAAK,CAAC,2CAoH5B"}
@@ -0,0 +1,91 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState, useMemo } from 'react';
4
+ import { FieldRenderer } from '../fields/FieldRenderer.js';
5
+ import { LoadingSpinner } from '../LoadingSpinner.js';
6
+ import { Button } from '../../primitives/button.js';
7
+ import { serializeFieldConfigs } from '../../lib/serializeFieldConfig.js';
8
+ /**
9
+ * Standalone form component for creating items
10
+ * Can be embedded in any custom page
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <ItemCreateForm
15
+ * fields={config.lists.Post.fields}
16
+ * onSubmit={async (data) => {
17
+ * const result = await createPost(data);
18
+ * return { success: !!result };
19
+ * }}
20
+ * onCancel={() => router.back()}
21
+ * />
22
+ * ```
23
+ */
24
+ export function ItemCreateForm({ fields, onSubmit, onCancel, relationshipData = {}, submitLabel = 'Create', cancelLabel = 'Cancel', className, }) {
25
+ // Serialize field configs to remove non-serializable properties
26
+ const serializedFields = useMemo(() => serializeFieldConfigs(fields), [fields]);
27
+ const [isPending, setIsPending] = useState(false);
28
+ const [formData, setFormData] = useState({});
29
+ const [errors, setErrors] = useState({});
30
+ const [generalError, setGeneralError] = useState(null);
31
+ const handleFieldChange = (fieldName, value) => {
32
+ setFormData((prev) => ({ ...prev, [fieldName]: value }));
33
+ // Clear error for this field when user starts typing
34
+ if (errors[fieldName]) {
35
+ setErrors((prev) => {
36
+ const newErrors = { ...prev };
37
+ delete newErrors[fieldName];
38
+ return newErrors;
39
+ });
40
+ }
41
+ };
42
+ const handleSubmit = async (e) => {
43
+ e.preventDefault();
44
+ setErrors({});
45
+ setGeneralError(null);
46
+ setIsPending(true);
47
+ try {
48
+ // Transform relationship fields to Prisma format
49
+ const transformedData = {};
50
+ for (const [fieldName, value] of Object.entries(formData)) {
51
+ const fieldConfig = serializedFields[fieldName];
52
+ // Transform relationship fields
53
+ if (fieldConfig?.type === 'relationship') {
54
+ if (fieldConfig.many) {
55
+ // Many relationship: use connect format
56
+ if (Array.isArray(value) && value.length > 0) {
57
+ transformedData[fieldName] = {
58
+ connect: value.map((id) => ({ id })),
59
+ };
60
+ }
61
+ }
62
+ else {
63
+ // Single relationship: use connect format
64
+ if (value) {
65
+ transformedData[fieldName] = {
66
+ connect: { id: value },
67
+ };
68
+ }
69
+ }
70
+ }
71
+ else {
72
+ // Non-relationship field: pass through
73
+ transformedData[fieldName] = value;
74
+ }
75
+ }
76
+ const result = await onSubmit(transformedData);
77
+ if (!result.success) {
78
+ setGeneralError(result.error || 'Failed to create item');
79
+ }
80
+ }
81
+ catch (error) {
82
+ setGeneralError(error.message || 'Failed to create item');
83
+ }
84
+ finally {
85
+ setIsPending(false);
86
+ }
87
+ };
88
+ // Filter out system fields
89
+ const editableFields = Object.entries(serializedFields).filter(([key]) => !['id', 'createdAt', 'updatedAt'].includes(key));
90
+ return (_jsxs("form", { onSubmit: handleSubmit, className: className, children: [generalError && (_jsx("div", { className: "bg-destructive/10 border border-destructive text-destructive rounded-lg p-4 mb-6", children: _jsx("p", { className: "text-sm font-medium", children: generalError }) })), _jsx("div", { className: "space-y-6", children: editableFields.map(([fieldName, fieldConfig]) => (_jsx(FieldRenderer, { fieldName: fieldName, fieldConfig: fieldConfig, value: formData[fieldName], onChange: (value) => handleFieldChange(fieldName, value), error: errors[fieldName], disabled: isPending, mode: "edit", relationshipItems: relationshipData[fieldName] || [], relationshipLoading: false }, fieldName))) }), _jsxs("div", { className: "flex gap-3 pt-6 mt-6 border-t border-border", children: [_jsxs(Button, { type: "submit", disabled: isPending, className: "gap-2", children: [isPending && (_jsx(LoadingSpinner, { size: "sm", className: "border-primary-foreground border-t-transparent" })), isPending ? 'Creating...' : submitLabel] }), onCancel && (_jsx(Button, { type: "button", variant: "secondary", onClick: onCancel, disabled: isPending, children: cancelLabel }))] })] }));
91
+ }
@@ -0,0 +1,37 @@
1
+ import type { FieldConfig } from '@opensaas/stack-core';
2
+ export interface ItemEditFormProps<TData = Record<string, unknown>> {
3
+ fields: Record<string, FieldConfig>;
4
+ initialData: TData;
5
+ onSubmit: (data: TData) => Promise<{
6
+ success: boolean;
7
+ error?: string;
8
+ }>;
9
+ onCancel?: () => void;
10
+ relationshipData?: Record<string, Array<{
11
+ id: string;
12
+ label: string;
13
+ }>>;
14
+ submitLabel?: string;
15
+ cancelLabel?: string;
16
+ className?: string;
17
+ basePath?: string;
18
+ }
19
+ /**
20
+ * Standalone form component for editing items
21
+ * Can be embedded in any custom page
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * <ItemEditForm
26
+ * fields={config.lists.Post.fields}
27
+ * initialData={post}
28
+ * onSubmit={async (data) => {
29
+ * const result = await updatePost(postId, data);
30
+ * return { success: !!result };
31
+ * }}
32
+ * onCancel={() => router.back()}
33
+ * />
34
+ * ```
35
+ */
36
+ export declare function ItemEditForm<TData = Record<string, unknown>>({ fields, initialData, onSubmit, onCancel, relationshipData, submitLabel, cancelLabel, className, basePath, }: ItemEditFormProps<TData>): import("react/jsx-runtime").JSX.Element;
37
+ //# sourceMappingURL=ItemEditForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemEditForm.d.ts","sourceRoot":"","sources":["../../../src/components/standalone/ItemEditForm.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGvD,MAAM,WAAW,iBAAiB,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAChE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACnC,WAAW,EAAE,KAAK,CAAA;IAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;IACvE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC5D,MAAM,EACN,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,gBAAqB,EACrB,WAAoB,EACpB,WAAsB,EACtB,SAAS,EACT,QAAmB,GACpB,EAAE,iBAAiB,CAAC,KAAK,CAAC,2CA+I1B"}
@@ -0,0 +1,112 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState, useMemo } from 'react';
4
+ import { FieldRenderer } from '../fields/FieldRenderer.js';
5
+ import { LoadingSpinner } from '../LoadingSpinner.js';
6
+ import { Button } from '../../primitives/button.js';
7
+ import { serializeFieldConfigs } from '../../lib/serializeFieldConfig.js';
8
+ /**
9
+ * Standalone form component for editing items
10
+ * Can be embedded in any custom page
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <ItemEditForm
15
+ * fields={config.lists.Post.fields}
16
+ * initialData={post}
17
+ * onSubmit={async (data) => {
18
+ * const result = await updatePost(postId, data);
19
+ * return { success: !!result };
20
+ * }}
21
+ * onCancel={() => router.back()}
22
+ * />
23
+ * ```
24
+ */
25
+ export function ItemEditForm({ fields, initialData, onSubmit, onCancel, relationshipData = {}, submitLabel = 'Save', cancelLabel = 'Cancel', className, basePath = '/admin', }) {
26
+ // Serialize field configs to remove non-serializable properties
27
+ const serializedFields = useMemo(() => serializeFieldConfigs(fields), [fields]);
28
+ // Apply valueForClientSerialization transformations to initial data
29
+ const transformedInitialData = useMemo(() => {
30
+ const transformed = { ...initialData };
31
+ for (const [fieldName, fieldConfig] of Object.entries(fields)) {
32
+ const fieldConfigAny = fieldConfig;
33
+ if (fieldConfigAny.ui?.valueForClientSerialization &&
34
+ typeof fieldConfigAny.ui.valueForClientSerialization === 'function') {
35
+ const transformer = fieldConfigAny.ui.valueForClientSerialization;
36
+ transformed[fieldName] = transformer({
37
+ value: transformed[fieldName],
38
+ });
39
+ }
40
+ }
41
+ return transformed;
42
+ }, [initialData, fields]);
43
+ const [isPending, setIsPending] = useState(false);
44
+ const [formData, setFormData] = useState(transformedInitialData);
45
+ const [errors, setErrors] = useState({});
46
+ const [generalError, setGeneralError] = useState(null);
47
+ const handleFieldChange = (fieldName, value) => {
48
+ setFormData((prev) => ({ ...prev, [fieldName]: value }));
49
+ // Clear error for this field when user starts typing
50
+ if (errors[fieldName]) {
51
+ setErrors((prev) => {
52
+ const newErrors = { ...prev };
53
+ delete newErrors[fieldName];
54
+ return newErrors;
55
+ });
56
+ }
57
+ };
58
+ const handleSubmit = async (e) => {
59
+ e.preventDefault();
60
+ setErrors({});
61
+ setGeneralError(null);
62
+ setIsPending(true);
63
+ try {
64
+ // Transform relationship fields to Prisma format
65
+ // Filter out password fields with isSet objects (unchanged passwords)
66
+ const transformedData = {};
67
+ for (const [fieldName, value] of Object.entries(formData)) {
68
+ const fieldConfig = serializedFields[fieldName];
69
+ // Skip password fields that have { isSet: boolean } value (not being changed)
70
+ if (typeof value === 'object' && value !== null && 'isSet' in value) {
71
+ continue;
72
+ }
73
+ // Transform relationship fields
74
+ if (fieldConfig?.type === 'relationship') {
75
+ if (fieldConfig.many) {
76
+ // Many relationship: use connect format
77
+ if (Array.isArray(value) && value.length > 0) {
78
+ transformedData[fieldName] = {
79
+ connect: value.map((id) => ({ id })),
80
+ };
81
+ }
82
+ }
83
+ else {
84
+ // Single relationship: use connect format
85
+ if (value) {
86
+ transformedData[fieldName] = {
87
+ connect: { id: value },
88
+ };
89
+ }
90
+ }
91
+ }
92
+ else {
93
+ // Non-relationship field: pass through
94
+ transformedData[fieldName] = value;
95
+ }
96
+ }
97
+ const result = await onSubmit(transformedData);
98
+ if (!result.success) {
99
+ setGeneralError(result.error || 'Failed to update item');
100
+ }
101
+ }
102
+ catch (error) {
103
+ setGeneralError(error.message || 'Failed to update item');
104
+ }
105
+ finally {
106
+ setIsPending(false);
107
+ }
108
+ };
109
+ // Filter out system fields
110
+ const editableFields = Object.entries(serializedFields).filter(([key]) => !['id', 'createdAt', 'updatedAt'].includes(key));
111
+ return (_jsxs("form", { onSubmit: handleSubmit, className: className, children: [generalError && (_jsx("div", { className: "bg-destructive/10 border border-destructive text-destructive rounded-lg p-4 mb-6", children: _jsx("p", { className: "text-sm font-medium", children: generalError }) })), _jsx("div", { className: "space-y-6", children: editableFields.map(([fieldName, fieldConfig]) => (_jsx(FieldRenderer, { fieldName: fieldName, fieldConfig: fieldConfig, value: formData[fieldName], onChange: (value) => handleFieldChange(fieldName, value), error: errors[fieldName], disabled: isPending, mode: "edit", relationshipItems: relationshipData[fieldName] || [], relationshipLoading: false, basePath: basePath }, fieldName))) }), _jsxs("div", { className: "flex gap-3 pt-6 mt-6 border-t border-border", children: [_jsxs(Button, { type: "submit", disabled: isPending, className: "gap-2", children: [isPending && (_jsx(LoadingSpinner, { size: "sm", className: "border-primary-foreground border-t-transparent" })), isPending ? 'Saving...' : submitLabel] }), onCancel && (_jsx(Button, { type: "button", variant: "secondary", onClick: onCancel, disabled: isPending, children: cancelLabel }))] })] }));
112
+ }
@@ -0,0 +1,33 @@
1
+ import * as React from 'react';
2
+ export interface ListTableProps {
3
+ items: Array<Record<string, unknown>>;
4
+ fieldTypes: Record<string, string>;
5
+ relationshipRefs?: Record<string, string>;
6
+ basePath?: string;
7
+ columns?: string[];
8
+ onRowClick?: (item: Record<string, unknown>) => void;
9
+ sortable?: boolean;
10
+ emptyMessage?: string;
11
+ className?: string;
12
+ renderActions?: (item: Record<string, unknown>) => React.ReactNode;
13
+ }
14
+ /**
15
+ * Standalone table component for displaying list data
16
+ * Can be embedded in any custom page
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <ListTable
21
+ * items={posts}
22
+ * fieldTypes={{ title: 'text', status: 'select', publishedAt: 'timestamp', author: 'relationship' }}
23
+ * relationshipRefs={{ author: 'User.posts' }}
24
+ * columns={['title', 'status', 'publishedAt', 'author']}
25
+ * onRowClick={(post) => router.push(`/posts/${post.id}`)}
26
+ * renderActions={(post) => (
27
+ * <Button onClick={() => deletePost(post.id)}>Delete</Button>
28
+ * )}
29
+ * />
30
+ * ```
31
+ */
32
+ export declare function ListTable({ items, fieldTypes, relationshipRefs, basePath, columns, onRowClick, sortable, emptyMessage, className, renderActions, }: ListTableProps): import("react/jsx-runtime").JSX.Element;
33
+ //# sourceMappingURL=ListTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListTable.d.ts","sourceRoot":"","sources":["../../../src/components/standalone/ListTable.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAc9B,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACrC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;CACnE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,UAAU,EACV,gBAAgB,EAChB,QAAmB,EACnB,OAAO,EACP,UAAU,EACV,QAAe,EACf,YAA+B,EAC/B,SAAS,EACT,aAAa,GACd,EAAE,cAAc,2CAyJhB"}
@@ -0,0 +1,94 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ import { useState } from 'react';
5
+ import Link from 'next/link';
6
+ import { formatFieldName, getFieldDisplayValue } from '../../lib/utils.js';
7
+ import { getUrlKey } from '@opensaas/stack-core';
8
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '../../primitives/table.js';
9
+ /**
10
+ * Standalone table component for displaying list data
11
+ * Can be embedded in any custom page
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <ListTable
16
+ * items={posts}
17
+ * fieldTypes={{ title: 'text', status: 'select', publishedAt: 'timestamp', author: 'relationship' }}
18
+ * relationshipRefs={{ author: 'User.posts' }}
19
+ * columns={['title', 'status', 'publishedAt', 'author']}
20
+ * onRowClick={(post) => router.push(`/posts/${post.id}`)}
21
+ * renderActions={(post) => (
22
+ * <Button onClick={() => deletePost(post.id)}>Delete</Button>
23
+ * )}
24
+ * />
25
+ * ```
26
+ */
27
+ export function ListTable({ items, fieldTypes, relationshipRefs, basePath = '/admin', columns, onRowClick, sortable = true, emptyMessage = 'No items found', className, renderActions, }) {
28
+ const [sortBy, setSortBy] = useState(null);
29
+ const [sortOrder, setSortOrder] = useState('asc');
30
+ /**
31
+ * Render a relationship field as a clickable link or links
32
+ */
33
+ const renderRelationshipCell = (value, fieldName) => {
34
+ if (!relationshipRefs) {
35
+ return getFieldDisplayValue(value, 'relationship');
36
+ }
37
+ const ref = relationshipRefs[fieldName];
38
+ if (!ref) {
39
+ return getFieldDisplayValue(value, 'relationship');
40
+ }
41
+ // Parse ref to get related list name
42
+ const [relatedListKey] = ref.split('.');
43
+ const relatedUrlKey = getUrlKey(relatedListKey);
44
+ if (!value || typeof value !== 'object') {
45
+ return _jsx("span", { className: "text-muted-foreground", children: "-" });
46
+ }
47
+ // Handle array of relationships (many: true)
48
+ if (Array.isArray(value)) {
49
+ if (value.length === 0)
50
+ return _jsx("span", { className: "text-muted-foreground", children: "-" });
51
+ return (_jsx("span", { className: "flex flex-wrap gap-1", children: value.map((item, idx) => {
52
+ if (!item || typeof item !== 'object')
53
+ return null;
54
+ const displayValue = getFieldDisplayValue(item, 'relationship');
55
+ const itemId = 'id' in item ? item.id : null;
56
+ const key = itemId || idx;
57
+ return (_jsxs(React.Fragment, { children: [idx > 0 && _jsx("span", { className: "text-muted-foreground", children: ", " }), _jsx(Link, { href: `${basePath}/${relatedUrlKey}/${itemId}`, className: "text-primary hover:underline", onClick: (e) => e.stopPropagation(), children: displayValue })] }, key));
58
+ }) }));
59
+ }
60
+ // Handle single relationship
61
+ const itemId = 'id' in value ? value.id : null;
62
+ const displayValue = getFieldDisplayValue(value, 'relationship');
63
+ return (_jsx(Link, { href: `${basePath}/${relatedUrlKey}/${itemId}`, className: "text-primary hover:underline", onClick: (e) => e.stopPropagation(), children: displayValue }));
64
+ };
65
+ // Determine which columns to show
66
+ const displayColumns = columns ||
67
+ Object.keys(fieldTypes).filter((key) => !['password', 'createdAt', 'updatedAt'].includes(key));
68
+ // Sort items if needed
69
+ const sortedItems = [...items];
70
+ if (sortBy && sortable) {
71
+ sortedItems.sort((a, b) => {
72
+ const aVal = a[sortBy];
73
+ const bVal = b[sortBy];
74
+ if (aVal === bVal)
75
+ return 0;
76
+ const comparison = String(aVal) > String(bVal) ? 1 : -1;
77
+ return sortOrder === 'asc' ? comparison : -comparison;
78
+ });
79
+ }
80
+ const handleSort = (column) => {
81
+ if (!sortable)
82
+ return;
83
+ if (sortBy === column) {
84
+ setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc');
85
+ }
86
+ else {
87
+ setSortBy(column);
88
+ setSortOrder('asc');
89
+ }
90
+ };
91
+ return (_jsx("div", { className: className, children: _jsx("div", { className: "rounded-lg border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [displayColumns.map((column) => (_jsx(TableHead, { className: sortable ? 'cursor-pointer hover:bg-muted/70 transition-colors' : '', onClick: () => handleSort(column), children: _jsxs("div", { className: "flex items-center space-x-1", children: [_jsx("span", { children: formatFieldName(column) }), sortable && sortBy === column && (_jsx("span", { className: "text-primary", children: sortOrder === 'asc' ? '↑' : '↓' }))] }) }, column))), renderActions && _jsx(TableHead, { className: "text-right", children: "Actions" })] }) }), _jsx(TableBody, { children: sortedItems.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: displayColumns.length + (renderActions ? 1 : 0), className: "h-24 text-center", children: emptyMessage }) })) : (sortedItems.map((item) => (_jsxs(TableRow, { className: onRowClick ? 'cursor-pointer' : '', onClick: () => onRowClick?.(item), children: [displayColumns.map((column) => (_jsx(TableCell, { children: fieldTypes[column] === 'relationship'
92
+ ? renderRelationshipCell(item[column], column)
93
+ : getFieldDisplayValue(item[column], fieldTypes[column]) }, column))), renderActions && (_jsx(TableCell, { className: "text-right", onClick: (e) => e.stopPropagation(), children: renderActions(item) }))] }, String(item.id))))) })] }) }) }));
94
+ }
@@ -0,0 +1,29 @@
1
+ export interface SearchBarProps {
2
+ onSearch?: (query: string) => void;
3
+ onClear?: () => void;
4
+ placeholder?: string;
5
+ defaultValue?: string;
6
+ searchLabel?: string;
7
+ className?: string;
8
+ }
9
+ /**
10
+ * Standalone search bar component
11
+ * Can be embedded in any custom page
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <SearchBar
16
+ * onSearch={(query) => {
17
+ * setSearchQuery(query);
18
+ * fetchPosts({ search: query });
19
+ * }}
20
+ * onClear={() => {
21
+ * setSearchQuery('');
22
+ * fetchPosts({});
23
+ * }}
24
+ * placeholder="Search posts..."
25
+ * />
26
+ * ```
27
+ */
28
+ export declare function SearchBar({ onSearch, onClear, placeholder, defaultValue, searchLabel, className, }: SearchBarProps): import("react/jsx-runtime").JSX.Element;
29
+ //# sourceMappingURL=SearchBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchBar.d.ts","sourceRoot":"","sources":["../../../src/components/standalone/SearchBar.tsx"],"names":[],"mappings":"AASA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,OAAO,EACP,WAAyB,EACzB,YAAiB,EACjB,WAAsB,EACtB,SAAS,GACV,EAAE,cAAc,2CAyChB"}
@@ -0,0 +1,43 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { Input } from '../../primitives/input.js';
5
+ import { Button } from '../../primitives/button.js';
6
+ import { Card } from '../../primitives/card.js';
7
+ import { usePathname, useRouter } from 'next/navigation';
8
+ /**
9
+ * Standalone search bar component
10
+ * Can be embedded in any custom page
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <SearchBar
15
+ * onSearch={(query) => {
16
+ * setSearchQuery(query);
17
+ * fetchPosts({ search: query });
18
+ * }}
19
+ * onClear={() => {
20
+ * setSearchQuery('');
21
+ * fetchPosts({});
22
+ * }}
23
+ * placeholder="Search posts..."
24
+ * />
25
+ * ```
26
+ */
27
+ export function SearchBar({ onSearch, onClear, placeholder = 'Search...', defaultValue = '', searchLabel = 'Search', className, }) {
28
+ const router = useRouter();
29
+ const pathname = usePathname();
30
+ const [searchInput, setSearchInput] = useState(defaultValue);
31
+ const handleSubmit = (e) => {
32
+ e.preventDefault();
33
+ if (onSearch)
34
+ onSearch(searchInput.trim());
35
+ else
36
+ router.push(`${pathname}?search=${searchInput.trim()}`);
37
+ };
38
+ const handleClear = () => {
39
+ setSearchInput('');
40
+ onClear?.();
41
+ };
42
+ return (_jsx(Card, { className: `p-4 ${className || ''}`, children: _jsxs("form", { onSubmit: handleSubmit, className: "flex gap-2", children: [_jsxs("div", { className: "flex-1 relative", children: [_jsx(Input, { type: "text", value: searchInput, onChange: (e) => setSearchInput(e.target.value), placeholder: placeholder, className: "pr-10" }), searchInput && (_jsx("button", { type: "button", onClick: handleClear, className: "absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground", children: "\u2715" }))] }), _jsx(Button, { type: "submit", children: searchLabel })] }) }));
43
+ }
@@ -0,0 +1,11 @@
1
+ export { ItemCreateForm } from './ItemCreateForm.js';
2
+ export { ItemEditForm } from './ItemEditForm.js';
3
+ export { ListTable } from './ListTable.js';
4
+ export { SearchBar } from './SearchBar.js';
5
+ export { DeleteButton } from './DeleteButton.js';
6
+ export type { ItemCreateFormProps } from './ItemCreateForm.js';
7
+ export type { ItemEditFormProps } from './ItemEditForm.js';
8
+ export type { ListTableProps } from './ListTable.js';
9
+ export type { SearchBarProps } from './SearchBar.js';
10
+ export type { DeleteButtonProps } from './DeleteButton.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/standalone/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA"}
@@ -0,0 +1,6 @@
1
+ // Standalone composable components
2
+ export { ItemCreateForm } from './ItemCreateForm.js';
3
+ export { ItemEditForm } from './ItemEditForm.js';
4
+ export { ListTable } from './ListTable.js';
5
+ export { SearchBar } from './SearchBar.js';
6
+ export { DeleteButton } from './DeleteButton.js';
@@ -0,0 +1,27 @@
1
+ export { AdminUI } from './components/AdminUI.js';
2
+ export { Dashboard } from './components/Dashboard.js';
3
+ export { Navigation } from './components/Navigation.js';
4
+ export { ListView } from './components/ListView.js';
5
+ export { ListViewClient } from './components/ListViewClient.js';
6
+ export { ItemForm } from './components/ItemForm.js';
7
+ export { ItemFormClient } from './components/ItemFormClient.js';
8
+ export { ConfirmDialog } from './components/ConfirmDialog.js';
9
+ export { LoadingSpinner } from './components/LoadingSpinner.js';
10
+ export { SkeletonLoader, TableSkeleton, FormSkeleton } from './components/SkeletonLoader.js';
11
+ export { TextField, IntegerField, CheckboxField, SelectField, TimestampField, PasswordField, RelationshipField, FieldRenderer, fieldComponentRegistry, registerFieldComponent, getFieldComponent, } from './components/fields/index.js';
12
+ export type { AdminUIProps } from './components/AdminUI.js';
13
+ export type { DashboardProps } from './components/Dashboard.js';
14
+ export type { NavigationProps } from './components/Navigation.js';
15
+ export type { ListViewProps } from './components/ListView.js';
16
+ export type { ListViewClientProps } from './components/ListViewClient.js';
17
+ export type { ItemFormProps } from './components/ItemForm.js';
18
+ export type { ItemFormClientProps } from './components/ItemFormClient.js';
19
+ export type { ConfirmDialogProps } from './components/ConfirmDialog.js';
20
+ export type { LoadingSpinnerProps } from './components/LoadingSpinner.js';
21
+ export type { SkeletonLoaderProps } from './components/SkeletonLoader.js';
22
+ export type { TextFieldProps, IntegerFieldProps, CheckboxFieldProps, SelectFieldProps, TimestampFieldProps, PasswordFieldProps, RelationshipFieldProps, FieldRendererProps, FieldComponent, FieldComponentProps, } from './components/fields/index.js';
23
+ export { ItemCreateForm, ItemEditForm, ListTable, SearchBar, DeleteButton, } from './components/standalone/index.js';
24
+ export type { ItemCreateFormProps, ItemEditFormProps, ListTableProps, SearchBarProps, DeleteButtonProps, } from './components/standalone/index.js';
25
+ export { cn, formatListName, formatFieldName, getFieldDisplayValue } from './lib/utils.js';
26
+ export { generateThemeCSS, getThemeStyleTag, presetThemes } from './lib/theme.js';
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAG5F,OAAO,EACL,SAAS,EACT,YAAY,EACZ,aAAa,EACb,WAAW,EACX,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,8BAA8B,CAAA;AAGrC,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC/D,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AACjE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACzE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACzE,YAAY,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AACvE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACzE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AAEzE,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,cAAc,EACd,mBAAmB,GACpB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EACL,cAAc,EACd,YAAY,EACZ,SAAS,EACT,SAAS,EACT,YAAY,GACb,MAAM,kCAAkC,CAAA;AAEzC,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,kCAAkC,CAAA;AAGzC,OAAO,EAAE,EAAE,EAAE,cAAc,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAG1F,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ // Main components
2
+ export { AdminUI } from './components/AdminUI.js';
3
+ export { Dashboard } from './components/Dashboard.js';
4
+ export { Navigation } from './components/Navigation.js';
5
+ export { ListView } from './components/ListView.js';
6
+ export { ListViewClient } from './components/ListViewClient.js';
7
+ export { ItemForm } from './components/ItemForm.js';
8
+ export { ItemFormClient } from './components/ItemFormClient.js';
9
+ export { ConfirmDialog } from './components/ConfirmDialog.js';
10
+ export { LoadingSpinner } from './components/LoadingSpinner.js';
11
+ export { SkeletonLoader, TableSkeleton, FormSkeleton } from './components/SkeletonLoader.js';
12
+ // Field components
13
+ export { TextField, IntegerField, CheckboxField, SelectField, TimestampField, PasswordField, RelationshipField, FieldRenderer, fieldComponentRegistry, registerFieldComponent, getFieldComponent, } from './components/fields/index.js';
14
+ // Standalone composable components
15
+ export { ItemCreateForm, ItemEditForm, ListTable, SearchBar, DeleteButton, } from './components/standalone/index.js';
16
+ // Utility functions
17
+ export { cn, formatListName, formatFieldName, getFieldDisplayValue } from './lib/utils.js';
18
+ // Theme utilities
19
+ export { generateThemeCSS, getThemeStyleTag, presetThemes } from './lib/theme.js';
@@ -0,0 +1,43 @@
1
+ import type { FieldConfig } from '@opensaas/stack-core';
2
+ import type { ComponentType } from 'react';
3
+ /**
4
+ * Serializable field config for client components
5
+ * Strips out functions and non-serializable properties
6
+ */
7
+ export type SerializableFieldConfig = {
8
+ type: string;
9
+ label?: string;
10
+ validation?: {
11
+ isRequired?: boolean;
12
+ length?: {
13
+ min?: number;
14
+ max?: number;
15
+ };
16
+ min?: number;
17
+ max?: number;
18
+ };
19
+ options?: Array<{
20
+ label: string;
21
+ value: string;
22
+ }>;
23
+ many?: boolean;
24
+ ref?: string;
25
+ ui?: {
26
+ component?: ComponentType<any>;
27
+ fieldType?: string;
28
+ [key: string]: unknown;
29
+ };
30
+ };
31
+ /**
32
+ * Extract only serializable properties from a single field config
33
+ * Removes functions (getZodSchema, getPrismaType, getTypeScriptType)
34
+ * and non-serializable properties (access, hooks, typePatch, valueForClientSerialization)
35
+ */
36
+ export declare function serializeFieldConfig(fieldConfig: FieldConfig): SerializableFieldConfig;
37
+ /**
38
+ * Extract only serializable properties from field configs
39
+ * Removes functions (getZodSchema, getPrismaType, getTypeScriptType)
40
+ * and non-serializable properties (access, hooks, typePatch)
41
+ */
42
+ export declare function serializeFieldConfigs(fields: Record<string, FieldConfig>): Record<string, SerializableFieldConfig>;
43
+ //# sourceMappingURL=serializeFieldConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializeFieldConfig.d.ts","sourceRoot":"","sources":["../../src/lib/serializeFieldConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE;QACX,UAAU,CAAC,EAAE,OAAO,CAAA;QACpB,MAAM,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,MAAM,CAAC;YAAC,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QACvC,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,GAAG,CAAC,EAAE,MAAM,CAAA;KACb,CAAA;IACD,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,EAAE,CAAC,EAAE;QAEH,SAAS,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAA;QAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KACvB,CAAA;CACF,CAAA;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,GAAG,uBAAuB,CAsCtF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAQzC"}