betterstart-cli 0.0.108 → 0.0.109

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/cli.js CHANGED
@@ -16117,9 +16117,11 @@ ${contentStateDestructure}
16117
16117
  } = state
16118
16118
  ${contentSidebarVisibilityState}
16119
16119
  return (
16120
- <form id="${schemaName}-form" onSubmit={form.handleSubmit((values) => onSubmit(values${hasDraftInitialData}), handleErrors)} ${topLevelTabsFieldClassName}>
16121
- ${formBodyJsx}
16122
- </form>
16120
+ <Form {...form}>
16121
+ <form autoComplete="off" id="${schemaName}-form" onSubmit={form.handleSubmit((values) => onSubmit(values${hasDraftInitialData}), handleErrors)} ${topLevelTabsFieldClassName}>
16122
+ ${formBodyJsx}
16123
+ </form>
16124
+ </Form>
16123
16125
  )
16124
16126
  }
16125
16127
  `;
@@ -16345,7 +16347,7 @@ ${defaultValues}
16345
16347
 
16346
16348
  const form = useForm<FormValues>({
16347
16349
  resolver: standardSchemaResolver(formSchema),
16348
- mode: 'onBlur',
16350
+ mode: 'onChange',
16349
16351
  reValidateMode: 'onChange',
16350
16352
  defaultValues
16351
16353
  })
@@ -16522,16 +16524,12 @@ function renderFormTabContentDetailsTemplate({
16522
16524
  contentComponentName
16523
16525
  }) {
16524
16526
  return ` <TabsContent value="${tabName}" className="h-full min-h-0 w-full flex-1">
16525
- <Form {...entityForm.form}>
16526
- <${contentComponentName} state={entityForm} tab="${tabName}" />
16527
- </Form>
16527
+ <${contentComponentName} state={entityForm} tab="${tabName}" />
16528
16528
  </TabsContent>`;
16529
16529
  }
16530
16530
  function renderEntityFormBody({ contentComponentName }) {
16531
16531
  return ` <main className="w-full p-4 h-full">
