@classytic/formkit 1.0.3 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs DELETED
@@ -1,233 +0,0 @@
1
- 'use strict';
2
-
3
- var reactHookForm = require('react-hook-form');
4
- var react = require('react');
5
- var jsxRuntime = require('react/jsx-runtime');
6
- var clsx = require('clsx');
7
- var tailwindMerge = require('tailwind-merge');
8
-
9
- var FormSystemContext = react.createContext(null);
10
- FormSystemContext.displayName = "FormSystemContext";
11
- function FormSystemProvider({
12
- components,
13
- layouts,
14
- children
15
- }) {
16
- const value = react.useMemo(
17
- () => ({
18
- components: components ?? {},
19
- layouts: layouts ?? {}
20
- }),
21
- [components, layouts]
22
- );
23
- return /* @__PURE__ */ jsxRuntime.jsx(FormSystemContext.Provider, { value, children });
24
- }
25
- function useFormSystem() {
26
- const context = react.useContext(FormSystemContext);
27
- if (!context) {
28
- throw new Error(
29
- "[FormKit] useFormSystem must be used within a FormSystemProvider. Make sure to wrap your form components with <FormSystemProvider>."
30
- );
31
- }
32
- return context;
33
- }
34
- function useFieldComponent(type, variant) {
35
- const { components } = useFormSystem();
36
- if (variant && typeof components[variant] === "object" && components[variant] !== null) {
37
- const variantComponents = components[variant];
38
- const variantComponent = variantComponents[type];
39
- if (variantComponent) {
40
- return variantComponent;
41
- }
42
- }
43
- const typeComponent = components[type];
44
- if (typeComponent && typeof typeComponent === "function") {
45
- return typeComponent;
46
- }
47
- const defaultComponent = components["default"];
48
- if (defaultComponent && typeof defaultComponent === "function") {
49
- return defaultComponent;
50
- }
51
- const textComponent = components["text"];
52
- if (textComponent && typeof textComponent === "function") {
53
- return textComponent;
54
- }
55
- return NullComponent;
56
- }
57
- function useLayoutComponent(type, variant) {
58
- const { layouts } = useFormSystem();
59
- if (variant && typeof layouts[variant] === "object" && layouts[variant] !== null) {
60
- const variantLayouts = layouts[variant];
61
- const variantLayout = variantLayouts[type];
62
- if (variantLayout) {
63
- return variantLayout;
64
- }
65
- }
66
- const typeLayout = layouts[type];
67
- if (typeLayout && typeof typeLayout === "function") {
68
- return typeLayout;
69
- }
70
- const defaultLayout = layouts["default"];
71
- if (defaultLayout && typeof defaultLayout === "function") {
72
- return defaultLayout;
73
- }
74
- return DefaultLayout;
75
- }
76
- function DefaultLayout({ children, className }) {
77
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children });
78
- }
79
- function NullComponent() {
80
- return null;
81
- }
82
- function cn(...inputs) {
83
- return tailwindMerge.twMerge(clsx.clsx(inputs));
84
- }
85
- function FormGenerator({
86
- schema,
87
- control,
88
- disabled = false,
89
- variant,
90
- className
91
- }) {
92
- const formContext = reactHookForm.useFormContext();
93
- const activeControl = control ?? formContext?.control;
94
- if (!schema?.sections || schema.sections.length === 0) {
95
- return null;
96
- }
97
- return /* @__PURE__ */ jsxRuntime.jsx(
98
- "div",
99
- {
100
- className: cn(
101
- "formkit-root",
102
- variant && `formkit-variant-${variant}`,
103
- className
104
- ),
105
- "data-formkit-root": "",
106
- children: schema.sections.map((section, index) => /* @__PURE__ */ jsxRuntime.jsx(
107
- SectionRenderer,
108
- {
109
- section,
110
- control: activeControl,
111
- disabled,
112
- variant
113
- },
114
- section.id ?? `section-${index}`
115
- ))
116
- }
117
- );
118
- }
119
- function SectionRenderer({
120
- section,
121
- control,
122
- disabled,
123
- variant
124
- }) {
125
- const activeVariant = section.variant ?? variant;
126
- const SectionLayout = useLayoutComponent("section", activeVariant);
127
- if (section.condition && !section.condition(control)) {
128
- return null;
129
- }
130
- return /* @__PURE__ */ jsxRuntime.jsx(
131
- SectionLayout,
132
- {
133
- title: section.title,
134
- description: section.description,
135
- icon: section.icon,
136
- variant: activeVariant,
137
- className: section.className,
138
- collapsible: section.collapsible,
139
- defaultCollapsed: section.defaultCollapsed,
140
- children: section.render ? (
141
- // Custom render function
142
- section.render({ control, disabled, section })
143
- ) : (
144
- // Standard grid rendering
145
- /* @__PURE__ */ jsxRuntime.jsx(
146
- GridRenderer,
147
- {
148
- fields: section.fields,
149
- cols: section.cols,
150
- gap: section.gap,
151
- control,
152
- disabled,
153
- variant: activeVariant
154
- }
155
- )
156
- )
157
- }
158
- );
159
- }
160
- function GridRenderer({
161
- fields,
162
- cols = 1,
163
- gap,
164
- control,
165
- disabled,
166
- variant
167
- }) {
168
- const GridLayout = useLayoutComponent("grid", variant);
169
- if (!fields || fields.length === 0) {
170
- return null;
171
- }
172
- return /* @__PURE__ */ jsxRuntime.jsx(GridLayout, { cols, gap, children: fields.map((field, index) => /* @__PURE__ */ jsxRuntime.jsx(
173
- FieldWrapper,
174
- {
175
- field,
176
- control,
177
- disabled,
178
- variant
179
- },
180
- field.name || `field-${index}`
181
- )) });
182
- }
183
- function FieldWrapper({
184
- field,
185
- control,
186
- disabled,
187
- variant
188
- }) {
189
- const formValues = reactHookForm.useWatch({ control });
190
- if (field.condition && !field.condition(formValues)) {
191
- return null;
192
- }
193
- const activeVariant = field.variant ?? variant;
194
- const FieldComponent = useFieldComponent(field.type, activeVariant);
195
- if (!FieldComponent) {
196
- return null;
197
- }
198
- const isDisabled = disabled || field.disabled;
199
- return /* @__PURE__ */ jsxRuntime.jsx(
200
- "div",
201
- {
202
- className: cn(
203
- "formkit-field",
204
- field.fullWidth && "col-span-full",
205
- field.className
206
- ),
207
- "data-formkit-field": field.name,
208
- "data-field-type": field.type,
209
- children: /* @__PURE__ */ jsxRuntime.jsx(
210
- FieldComponent,
211
- {
212
- ...field,
213
- field,
214
- control,
215
- disabled: isDisabled,
216
- variant: activeVariant
217
- }
218
- )
219
- }
220
- );
221
- }
222
-
223
- exports.FieldWrapper = FieldWrapper;
224
- exports.FormGenerator = FormGenerator;
225
- exports.FormSystemProvider = FormSystemProvider;
226
- exports.GridRenderer = GridRenderer;
227
- exports.SectionRenderer = SectionRenderer;
228
- exports.cn = cn;
229
- exports.useFieldComponent = useFieldComponent;
230
- exports.useFormSystem = useFormSystem;
231
- exports.useLayoutComponent = useLayoutComponent;
232
- //# sourceMappingURL=index.cjs.map
233
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/FormSystemContext.tsx","../src/utils.ts","../src/FormGenerator.tsx"],"names":["createContext","useMemo","jsx","useContext","twMerge","clsx","useFormContext","useWatch"],"mappings":"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","file":"index.cjs","sourcesContent":["\"use client\";\r\n\r\nimport { createContext, useContext, useMemo } from \"react\";\r\nimport type {\r\n FormSystemContextValue,\r\n FormSystemProviderProps,\r\n FieldComponent,\r\n LayoutComponent,\r\n FieldType,\r\n LayoutType,\r\n Variant,\r\n SectionLayoutProps,\r\n GridLayoutProps,\r\n DefaultLayoutProps,\r\n FormElement,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// Context\r\n// ============================================================================\r\n\r\nconst FormSystemContext = createContext<FormSystemContextValue | null>(null);\r\n\r\n// Display name for React DevTools\r\nFormSystemContext.displayName = \"FormSystemContext\";\r\n\r\n// ============================================================================\r\n// Provider\r\n// ============================================================================\r\n\r\n/**\r\n * FormSystemProvider\r\n *\r\n * Root provider that enables the form system. Provides component and layout\r\n * registries to FormGenerator and its descendants.\r\n *\r\n * @example\r\n * ```tsx\r\n * import { FormSystemProvider } from '@classytic/formkit';\r\n *\r\n * const components = {\r\n * text: TextInput,\r\n * select: SelectInput,\r\n * // Variant-specific components\r\n * compact: {\r\n * text: CompactTextInput,\r\n * },\r\n * };\r\n *\r\n * const layouts = {\r\n * section: SectionLayout,\r\n * grid: GridLayout,\r\n * };\r\n *\r\n * function App() {\r\n * return (\r\n * <FormSystemProvider components={components} layouts={layouts}>\r\n * <YourFormComponent />\r\n * </FormSystemProvider>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport function FormSystemProvider({\r\n components,\r\n layouts,\r\n children,\r\n}: FormSystemProviderProps): FormElement {\r\n const value = useMemo<FormSystemContextValue>(\r\n () => ({\r\n components: components ?? {},\r\n layouts: layouts ?? {},\r\n }),\r\n [components, layouts]\r\n );\r\n\r\n return <FormSystemContext.Provider value={value}>{children}</FormSystemContext.Provider>;\r\n}\r\n\r\n// ============================================================================\r\n// Hooks\r\n// ============================================================================\r\n\r\n/**\r\n * Hook to access the form system context.\r\n *\r\n * @throws {Error} If used outside FormSystemProvider\r\n * @returns Form system context value\r\n *\r\n * @example\r\n * ```tsx\r\n * const { components, layouts } = useFormSystem();\r\n * ```\r\n */\r\nexport function useFormSystem(): FormSystemContextValue {\r\n const context = useContext(FormSystemContext);\r\n if (!context) {\r\n throw new Error(\r\n \"[FormKit] useFormSystem must be used within a FormSystemProvider. \" +\r\n \"Make sure to wrap your form components with <FormSystemProvider>.\"\r\n );\r\n }\r\n return context;\r\n}\r\n\r\n/**\r\n * Hook to get a field component by type and optional variant.\r\n *\r\n * Resolution order:\r\n * 1. Variant-specific component: `components[variant][type]`\r\n * 2. Type-specific component: `components[type]`\r\n * 3. Default component: `components[\"default\"]`\r\n * 4. Text fallback: `components[\"text\"]`\r\n *\r\n * @param type - Field type identifier\r\n * @param variant - Optional variant name\r\n * @returns Field component or fallback\r\n *\r\n * @internal\r\n */\r\nexport function useFieldComponent(type: FieldType, variant?: Variant): FieldComponent {\r\n const { components } = useFormSystem();\r\n\r\n // 1. Try variant-specific component\r\n if (variant && typeof components[variant] === \"object\" && components[variant] !== null) {\r\n const variantComponents = components[variant] as Record<string, FieldComponent>;\r\n const variantComponent = variantComponents[type];\r\n if (variantComponent) {\r\n return variantComponent;\r\n }\r\n }\r\n\r\n // 2. Try type-specific component\r\n const typeComponent = components[type] as FieldComponent | undefined;\r\n if (typeComponent && typeof typeComponent === \"function\") {\r\n return typeComponent;\r\n }\r\n\r\n // 3. Try default component\r\n const defaultComponent = components[\"default\"] as FieldComponent | undefined;\r\n if (defaultComponent && typeof defaultComponent === \"function\") {\r\n return defaultComponent;\r\n }\r\n\r\n // 4. Try text fallback\r\n const textComponent = components[\"text\"] as FieldComponent | undefined;\r\n if (textComponent && typeof textComponent === \"function\") {\r\n return textComponent;\r\n }\r\n\r\n // 5. Development warning and placeholder\r\n if (process.env.NODE_ENV !== \"production\") {\r\n console.warn(\r\n `[FormKit] No component found for type \"${type}\"${variant ? ` (variant: \"${variant}\")` : \"\"}. ` +\r\n \"Register a component for this type in your FormSystemProvider.\"\r\n );\r\n return MissingFieldComponent;\r\n }\r\n\r\n // Production: silent fallback\r\n return NullComponent;\r\n}\r\n\r\n/**\r\n * Hook to get a layout component by type and optional variant.\r\n *\r\n * Resolution order:\r\n * 1. Variant-specific layout: `layouts[variant][type]`\r\n * 2. Type-specific layout: `layouts[type]`\r\n * 3. Default layout: `layouts[\"default\"]`\r\n * 4. Built-in default layout\r\n *\r\n * @param type - Layout type identifier\r\n * @param variant - Optional variant name\r\n * @returns Layout component or fallback\r\n *\r\n * @internal\r\n */\r\nexport function useLayoutComponent(\r\n type: LayoutType,\r\n variant?: Variant\r\n): LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps> {\r\n const { layouts } = useFormSystem();\r\n\r\n // 1. Try variant-specific layout\r\n if (variant && typeof layouts[variant] === \"object\" && layouts[variant] !== null) {\r\n const variantLayouts = layouts[variant] as Record<\r\n string,\r\n LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>\r\n >;\r\n const variantLayout = variantLayouts[type];\r\n if (variantLayout) {\r\n return variantLayout;\r\n }\r\n }\r\n\r\n // 2. Try type-specific layout\r\n const typeLayout = layouts[type] as\r\n | LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>\r\n | undefined;\r\n if (typeLayout && typeof typeLayout === \"function\") {\r\n return typeLayout;\r\n }\r\n\r\n // 3. Try default layout\r\n const defaultLayout = layouts[\"default\"] as\r\n | LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>\r\n | undefined;\r\n if (defaultLayout && typeof defaultLayout === \"function\") {\r\n return defaultLayout;\r\n }\r\n\r\n // 4. Built-in default layout\r\n return DefaultLayout;\r\n}\r\n\r\n// ============================================================================\r\n// Fallback Components\r\n// ============================================================================\r\n\r\n/**\r\n * Default layout component - simple div wrapper.\r\n * Used when no layout is registered.\r\n */\r\nfunction DefaultLayout({ children, className }: DefaultLayoutProps): FormElement {\r\n return <div className={className}>{children}</div>;\r\n}\r\n\r\n/**\r\n * Null component for production fallback.\r\n */\r\nfunction NullComponent(): FormElement {\r\n return null;\r\n}\r\n\r\n/**\r\n * Development placeholder for missing field components.\r\n */\r\nfunction MissingFieldComponent({ field }: { field: { type: string; name: string } }): FormElement {\r\n return (\r\n <div\r\n style={{\r\n color: \"#dc2626\",\r\n padding: \"8px 12px\",\r\n border: \"1px dashed #dc2626\",\r\n borderRadius: \"4px\",\r\n fontSize: \"12px\",\r\n fontFamily: \"monospace\",\r\n backgroundColor: \"#fef2f2\",\r\n }}\r\n >\r\n Missing component: <strong>{field.type}</strong> (field: {field.name})\r\n </div>\r\n );\r\n}\r\n","import { clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport type { ClassValue } from \"clsx\";\r\n\r\n/**\r\n * Utility function to merge CSS classes with Tailwind CSS conflict resolution.\r\n *\r\n * Combines `clsx` for conditional class handling with `tailwind-merge`\r\n * for proper Tailwind CSS class conflict resolution.\r\n *\r\n * @param inputs - Class values to merge (strings, arrays, objects, or conditionals)\r\n * @returns Merged and deduplicated class string\r\n *\r\n * @example\r\n * ```tsx\r\n * // Basic usage\r\n * cn(\"px-2 py-1\", \"px-4\") // \"py-1 px-4\"\r\n *\r\n * // Conditional classes\r\n * cn(\"base\", isActive && \"active\", { \"disabled\": isDisabled })\r\n *\r\n * // Arrays\r\n * cn([\"flex\", \"items-center\"], \"gap-2\")\r\n * ```\r\n */\r\nexport function cn(...inputs: ClassValue[]): string {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\n/**\r\n * Re-export ClassValue type for consumers who need it.\r\n */\r\nexport type { ClassValue };\r\n","\"use client\";\r\n\r\nimport { useFormContext, useWatch } from \"react-hook-form\";\r\nimport type { Control, FieldValues } from \"react-hook-form\";\r\nimport { useFieldComponent, useLayoutComponent } from \"./FormSystemContext\";\r\nimport { cn } from \"./utils\";\r\nimport type {\r\n FormGeneratorProps,\r\n Section,\r\n BaseField,\r\n Variant,\r\n FormElement,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// FormGenerator Component\r\n// ============================================================================\r\n\r\n/**\r\n * FormGenerator - Headless Form Generator Component\r\n *\r\n * Renders a form based on a schema definition, using components registered\r\n * via FormSystemProvider. Supports conditional fields, dynamic layouts,\r\n * and component variants.\r\n *\r\n * @template TFieldValues - Form field values type for type safety\r\n *\r\n * @example\r\n * ```tsx\r\n * import { useForm } from 'react-hook-form';\r\n * import { FormGenerator } from '@classytic/formkit';\r\n *\r\n * interface FormData {\r\n * firstName: string;\r\n * email: string;\r\n * }\r\n *\r\n * function MyForm() {\r\n * const { control } = useForm<FormData>();\r\n *\r\n * const schema = {\r\n * sections: [\r\n * {\r\n * title: \"User Details\",\r\n * fields: [\r\n * { name: \"firstName\", type: \"text\", label: \"First Name\" },\r\n * { name: \"email\", type: \"email\", label: \"Email\" }\r\n * ]\r\n * }\r\n * ]\r\n * };\r\n *\r\n * return <FormGenerator schema={schema} control={control} />;\r\n * }\r\n * ```\r\n */\r\nexport function FormGenerator<TFieldValues extends FieldValues = FieldValues>({\r\n schema,\r\n control,\r\n disabled = false,\r\n variant,\r\n className,\r\n}: FormGeneratorProps<TFieldValues>): FormElement {\r\n // Use provided control or fall back to FormProvider context\r\n const formContext = useFormContext<TFieldValues>();\r\n const activeControl = control ?? formContext?.control;\r\n\r\n // Early return if no schema\r\n if (!schema?.sections || schema.sections.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-root\",\r\n variant && `formkit-variant-${variant}`,\r\n className\r\n )}\r\n data-formkit-root=\"\"\r\n >\r\n {schema.sections.map((section, index) => (\r\n <SectionRenderer\r\n key={section.id ?? `section-${index}`}\r\n section={section}\r\n control={activeControl}\r\n disabled={disabled}\r\n variant={variant}\r\n />\r\n ))}\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Section Renderer\r\n// ============================================================================\r\n\r\ninterface SectionRendererProps<TFieldValues extends FieldValues = FieldValues> {\r\n section: Section<TFieldValues>;\r\n control?: Control<TFieldValues>;\r\n disabled?: boolean;\r\n variant?: Variant;\r\n}\r\n\r\n/**\r\n * Renders a single section with its fields.\r\n * Handles conditional rendering and variant resolution.\r\n */\r\nfunction SectionRenderer<TFieldValues extends FieldValues = FieldValues>({\r\n section,\r\n control,\r\n disabled,\r\n variant,\r\n}: SectionRendererProps<TFieldValues>): FormElement {\r\n // Section can override variant\r\n const activeVariant = section.variant ?? variant;\r\n const SectionLayout = useLayoutComponent(\"section\", activeVariant);\r\n\r\n // Check section condition\r\n if (section.condition && !section.condition(control)) {\r\n return null;\r\n }\r\n\r\n return (\r\n <SectionLayout\r\n title={section.title}\r\n description={section.description}\r\n icon={section.icon}\r\n variant={activeVariant}\r\n className={section.className}\r\n collapsible={section.collapsible}\r\n defaultCollapsed={section.defaultCollapsed}\r\n >\r\n {section.render ? (\r\n // Custom render function\r\n section.render({ control, disabled, section })\r\n ) : (\r\n // Standard grid rendering\r\n <GridRenderer\r\n fields={section.fields}\r\n cols={section.cols}\r\n gap={section.gap}\r\n control={control}\r\n disabled={disabled}\r\n variant={activeVariant}\r\n />\r\n )}\r\n </SectionLayout>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Grid Renderer\r\n// ============================================================================\r\n\r\ninterface GridRendererProps<TFieldValues extends FieldValues = FieldValues> {\r\n fields?: BaseField<TFieldValues>[];\r\n cols?: number;\r\n gap?: number;\r\n control?: Control<TFieldValues>;\r\n disabled?: boolean;\r\n variant?: Variant;\r\n}\r\n\r\n/**\r\n * Renders a grid of fields with specified column layout.\r\n */\r\nfunction GridRenderer<TFieldValues extends FieldValues = FieldValues>({\r\n fields,\r\n cols = 1,\r\n gap,\r\n control,\r\n disabled,\r\n variant,\r\n}: GridRendererProps<TFieldValues>): FormElement {\r\n const GridLayout = useLayoutComponent(\"grid\", variant);\r\n\r\n if (!fields || fields.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <GridLayout cols={cols} gap={gap}>\r\n {fields.map((field, index) => (\r\n <FieldWrapper\r\n key={field.name || `field-${index}`}\r\n field={field}\r\n control={control}\r\n disabled={disabled}\r\n variant={variant}\r\n />\r\n ))}\r\n </GridLayout>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Field Wrapper\r\n// ============================================================================\r\n\r\ninterface FieldWrapperProps<TFieldValues extends FieldValues = FieldValues> {\r\n field: BaseField<TFieldValues>;\r\n control?: Control<TFieldValues>;\r\n disabled?: boolean;\r\n variant?: Variant;\r\n}\r\n\r\n/**\r\n * Wraps individual fields with conditional rendering logic.\r\n * Handles field visibility and variant resolution.\r\n */\r\nfunction FieldWrapper<TFieldValues extends FieldValues = FieldValues>({\r\n field,\r\n control,\r\n disabled,\r\n variant,\r\n}: FieldWrapperProps<TFieldValues>): FormElement {\r\n // Watch form values for conditional rendering\r\n const formValues = useWatch({ control }) as TFieldValues;\r\n\r\n // Check field condition\r\n if (field.condition && !field.condition(formValues)) {\r\n return null;\r\n }\r\n\r\n // Field can override variant\r\n const activeVariant = field.variant ?? variant;\r\n const FieldComponent = useFieldComponent(field.type, activeVariant);\r\n\r\n if (!FieldComponent) {\r\n return null;\r\n }\r\n\r\n // Merge disabled states\r\n const isDisabled = disabled || field.disabled;\r\n\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-field\",\r\n field.fullWidth && \"col-span-full\",\r\n field.className\r\n )}\r\n data-formkit-field={field.name}\r\n data-field-type={field.type}\r\n >\r\n <FieldComponent\r\n {...(field as BaseField<FieldValues>)}\r\n field={field as BaseField<FieldValues>}\r\n control={control as Control<FieldValues>}\r\n disabled={isDisabled}\r\n variant={activeVariant}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Named Exports for Subcomponents (for advanced use cases)\r\n// ============================================================================\r\n\r\nexport { SectionRenderer, GridRenderer, FieldWrapper };\r\n"]}