Skip to content

Commit

Permalink
feat(ui): expose onMount to CodeField (#10223)
Browse files Browse the repository at this point in the history
This is useful for modifying the monaco instance, e.g. to add external
types to the editor:

```tsx
<CodeField
        autoComplete={autoComplete}
        field={props}
        forceRender={forceRender}
        key={key}
        onMount={(editor, monaco) => {
          console.log('editor mounted')
          monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
            allowNonTsExtensions: true,
            moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
            paths: {
              payload: ['file:///node_modules/payload/index.d.ts'],
            },
            target: monaco.languages.typescript.ScriptTarget.ESNext,
            typeRoots: ['node_modules/@types', 'node_modules/payload'],
          })
          const run = async () => {
            const types = await fetch('https://unpkg.com/payload@latest/dist/index.d.ts')
            const typesText = await types.text()
            monaco.languages.typescript.typescriptDefaults.addExtraLib(
              typesText,
              'file:///node_modules/payload/index.d.ts',
            )
          }
          void run()
        }}
        path={path}
        permissions={permissions}
        readOnly={readOnly}
        renderedBlocks={renderedBlocks}
        schemaPath={schemaPath}
        validate={validate}
      />
```
  • Loading branch information
AlessioGr authored Dec 28, 2024
1 parent fabe541 commit 68a5f5c
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 6 deletions.
2 changes: 2 additions & 0 deletions packages/payload/src/admin/fields/Code.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { EditorProps } from '@monaco-editor/react'
import type { MarkOptional } from 'ts-essentials'

import type { CodeField, CodeFieldClient } from '../../fields/config/types.js'
Expand All @@ -20,6 +21,7 @@ type CodeFieldClientWithoutType = MarkOptional<CodeFieldClient, 'type'>

type CodeFieldBaseClientProps = {
readonly autoComplete?: string
readonly onMount?: EditorProps['onMount']
readonly path: string
readonly validate?: CodeFieldValidation
}
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/fields/Code/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const CodeFieldComponent: CodeFieldClientComponent = (props) => {
localized,
required,
},
onMount,
path,
readOnly,
validate,
Expand Down Expand Up @@ -84,6 +85,7 @@ const CodeFieldComponent: CodeFieldClientComponent = (props) => {
<CodeEditor
defaultLanguage={prismToMonacoLanguageMap[language] || language}
onChange={readOnly ? () => null : (val) => setValue(val)}
onMount={onMount}
options={editorOptions}
readOnly={readOnly}
value={(value as string) || ''}
Expand Down
85 changes: 79 additions & 6 deletions test/lexical-mdx/collections/Posts/CodeFields.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import type { CodeFieldClientProps } from 'payload'
import type { CodeFieldClient, CodeFieldClientProps } from 'payload'

import { CodeField, useFormFields } from '@payloadcms/ui'
import React, { useMemo } from 'react'
Expand All @@ -13,21 +13,57 @@ const languageKeyToMonacoLanguageMap = {
tsx: 'typescript',
}

export const Code: React.FC<CodeFieldClientProps> = ({ field }) => {
export const Code: React.FC<CodeFieldClientProps> = ({
autoComplete,
field,
forceRender,
path,
permissions,
readOnly,
renderedBlocks,
schemaPath,
validate,
}) => {
const languageField = useFormFields(([fields]) => fields['language'])

const language: string =
(languageField?.value as string) || (languageField.initialValue as string) || 'typescript'

const label = languages[language as keyof typeof languages]

const props: typeof field = useMemo(
const props: CodeFieldClient = useMemo<CodeFieldClient>(
() => ({
...field,
type: 'code',
admin: {
...field.admin,
components: field.admin?.components || {},
editorOptions: field.admin?.editorOptions || {},
description: 'test',
editorOptions: {
onMount: (editor, monaco) => {
// Set module resolution to NodeNext to enable autocompletion
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
allowNonTsExtensions: true,
module: monaco.languages.typescript.ModuleKind.ESNext,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
target: monaco.languages.typescript.ScriptTarget.ESNext,
typeRoots: ['node_modules/@types'],
})

monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
noSemanticValidation: false,
noSyntaxValidation: false,
})

const libUri = 'node_modules/@types/payload/index.d.ts'

const run = async () => {
const types = await fetch('https://unpkg.com/payload@latest/dist/index.d.ts')
const libSource = await types.text()
monaco.languages.typescript.typescriptDefaults.addExtraLib(libSource, libUri)
}
void run()
},
} as any,
label,
language: languageKeyToMonacoLanguageMap[language] || language,
},
Expand All @@ -37,5 +73,42 @@ export const Code: React.FC<CodeFieldClientProps> = ({ field }) => {

const key = `${field.name}-${language}-${label}`

return <CodeField field={props} key={key} />
return (
props && (
<CodeField
autoComplete={autoComplete}
field={props}
forceRender={forceRender}
key={key}
onMount={(editor, monaco) => {
console.log('editor mounted')
// Set module resolution to NodeNext to enable autocompletion
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
allowNonTsExtensions: true,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
paths: {
payload: ['file:///node_modules/payload/index.d.ts'],
},
target: monaco.languages.typescript.ScriptTarget.ESNext,
typeRoots: ['node_modules/@types', 'node_modules/payload'],
})
const run = async () => {
const types = await fetch('https://unpkg.com/payload@latest/dist/index.d.ts')
const typesText = await types.text()
monaco.languages.typescript.typescriptDefaults.addExtraLib(
typesText,
'file:///node_modules/payload/index.d.ts',
)
}
void run()
}}
path={path}
permissions={permissions}
readOnly={readOnly}
renderedBlocks={renderedBlocks}
schemaPath={schemaPath}
validate={validate}
/>
)
)
}

0 comments on commit 68a5f5c

Please sign in to comment.