16532
- <Form {...entityForm.form}>
16533
- <${contentComponentName} state={entityForm} />
16534
- </Form>
16532
+ <${contentComponentName} state={entityForm} />
16535
16533
  </main>`;
16536
16534
  }
16537
16535
  function renderEntityFormPage({
@@ -16557,7 +16555,6 @@ function renderEntityFormPage({
16557
16555
  ${showMetadataWidgetScrollThresholdImport}
16558
16556
  ${topLevelTabIconNamesLucide}
16559
16557
  import { Button } from '@admin/components/ui/button'
16560
- import { Form } from '@admin/components/ui/form'
16561
16558
  ${topLevelTabsFieldTabs}import { PageHeader } from '@admin/components/shared/page-header'${showMetadataWidgetEntityMetadataImport}
16562
16559
  import type { ${singular} } from '@admin/actions/${actionImportPath}'
16563
16560
  ${showMetadataWidgetAdmin}
@@ -16718,7 +16715,8 @@ function buildEntityFormArtifacts({
16718
16715
  });
16719
16716
  const shellBody = topLevelTabsField ? topLevelTabsShell : defaultShellBody;
16720
16717
  const topLevelTabComponentImports = topLevelTabComponents.map((spec) => `import { ${spec.componentName} } from './${spec.fileBaseName}'`).join("\n");
16721
- const contentImports = topLevelTabsField ? `import type { TabValue, ${hookName} } from '${hookImportPath}'${topLevelTabComponentImports ? `
16718
+ const contentImports = topLevelTabsField ? `import { Form } from '@admin/components/ui/form'
16719
+ import type { TabValue, ${hookName} } from '${hookImportPath}'${topLevelTabComponentImports ? `
16722
16720
  ${topLevelTabComponentImports}` : ""}` : renderEntityFormContentRenderer({
16723
16721
  kind: "renderFormContentLucideTemplate",
16724
16722
  props: {
@@ -18705,6 +18703,7 @@ ${indent} ) : null}`;
18705
18703
  function renderMultiSelectFieldActionButtonsSerializedValueTemplate({
18706
18704
  indent,
18707
18705
  fieldName,
18706
+ optionsId,
18708
18707
  optionsDeclaration,
18709
18708
  createState,
18710
18709
  previewLimit,
@@ -18747,6 +18746,7 @@ ${indent} type="button"
18747
18746
  ${indent} variant="outline"
18748
18747
  ${indent} role="combobox"
18749
18748
  ${indent} aria-expanded={${openVar}}
18749
+ ${indent} aria-controls="${optionsId}"
18750
18750
  ${indent} className={cn("w-full justify-between gap-2", {
18751
18751
  ${indent} "text-muted-foreground": selectedOptions.length === 0
18752
18752
  ${indent} })}
@@ -18788,7 +18788,7 @@ ${indent} </Button>
18788
18788
  ${indent} </FormControl>
18789
18789
  ${indent} }
18790
18790
  ${indent} />
18791
- ${indent} <PopoverContent className="w-(--anchor-width) p-0" align="start">
18791
+ ${indent} <PopoverContent id="${optionsId}" className="w-(--anchor-width) p-0" align="start">
18792
18792
  ${indent} <Command>
18793
18793
  ${indent} ${searchInput}
18794
18794
  ${indent} <CommandList>
@@ -18858,6 +18858,7 @@ function renderMultiSelectField(field, indent, label, hintJSX, context) {
18858
18858
  const placeholder = field.placeholder || `Select ${label.toLowerCase()}`;
18859
18859
  const previewLimit = Math.max(1, Math.floor(field.previewLimit ?? 1));
18860
18860
  const lowerLabel = label.toLowerCase();
18861
+ const optionsId = `${context.schemaName ? `${toKebabCase(singularize(context.schemaName))}-` : ""}${toKebabCase(field.name)}-options`;
18861
18862
  const optionsDeclaration = isCreatable ? `const options = ${optionsVar}` : renderMultiSelectFieldRenderer({
18862
18863
  kind: "renderMultiSelectFieldStaticOptionsTemplate",
18863
18864
  props: {
@@ -18896,6 +18897,7 @@ ${indent} ${setSearchVar}('')` : "";
18896
18897
  props: {
18897
18898
  indent,
18898
18899
  fieldName: field.name,
18900
+ optionsId,
18899
18901
  optionsDeclaration,
18900
18902
  createState,
18901
18903
  previewLimit,
@@ -19210,6 +19212,7 @@ function buildEntityFormLayout({
19210
19212
  (tabField) => generateFieldJSX2(tabField, `${cardFieldIndent} `, {
19211
19213
  creatableSelectFieldNames,
19212
19214
  defaultValueFromSourceNames,
19215
+ schemaName,
19213
19216
  ...childContext
19214
19217
  })
19215
19218
  ).filter(Boolean).join("\n");
@@ -19256,6 +19259,7 @@ function buildEntityFormLayout({
19256
19259
  return generateFieldJSX2(field, cardFieldIndent, {
19257
19260
  creatableSelectFieldNames,
19258
19261
  defaultValueFromSourceNames,
19262
+ schemaName,
19259
19263
  slotFilter: "main"
19260
19264
  });
19261
19265
  };
@@ -19263,7 +19267,8 @@ function buildEntityFormLayout({
19263
19267
  if (field.type === "tabs") return renderNestedTabsField(field);
19264
19268
  return generateFieldJSX2(field, cardFieldIndent, {
19265
19269
  creatableSelectFieldNames,
19266
- defaultValueFromSourceNames
19270
+ defaultValueFromSourceNames,
19271
+ schemaName
19267
19272
  });
19268
19273
  };
19269
19274
  const renderConditionalSidebarEntry = ({
@@ -19371,6 +19376,7 @@ function buildEntityFormLayout({
19371
19376
  (field) => generateFieldJSX2(field, cardFieldIndent, {
19372
19377
  creatableSelectFieldNames,
19373
19378
  defaultValueFromSourceNames,
19379
+ schemaName,
19374
19380
  slotFilter: "main"
19375
19381
  })
19376
19382
  ).filter(Boolean).join("\n");
@@ -19705,7 +19711,7 @@ function generateForm(schema, pagesDir, options = {}) {
19705
19711
  hasNestedObjectList,
19706
19712
  hasCardContent: true,
19707
19713
  hasSectionCardHeading,
19708
- hasFormRoot: false,
19714
+ hasFormRoot: true,
19709
19715
  hasButton: hasRelationship || hasSelectCombobox || hasNestedList,
19710
19716
  hasFormControls: contentUsesFormControls || contentHasRenderedIconPostfix,
19711
19717
  hasInput: contentUsesInput
@@ -22400,37 +22406,24 @@ function renderSingleFormImportsTemplate({ map }) {
22400
22406
  ${map}
22401
22407
  } from '@admin/components/ui/card'`;
22402
22408
  }
22403
- function renderSingleFormClientModuleTemplate({
22404
- needsReactImport,
22405
- hasCreatableSelectUseQuery,
22406
- lucideIconsLucide,
22407
- hasNestedListUseFieldArray,
22408
- hasTabsFieldImport,
22409
- hasRelationshipImport,
22410
- relHookImportsContent,
22411
- join,
22409
+ function renderSingleFormCardModuleTemplate({
22410
+ imports,
22411
+ content
22412
+ }) {
22413
+ return `'use client'
22414
+ ${imports}
22415
+
22416
+ ${content}
22417
+ `;
22418
+ }
22419
+ function renderSingleFormEntryModuleTemplate({
22412
22420
  singular,
22413
- hasCreatableSelectContent,
22414
22421
  actionImportPath,
22415
- hasCreatableSelectContentText,
22416
- joinText,
22422
+ cardImports,
22417
22423
  cardRenders
22418
22424
  }) {
22419
- return `'use client'
22420
- ${needsReactImport}
22421
- import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'
22422
- import { useMutation, ${hasCreatableSelectUseQuery}useQueryClient } from '@tanstack/react-query'${lucideIconsLucide}
22423
- import {${hasNestedListUseFieldArray} useForm } from 'react-hook-form'
22424
- import { toast } from 'sonner'
22425
- import { z } from 'zod/v3'${hasTabsFieldImport}${hasRelationshipImport}
22426
- ${relHookImportsContent}${join}
22427
- import type {
22428
- ${singular},
22429
- ${hasCreatableSelectContent}${singular}UpsertInput
22430
- } from '@admin/actions/${actionImportPath}'
22431
- import { ${hasCreatableSelectContentText}upsert${singular} } from '@admin/actions/${actionImportPath}'
22432
-
22433
- ${joinText}
22425
+ return `import type { ${singular} } from '@admin/actions/${actionImportPath}'
22426
+ ${cardImports}
22434
22427
 
22435
22428
  interface ${singular}FormProps {
22436
22429
  initialData?: ${singular} | null
@@ -22449,8 +22442,10 @@ function renderSingleFormRenderer(request) {
22449
22442
  switch (request.kind) {
22450
22443
  case "renderSingleFormImportsTemplate":
22451
22444
  return renderSingleFormImportsTemplate(request.props);
22452
- case "renderSingleFormClientModuleTemplate":
22453
- return renderSingleFormClientModuleTemplate(request.props);
22445
+ case "renderSingleFormCardModuleTemplate":
22446
+ return renderSingleFormCardModuleTemplate(request.props);
22447
+ case "renderSingleFormEntryModuleTemplate":
22448
+ return renderSingleFormEntryModuleTemplate(request.props);
22454
22449
  }
22455
22450
  throw new Error("Unsupported renderer request");
22456
22451
  }
@@ -22536,12 +22531,12 @@ ${zodFields}
22536
22531
  })
22537
22532
  ${tabParserConst}
22538
22533
 
22539
- function ${groupComponentName}({ initialData }: { initialData?: ${singular} | null }) {
22534
+ export function ${groupComponentName}({ initialData }: { initialData?: ${singular} | null }) {
22540
22535
  const queryClient = useQueryClient()${analysisHasTabsFieldTab}${relStateContent}${creatableSelectStateContent}${selectStateContent}
22541
22536
 
22542
22537
  const form = useForm<z.infer<typeof ${groupVarPrefix}Schema>>({
22543
22538
  resolver: standardSchemaResolver(${groupVarPrefix}Schema),
22544
- mode: 'onBlur',
22539
+ mode: 'onChange',
22545
22540
  reValidateMode: 'onChange',
22546
22541
  defaultValues: {
22547
22542
  ${defaultValues}
@@ -22571,7 +22566,7 @@ ${fieldArrayHooksContent}
22571
22566
  ${creatableSelectHandlersContent}
22572
22567
  return (
22573
22568
  <Form {...form}>
22574
- <form onSubmit={form.handleSubmit((values) => {
22569
+ <form autoComplete="off" onSubmit={form.handleSubmit((values) => {
22575
22570
  mutation.mutate(values as ${singular}UpsertInput)
22576
22571
  })}>
22577
22572
  <Card >
@@ -22805,7 +22800,7 @@ function renderSingleFormBuildGroupFieldsJsxRenderer(request) {
22805
22800
  }
22806
22801
 
22807
22802
  // adapters/next/generators/form/form-single/build-group-fields-jsx.ts
22808
- function buildGroupFieldsJSX(group2, analysis, defaultValueFromSourceNames, creatableSelectFieldNames) {
22803
+ function buildGroupFieldsJSX(group2, analysis, defaultValueFromSourceNames, creatableSelectFieldNames, schemaName) {
22809
22804
  const indent = " ";
22810
22805
  return group2.fields.map((f) => {
22811
22806
  if (f.type === "tabs" && f.tabs) {
@@ -22814,7 +22809,8 @@ function buildGroupFieldsJSX(group2, analysis, defaultValueFromSourceNames, crea
22814
22809
  const tabFields = (t.fields || []).map(
22815
22810
  (tf) => generateFieldJSX2(tf, " ", {
22816
22811
  creatableSelectFieldNames,
22817
- defaultValueFromSourceNames
22812
+ defaultValueFromSourceNames,
22813
+ schemaName
22818
22814
  })
22819
22815
  ).join("\n");
22820
22816
  return renderSingleFormBuildGroupFieldsJsxRenderer({
@@ -22838,7 +22834,8 @@ function buildGroupFieldsJSX(group2, analysis, defaultValueFromSourceNames, crea
22838
22834
  if (analysis.tabFieldNames.has(f.name)) return "";
22839
22835
  return generateFieldJSX2(f, indent, {
22840
22836
  creatableSelectFieldNames,
22841
- defaultValueFromSourceNames
22837
+ defaultValueFromSourceNames,
22838
+ schemaName
22842
22839
  });
22843
22840
  }).filter(Boolean).join("\n");
22844
22841
  }
@@ -22880,7 +22877,8 @@ function generateCardComponent(group2, schema, analysis, allFlatFields) {
22880
22877
  group2,
22881
22878
  analysis,
22882
22879
  defaultValueFromSourceNames,
22883
- creatableSelectFieldNames
22880
+ creatableSelectFieldNames,
22881
+ schema.name
22884
22882
  );
22885
22883
  const relState = buildGroupRelState(analysis);
22886
22884
  const selectState = buildGroupSelectState(
@@ -23043,135 +23041,179 @@ function generateSingleForm(schema, pagesDir, options = {}) {
23043
23041
  (f) => !f.primaryKey && f.name !== "createdAt" && f.name !== "updatedAt" && !isAuthorshipFieldName(f.name)
23044
23042
  );
23045
23043
  const cardGroups = parseCardGroups(allFormFields, schema.label);
23046
- const hasBoolean = hasFieldType(schema.fields, "boolean");
23047
- const hasImage = hasFieldType(schema.fields, "image");
23048
- const hasVideo = hasFieldType(schema.fields, "video");
23049
- const hasMedia = hasFieldType(schema.fields, "media");
23050
- const hasGallery = hasFieldType(schema.fields, "gallery");
23051
- const hasIcon = hasFieldType(schema.fields, "icon");
23052
- const hasIconPostfix = hasRenderedIconPostfix(allFormFields);
23053
- const hasDate = hasFieldType(schema.fields, "date");
23054
23044
  const flatFields = flattenFields(allFormFields);
23055
- const hasMultiSelect = flatFields.some((f) => f.type === "select" && f.multiple === true);
23056
- const hasCreatableSelect = flatFields.some((f) => f.type === "select" && f.creatable === true);
23057
- const hasSelectCombobox = hasMultiSelect || hasCreatableSelect;
23058
- const hasSelect = flatFields.some(
23059
- (f) => f.type === "select" && f.multiple !== true && f.creatable !== true
23060
- );
23061
- const hasMarkdown = hasFieldType(schema.fields, "markdown");
23062
- const hasRichtext = hasFieldType(schema.fields, "richtext");
23063
- const hasTextarea = hasFieldType(schema.fields, "text");
23064
- const hasSeparator = hasFieldType(schema.fields, "separator");
23065
- const hasRelationship = hasFieldType(schema.fields, "relationship");
23066
- const hasTabsField = cardGroups.some((group2) => analyzeGroup(group2.fields).hasTabsField);
23067
- const hasList = hasFieldType(schema.fields, "list");
23068
- const hasNestedList = cardGroups.some(
23069
- (g) => analyzeGroup(g.fields).listFieldsWithNested.length > 0
23070
- );
23071
- const hasNestedObjectList = cardGroups.some(
23072
- (group2) => analyzeGroup(group2.fields).hasNestedObjectList
23073
- );
23074
- const hasSimpleList = hasList && hasSimpleListField(allFormFields);
23075
- const tabIconNames = collectTabIconNames(allFormFields);
23076
- const allRelFields = [];
23077
- for (const g of cardGroups) {
23078
- const a = analyzeGroup(g.fields);
23079
- for (const rf of a.relFields) {
23080
- if (!allRelFields.some((e) => e.relationship === rf.relationship)) {
23081
- allRelFields.push(rf);
23045
+ const inputFreeFieldTypes = /* @__PURE__ */ new Set([
23046
+ "boolean",
23047
+ "image",
23048
+ "video",
23049
+ "media",
23050
+ "gallery",
23051
+ "icon",
23052
+ "date",
23053
+ "select",
23054
+ "richtext",
23055
+ "markdown",
23056
+ "text",
23057
+ "relationship",
23058
+ "list",
23059
+ "separator",
23060
+ "tabs"
23061
+ ]);
23062
+ const formControlFreeFieldTypes = /* @__PURE__ */ new Set(["separator", "tabs"]);
23063
+ const cardArtifacts = cardGroups.map((group2) => {
23064
+ const analysis = analyzeGroup(group2.fields);
23065
+ const groupFlatFields = group2.flatFields;
23066
+ const creatableSelectFields = groupFlatFields.filter(
23067
+ (field) => field.type === "select" && field.creatable === true
23068
+ );
23069
+ const hasCreatableSelect = creatableSelectFields.length > 0;
23070
+ const hasMultiSelect = analysis.multiSelectFields.length > 0;
23071
+ const hasRelationship = analysis.relFields.length > 0;
23072
+ const hasSelectCombobox = hasRelationship || hasMultiSelect || hasCreatableSelect;
23073
+ const hasSelect = groupFlatFields.some(
23074
+ (field) => field.type === "select" && field.multiple !== true && field.creatable !== true
23075
+ );
23076
+ const hasIconPostfix = hasRenderedIconPostfix(group2.fields);
23077
+ const hasNestedList = analysis.listFieldsWithNested.length > 0;
23078
+ const hasInput = analysis.listFieldsWithNested.some(
23079
+ (field) => field.fields?.some(
23080
+ (nestedField) => !["boolean", "image", "video", "media"].includes(nestedField.type)
23081
+ )
23082
+ ) || groupFlatFields.some(
23083
+ (field) => !field.primaryKey && !field.hidden && !inputFreeFieldTypes.has(field.type)
23084
+ );
23085
+ const hasFormControls = groupFlatFields.some((field) => {
23086
+ if (field.primaryKey || field.hidden) return false;
23087
+ if (field.hasIcon && !["group", "section", "tabs", "separator"].includes(field.type)) {
23088
+ return true;
23082
23089
  }
23090
+ if (field.type === "list" && (!field.fields || field.fields.length === 0)) return false;
23091
+ return !formControlFreeFieldTypes.has(field.type);
23092
+ }) || hasIconPostfix;
23093
+ const groupUiImports = buildUiImports({
23094
+ hasBoolean: hasFieldType(group2.fields, "boolean"),
23095
+ hasTextarea: hasFieldType(group2.fields, "text"),
23096
+ hasImage: hasFieldType(group2.fields, "image"),
23097
+ hasVideo: hasFieldType(group2.fields, "video"),
23098
+ hasMedia: hasFieldType(group2.fields, "media"),
23099
+ hasGallery: hasFieldType(group2.fields, "gallery"),
23100
+ hasIcon: hasFieldType(group2.fields, "icon"),
23101
+ hasIconPostfix,
23102
+ hasDate: hasFieldType(group2.fields, "date"),
23103
+ hasMarkdown: hasFieldType(group2.fields, "markdown"),
23104
+ hasRichtext: hasFieldType(group2.fields, "richtext"),
23105
+ hasSeparator: hasFieldType(group2.fields, "separator"),
23106
+ hasSelect,
23107
+ hasSelectCombobox,
23108
+ hasCreatableSelect,
23109
+ hasMultiSelect,
23110
+ hasTabsField: analysis.hasTabsField,
23111
+ hasRelationship,
23112
+ hasSimpleList: hasSimpleListField(group2.fields),
23113
+ hasNestedList,
23114
+ hasNestedObjectList: analysis.hasNestedObjectList,
23115
+ hasCardContent: true,
23116
+ hasSectionCardHeading: true,
23117
+ hasFormRoot: true,
23118
+ hasButton: true,
23119
+ hasFormControls,
23120
+ hasInput
23121
+ });
23122
+ const cardImportIndex = groupUiImports.findIndex(
23123
+ (value) => value.includes("from '@admin/components/ui/card'")
23124
+ );
23125
+ if (cardImportIndex !== -1) {
23126
+ const cardImportNames = [
23127
+ "Card",
23128
+ "CardContent",
23129
+ ...group2.description ? ["CardDescription"] : [],
23130
+ "CardFooter",
23131
+ "CardHeader",
23132
+ "CardTitle"
23133
+ ];
23134
+ groupUiImports[cardImportIndex] = renderSingleFormRenderer({
23135
+ kind: "renderSingleFormImportsTemplate",
23136
+ props: {
23137
+ map: cardImportNames.map((name) => ` ${name}`).join(",\n")
23138
+ }
23139
+ });
23083
23140
  }
23084
- }
23085
- const needsReact = allRelFields.length > 0 || hasNestedList || hasSelectCombobox;
23086
- const uiImports = buildUiImports({
23087
- hasBoolean,
23088
- hasTextarea,
23089
- hasImage,
23090
- hasVideo,
23091
- hasMedia,
23092
- hasGallery,
23093
- hasIcon,
23094
- hasIconPostfix,
23095
- hasDate,
23096
- hasMarkdown,
23097
- hasRichtext,
23098
- hasSeparator,
23099
- hasSelect,
23100
- hasSelectCombobox,
23101
- hasCreatableSelect,
23102
- hasMultiSelect,
23103
- hasTabsField,
23104
- hasRelationship,
23105
- hasSimpleList,
23106
- hasNestedList,
23107
- hasNestedObjectList
23108
- });
23109
- const cardImportIndex = uiImports.indexOf("import { Card } from '@admin/components/ui/card'");
23110
- if (cardImportIndex !== -1) {
23111
- uiImports.splice(cardImportIndex, 1);
23112
- }
23113
- const cardImportNames = [
23114
- "Card",
23115
- "CardContent",
23116
- ...cardGroups.some((group2) => group2.description) ? ["CardDescription"] : [],
23117
- "CardFooter",
23118
- "CardHeader",
23119
- "CardTitle"
23120
- ];
23121
- uiImports.push(
23122
- renderSingleFormRenderer({
23123
- kind: "renderSingleFormImportsTemplate",
23141
+ groupUiImports.push("import { Spinner } from '@admin/components/ui/spinner'");
23142
+ const lucideIcons = [];
23143
+ const addLucideIcons = (...icons) => {
23144
+ for (const icon of icons) {
23145
+ if (!lucideIcons.includes(icon)) lucideIcons.push(icon);
23146
+ }
23147
+ };
23148
+ addLucideIcons(...collectTabIconNames(group2.fields));
23149
+ if (hasSelectCombobox) addLucideIcons("Check", "ChevronsUpDown");
23150
+ if (hasCreatableSelect || hasNestedList) addLucideIcons("Plus");
23151
+ if (hasNestedList) addLucideIcons("X");
23152
+ const relationshipImports = Array.from(
23153
+ new Set(analysis.relFields.map((field) => field.relationship).filter(Boolean))
23154
+ ).map((relationship) => {
23155
+ const relationshipPlural = toPascalCase(pluralize(relationship || ""));
23156
+ return `import { use${relationshipPlural} } from '@admin/hooks/use-${relationship}'`;
23157
+ }).join("\n");
23158
+ const needsReact = hasRelationship || hasMultiSelect || hasCreatableSelect || analysis.listFieldsWithNested.length > 0;
23159
+ const hookImports = ["useForm"];
23160
+ if (hasNestedList) hookImports.unshift("useFieldArray");
23161
+ const actionTypeImports = [
23162
+ Singular,
23163
+ ...hasCreatableSelect ? [`${Singular}SelectOption`] : [],
23164
+ `${Singular}UpsertInput`
23165
+ ];
23166
+ const actionImports = [
23167
+ ...hasCreatableSelect ? [`create${Singular}SelectOption`, `get${Singular}SelectOptions`] : [],
23168
+ `upsert${Singular}`
23169
+ ];
23170
+ const cardImports = [
23171
+ needsReact ? "import * as React from 'react'" : "",
23172
+ "import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'",
23173
+ `import { useMutation, ${hasCreatableSelect ? "useQuery, " : ""}useQueryClient } from '@tanstack/react-query'`,
23174
+ lucideIcons.length > 0 ? `import { ${lucideIcons.join(", ")} } from 'lucide-react'` : "",
23175
+ `import { ${hookImports.join(", ")} } from 'react-hook-form'`,
23176
+ "import { toast } from 'sonner'",
23177
+ "import { z } from 'zod/v3'",
23178
+ analysis.hasTabsField ? "import { parseAsStringLiteral, useQueryState } from 'nuqs'" : "",
23179
+ hasSelectCombobox ? "import { cn } from '@admin/utils/shared/cn'" : "",
23180
+ relationshipImports,
23181
+ groupUiImports.join("\n"),
23182
+ `import type { ${actionTypeImports.join(",\n ")} } from '@admin/actions/${actionImportPath}'`,
23183
+ `import { ${actionImports.join(", ")} } from '@admin/actions/${actionImportPath}'`
23184
+ ].filter(Boolean).join("\n");
23185
+ const content2 = renderSingleFormRenderer({
23186
+ kind: "renderSingleFormCardModuleTemplate",
23124
23187
  props: {
23125
- map: cardImportNames.map((name) => ` ${name}`).join(",\n")
23188
+ imports: cardImports,
23189
+ content: generateCardComponent(group2, schema, analysis, flatFields)
23126
23190
  }
23127
- })
23128
- );
23129
- uiImports.push("import { Spinner } from '@admin/components/ui/spinner'");
23130
- const lucideIcons = [];
23131
- const addLucideIcons = (...icons) => {
23132
- for (const icon of icons) {
23133
- if (!lucideIcons.includes(icon)) lucideIcons.push(icon);
23134
- }
23135
- };
23136
- addLucideIcons(...tabIconNames);
23137
- if (hasRelationship || hasSelectCombobox) addLucideIcons("Check", "ChevronsUpDown");
23138
- if (hasCreatableSelect) addLucideIcons("Plus");
23139
- if (hasNestedList) {
23140
- addLucideIcons("Plus", "X");
23141
- }
23142
- const relHookImports = allRelFields.map((f) => {
23143
- const relPlural = toPascalCase(pluralize(f.relationship || ""));
23144
- return `import { use${relPlural} } from '@admin/hooks/use-${f.relationship}'`;
23145
- }).filter((v, i, a) => a.indexOf(v) === i).join("\n");
23146
- const cardComponents = cardGroups.map((group2) => {
23147
- const analysis = analyzeGroup(group2.fields);
23148
- return generateCardComponent(group2, schema, analysis, flatFields);
23191
+ });
23192
+ return {
23193
+ content: content2,
23194
+ fileName: `${toKebabCase(group2.componentName)}.tsx`,
23195
+ group: group2
23196
+ };
23149
23197
  });
23150
- const cardRenders = cardGroups.map((g) => ` <${g.componentName} initialData={initialData} />`).join("\n");
23198
+ const cardRenders = cardArtifacts.map(({ group: group2 }) => ` <${group2.componentName} initialData={initialData} />`).join("\n");
23151
23199
  const content = renderSingleFormRenderer({
23152
- kind: "renderSingleFormClientModuleTemplate",
23200
+ kind: "renderSingleFormEntryModuleTemplate",
23153
23201
  props: {
23154
- needsReactImport: needsReact ? "\nimport * as React from 'react'" : "",
23155
- hasCreatableSelectUseQuery: hasCreatableSelect ? "useQuery, " : "",
23156
- lucideIconsLucide: lucideIcons.length > 0 ? `
23157
- import { ${lucideIcons.join(", ")} } from 'lucide-react'` : "",
23158
- hasNestedListUseFieldArray: hasNestedList ? " useFieldArray," : "",
23159
- hasTabsFieldImport: hasTabsField ? "\nimport { parseAsStringLiteral, useQueryState } from 'nuqs'" : "",
23160
- hasRelationshipImport: hasRelationship || hasSelectCombobox ? "\nimport { cn } from '@admin/utils/shared/cn'" : "",
23161
- relHookImportsContent: relHookImports ? `${relHookImports}
23162
- ` : "",
23163
- join: uiImports.join("\n"),
23164
23202
  singular: Singular,
23165
- hasCreatableSelectContent: hasCreatableSelect ? `${Singular}SelectOption,
23166
- ` : "",
23167
23203
  actionImportPath,
23168
- hasCreatableSelectContentText: hasCreatableSelect ? `create${Singular}SelectOption, get${Singular}SelectOptions, ` : "",
23169
- joinText: cardComponents.join("\n\n"),
23204
+ cardImports: cardArtifacts.map(
23205
+ ({ fileName, group: group2 }) => `import { ${group2.componentName} } from './${fileName.slice(0, -4)}'`
23206
+ ).join("\n"),
23170
23207
  cardRenders
23171
23208
  }
23172
23209
  });
23173
23210
  return {
23174
- files: [createGeneratedFile(`${pagesDir}/${schema.name}/${schema.name}-form.tsx`, content)]
23211
+ files: [
23212
+ createGeneratedFile(`${pagesDir}/${schema.name}/${schema.name}-form.tsx`, content),
23213
+ ...cardArtifacts.map(
23214
+ ({ content: cardContent, fileName }) => createGeneratedFile(`${pagesDir}/${schema.name}/${fileName}`, cardContent)
23215
+ )
23216
+ ]
23175
23217
  };
23176
23218
  }
23177
23219