diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 76087b2a2..70eab607d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -286,6 +286,8 @@ jobs: - group-by - folders - hooks + - lexical__collections___LexicalFullyFeatured + - lexical__collections__OnDemandForm - lexical__collections__Lexical__e2e__main - lexical__collections__Lexical__e2e__blocks - lexical__collections__Lexical__e2e__blocks#config.blockreferences.ts @@ -424,6 +426,8 @@ jobs: - group-by - folders - hooks + - lexical__collections___LexicalFullyFeatured + - lexical__collections__OnDemandForm - lexical__collections__Lexical__e2e__main - lexical__collections__Lexical__e2e__blocks - lexical__collections__Lexical__e2e__blocks#config.blockreferences.ts diff --git a/docs/rich-text/rendering-on-demand.mdx b/docs/rich-text/rendering-on-demand.mdx new file mode 100644 index 000000000..83af6318c --- /dev/null +++ b/docs/rich-text/rendering-on-demand.mdx @@ -0,0 +1,116 @@ +--- +title: Rendering On Demand +label: Rendering On Demand +order: 50 +desc: Rendering rich text on demand +keywords: lexical, rich text, editor, headless cms, render, rendering +--- + +Lexical in Payload is a **React Server Component (RSC)**. Historically that created three headaches: 1. You couldn't render the editor directly from the client. 2. Features like blocks, tables and link drawers require the server to know the shape of nested sub-fields at render time. If you tried to render on demand, the server didn't know those schemas. 3. The rich text field is designed to live inside a `Form`. For simple use cases, setting up a full form just to manage editor state was cumbersome. + +To simplify rendering richtext on demand, , that renders a Lexical editor while still covering the full feature set. On mount, it calls a server action to render the editor on the server using the new `render-field` server function. That server render gives Lexical everything it needs (including nested field schemas) and returns a ready-to-hydrate editor. + + + `RenderLexical` and the underlying `render-field` server function are + experimental and may change in minor releases. + + +## Inside an existing Form + +If you have an existing Form and want to render a richtext field within it, you can use the `RenderLexical` component like this: + +```tsx +'use client' + +import type { JSONFieldClientComponent } from 'payload' + +import { + buildEditorState, + RenderLexical, +} from '@payloadcms/richtext-lexical/client' + +import { lexicalFullyFeaturedSlug } from '../../slugs.js' + +export const Component: JSONFieldClientComponent = (args) => { + return ( + + ) +} +``` + +## Outside of a Form (you control state) + +```tsx +'use client' + +import type { DefaultTypedEditorState } from '@payloadcms/richtext-lexical' +import type { JSONFieldClientComponent } from 'payload' + +import { + buildEditorState, + RenderLexical, +} from '@payloadcms/richtext-lexical/client' +import React, { useState } from 'react' + +import { lexicalFullyFeaturedSlug } from '../../slugs.js' + +export const Component: JSONFieldClientComponent = (args) => { + // Manually manage the editor state + const [value, setValue] = useState(() => + buildEditorState({ text: 'state default' }), + ) + + const handleReset = React.useCallback(() => { + setValue(buildEditorState({ text: 'state default' })) + }, []) + + return ( +
+ + +
+ ) +} +``` + +## Choosing the schemaPath + +`schemaPath` tells the server which richText field to render. This gives the server the exact nested field schemas (blocks, relationship drawers, upload fields, tables, etc.). + +Format: + +- `collection..` +- `global..` + +Example (top level): `collection.posts.richText` + +Example (nested in a group/tab): `collection.posts.content.richText` + + + **Tip:** If your target editor lives deep in arrays/blocks and you're unsure of the exact path, you can define a **hidden top-level richText** purely as a "render anchor": + +```ts +{ + name: 'onDemandAnchor', + type: 'richText', + admin: { hidden: true } +} +``` + +Then use `schemaPath="collection.posts.onDemandAnchor"` + + diff --git a/package.json b/package.json index fb01ea8ee..591f7b6cc 100644 --- a/package.json +++ b/package.json @@ -147,8 +147,8 @@ "@types/jest": "29.5.12", "@types/minimist": "1.2.5", "@types/node": "22.15.30", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "@types/shelljs": "0.8.15", "chalk": "^4.1.2", "comment-json": "^4.2.3", @@ -175,8 +175,8 @@ "playwright": "1.54.1", "playwright-core": "1.54.1", "prettier": "3.5.3", - "react": "19.1.0", - "react-dom": "19.1.0", + "react": "19.1.1", + "react-dom": "19.1.1", "rimraf": "6.0.1", "sharp": "0.32.6", "shelljs": "0.8.5", @@ -184,7 +184,7 @@ "sort-package-json": "^2.10.0", "swc-plugin-transform-remove-imports": "4.0.4", "tempy": "1.0.1", - "tstyche": "^3.1.1", + "tstyche": "3.5.0", "tsx": "4.19.2", "turbo": "^2.5.4", "typescript": "5.7.3" diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json index f9c0a5417..4aac216c9 100644 --- a/packages/admin-bar/package.json +++ b/packages/admin-bar/package.json @@ -42,8 +42,8 @@ }, "devDependencies": { "@payloadcms/eslint-config": "workspace:*", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "payload": "workspace:*" }, "peerDependencies": { diff --git a/packages/live-preview-react/package.json b/packages/live-preview-react/package.json index f8f05f473..18f949293 100644 --- a/packages/live-preview-react/package.json +++ b/packages/live-preview-react/package.json @@ -46,8 +46,8 @@ }, "devDependencies": { "@payloadcms/eslint-config": "workspace:*", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "payload": "workspace:*" }, "peerDependencies": { diff --git a/packages/next/package.json b/packages/next/package.json index e2c44d9f9..165f168ae 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -120,10 +120,10 @@ "@next/eslint-plugin-next": "15.4.4", "@payloadcms/eslint-config": "workspace:*", "@types/busboy": "1.5.4", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "@types/uuid": "10.0.0", - "babel-plugin-react-compiler": "19.1.0-rc.2", + "babel-plugin-react-compiler": "19.1.0-rc.3", "esbuild": "0.25.5", "esbuild-sass-plugin": "3.3.1", "payload": "workspace:*", diff --git a/packages/next/src/utilities/handleServerFunctions.ts b/packages/next/src/utilities/handleServerFunctions.ts index 237e1a089..7c723333e 100644 --- a/packages/next/src/utilities/handleServerFunctions.ts +++ b/packages/next/src/utilities/handleServerFunctions.ts @@ -1,6 +1,6 @@ import type { ServerFunction, ServerFunctionHandler } from 'payload' -import { copyDataFromLocaleHandler } from '@payloadcms/ui/rsc' +import { _internal_renderFieldHandler, copyDataFromLocaleHandler } from '@payloadcms/ui/rsc' import { buildFormStateHandler } from '@payloadcms/ui/utilities/buildFormState' import { buildTableStateHandler } from '@payloadcms/ui/utilities/buildTableState' import { getFolderResultsComponentAndDataHandler } from '@payloadcms/ui/utilities/getFolderResultsComponentAndData' @@ -11,19 +11,26 @@ import { renderDocumentSlotsHandler } from '../views/Document/renderDocumentSlot import { renderListHandler } from '../views/List/handleServerFunction.js' import { initReq } from './initReq.js' -const serverFunctions: Record = { +const baseServerFunctions: Record> = { 'copy-data-from-locale': copyDataFromLocaleHandler, 'form-state': buildFormStateHandler, 'get-folder-results-component-and-data': getFolderResultsComponentAndDataHandler, 'render-document': renderDocumentHandler, 'render-document-slots': renderDocumentSlotsHandler, + 'render-field': _internal_renderFieldHandler, 'render-list': renderListHandler, 'schedule-publish': schedulePublishHandler, 'table-state': buildTableStateHandler, } export const handleServerFunctions: ServerFunctionHandler = async (args) => { - const { name: fnKey, args: fnArgs, config: configPromise, importMap } = args + const { + name: fnKey, + args: fnArgs, + config: configPromise, + importMap, + serverFunctions: extraServerFunctions, + } = args const { req } = await initReq({ configPromise, @@ -37,6 +44,11 @@ export const handleServerFunctions: ServerFunctionHandler = async (args) => { req, } + const serverFunctions = { + ...baseServerFunctions, + ...(extraServerFunctions || {}), + } + const fn = serverFunctions[fnKey] if (!fn) { diff --git a/packages/payload/src/admin/fields/Row.ts b/packages/payload/src/admin/fields/Row.ts index 6ca2e7264..3e27e3ee0 100644 --- a/packages/payload/src/admin/fields/Row.ts +++ b/packages/payload/src/admin/fields/Row.ts @@ -2,6 +2,7 @@ import type { MarkOptional } from 'ts-essentials' import type { RowField, RowFieldClient } from '../../fields/config/types.js' import type { + ClientComponentProps, ClientFieldBase, FieldClientComponent, FieldPaths, @@ -21,9 +22,7 @@ import type { type RowFieldClientWithoutType = MarkOptional -type RowFieldBaseClientProps = { - readonly forceRender?: boolean -} & Omit +type RowFieldBaseClientProps = Omit & Pick export type RowFieldClientProps = Omit, 'path'> & RowFieldBaseClientProps diff --git a/packages/payload/src/admin/forms/Field.ts b/packages/payload/src/admin/forms/Field.ts index cba2f61fd..8826df4f8 100644 --- a/packages/payload/src/admin/forms/Field.ts +++ b/packages/payload/src/admin/forms/Field.ts @@ -21,6 +21,13 @@ export type ClientFieldWithOptionalType = MarkOptional export type ClientComponentProps = { customComponents?: FormField['customComponents'] field: ClientBlock | ClientField | ClientTab + /** + * Controls the rendering behavior of the fields, i.e. defers rendering until they intersect with the viewport using the Intersection Observer API. + * + * If true, the fields will be rendered immediately, rather than waiting for them to intersect with the viewport. + * + * If a number is provided, will immediately render fields _up to that index_. + */ forceRender?: boolean permissions?: SanitizedFieldPermissions readOnly?: boolean diff --git a/packages/payload/src/admin/functions/index.ts b/packages/payload/src/admin/functions/index.ts index 0a9b07f3b..f6fb7ce06 100644 --- a/packages/payload/src/admin/functions/index.ts +++ b/packages/payload/src/admin/functions/index.ts @@ -36,6 +36,31 @@ export type ServerFunctionHandler = ( args: { config: Promise | SanitizedConfig importMap: ImportMap + /** + * A map of server function names to their implementations. These are + * registered alongside the base server functions and can be called + * using the useServerFunctions() hook. + * + * @example + * const { serverFunction } = useServerFunctions() + * + * const callServerFunction = useCallback(() => { + * + * async function call() { + * const result = (await serverFunction({ + * name: 'record-key', + * args: { + * // Your args + * }, + * })) + * + * // Do someting with the result + * } + * + * void call() + * }, [serverFunction]) + */ + serverFunctions?: Record> } & ServerFunctionClientArgs, ) => Promise diff --git a/packages/plugin-cloud-storage/package.json b/packages/plugin-cloud-storage/package.json index f2da63935..ecbbb35af 100644 --- a/packages/plugin-cloud-storage/package.json +++ b/packages/plugin-cloud-storage/package.json @@ -65,8 +65,8 @@ }, "devDependencies": { "@types/find-node-modules": "^2.1.2", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "payload": "workspace:*" }, "peerDependencies": { diff --git a/packages/plugin-form-builder/package.json b/packages/plugin-form-builder/package.json index f4981911c..2cd6ece43 100644 --- a/packages/plugin-form-builder/package.json +++ b/packages/plugin-form-builder/package.json @@ -68,8 +68,8 @@ "devDependencies": { "@payloadcms/eslint-config": "workspace:*", "@types/escape-html": "^1.0.4", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", "payload": "workspace:*" diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index 09cd5be0a..95468e188 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -65,8 +65,8 @@ }, "devDependencies": { "@payloadcms/eslint-config": "workspace:*", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "payload": "workspace:*" }, "peerDependencies": { diff --git a/packages/plugin-sentry/package.json b/packages/plugin-sentry/package.json index 9e0651839..a9d378177 100644 --- a/packages/plugin-sentry/package.json +++ b/packages/plugin-sentry/package.json @@ -59,8 +59,8 @@ }, "devDependencies": { "@payloadcms/eslint-config": "workspace:*", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "payload": "workspace:*" }, "peerDependencies": { diff --git a/packages/plugin-seo/package.json b/packages/plugin-seo/package.json index d163f157c..45e36e0b7 100644 --- a/packages/plugin-seo/package.json +++ b/packages/plugin-seo/package.json @@ -74,8 +74,8 @@ "devDependencies": { "@payloadcms/eslint-config": "workspace:*", "@payloadcms/next": "workspace:*", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "payload": "workspace:*" }, "peerDependencies": { diff --git a/packages/plugin-stripe/package.json b/packages/plugin-stripe/package.json index 6c12b95a5..2144dc999 100644 --- a/packages/plugin-stripe/package.json +++ b/packages/plugin-stripe/package.json @@ -72,8 +72,8 @@ "@payloadcms/eslint-config": "workspace:*", "@payloadcms/next": "workspace:*", "@types/lodash.get": "^4.4.7", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "@types/uuid": "10.0.0", "payload": "workspace:*" }, diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index 062edc9a0..8dd31c968 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -404,9 +404,9 @@ "@types/escape-html": "1.0.4", "@types/json-schema": "7.0.15", "@types/node": "22.15.30", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", - "babel-plugin-react-compiler": "19.1.0-rc.2", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", + "babel-plugin-react-compiler": "19.1.0-rc.3", "babel-plugin-transform-remove-imports": "^1.8.0", "esbuild": "0.25.5", "esbuild-sass-plugin": "3.3.1", diff --git a/packages/richtext-lexical/src/exports/client/index.ts b/packages/richtext-lexical/src/exports/client/index.ts index f605b0883..b450e3e68 100644 --- a/packages/richtext-lexical/src/exports/client/index.ts +++ b/packages/richtext-lexical/src/exports/client/index.ts @@ -150,3 +150,6 @@ export { BlockEditButton } from '../../features/blocks/client/component/componen export { BlockRemoveButton } from '../../features/blocks/client/component/components/BlockRemoveButton.js' export { useBlockComponentContext } from '../../features/blocks/client/component/BlockContent.js' export { getRestPopulateFn } from '../../features/converters/utilities/restPopulateFn.js' + +export { RenderLexical } from '../../field/RenderLexical/index.js' +export { buildEditorState } from '../../utilities/buildEditorState.js' diff --git a/packages/richtext-lexical/src/field/RenderLexical/index.tsx b/packages/richtext-lexical/src/field/RenderLexical/index.tsx new file mode 100644 index 000000000..5901f3816 --- /dev/null +++ b/packages/richtext-lexical/src/field/RenderLexical/index.tsx @@ -0,0 +1,127 @@ +'use client' +import type { RichTextField } from 'payload' + +import { + FieldContext, + FieldPathContext, + type FieldType, + type RenderFieldServerFnArgs, + ServerFunctionsContext, + type ServerFunctionsContextType, + ShimmerEffect, + useServerFunctions, +} from '@payloadcms/ui' +import React, { useCallback, useEffect, useRef } from 'react' + +import type { DefaultTypedEditorState } from '../../nodeTypes.js' + +/** + * Utility to render a lexical editor on the client. + * + * @experimental - may break in minor releases + * @todo - replace this with a general utility that works for all fields. Maybe merge with packages/ui/src/forms/RenderFields/RenderField.tsx + */ +export const RenderLexical: React.FC< + /** + * If value or setValue, or both, is provided, this component will manage its own value. + * If neither is passed, it will rely on the parent form to manage the value. + */ + { + /** + * Override the loading state while the field component is being fetched and rendered. + */ + Loading?: React.ReactElement + + setValue?: FieldType['setValue'] + value?: FieldType['value'] + } & RenderFieldServerFnArgs +> = (args) => { + const { field, initialValue, Loading, path, schemaPath, setValue, value } = args + const [Component, setComponent] = React.useState(null) + const serverFunctionContext = useServerFunctions() + const { _internal_renderField } = serverFunctionContext + + const [entityType, entitySlug] = schemaPath.split('.') + + const fieldPath = path ?? (field && 'name' in field ? field?.name : '') ?? '' + + const renderLexical = useCallback(() => { + async function render() { + const { Field } = await _internal_renderField({ + field: { + ...((field as RichTextField) || {}), + type: 'richText', + admin: { + hidden: false, + }, + }, + initialValue: initialValue ?? undefined, + path, + schemaPath, + }) + + setComponent(Field) + } + void render() + }, [_internal_renderField, schemaPath, path, field, initialValue]) + + const mounted = useRef(false) + + useEffect(() => { + if (mounted.current) { + return + } + mounted.current = true + void renderLexical() + }, [renderLexical]) + + if (!Component) { + return typeof Loading !== 'undefined' ? Loading : + } + + /** + * By default, the lexical will make form state requests (e.g. to get drawer fields), passing in the arguments + * of the current field. However, we need to override those arguments to get it to make requests based on the + * *target* field. The server only knows the schema map of the target field. + */ + const adjustedServerFunctionContext: ServerFunctionsContextType = { + ...serverFunctionContext, + getFormState: async (getFormStateArgs) => { + return serverFunctionContext.getFormState({ + ...getFormStateArgs, + collectionSlug: entityType === 'collection' ? entitySlug : undefined, + globalSlug: entityType === 'global' ? entitySlug : undefined, + }) + }, + } + + if (typeof value === 'undefined' && !setValue) { + return ( + + + {Component} + + + ) + } + + const fieldValue: FieldType = { + disabled: false, + formInitializing: false, + formProcessing: false, + formSubmitted: false, + initialValue: value, + path: fieldPath, + setValue: setValue ?? (() => undefined), + showError: false, + value, + } + + return ( + + + {Component} + + + ) +} diff --git a/packages/richtext-lexical/src/index.ts b/packages/richtext-lexical/src/index.ts index ef0ebb3ff..a5ddd3354 100644 --- a/packages/richtext-lexical/src/index.ts +++ b/packages/richtext-lexical/src/index.ts @@ -814,6 +814,7 @@ export function lexicalEditor(args?: LexicalEditorProps): LexicalRichTextAdapter properties: { type: { type: 'string', + tsType: 'any', }, version: { type: 'integer', @@ -1055,10 +1056,12 @@ export { populate } from './populateGraphQL/populate.js' export type { LexicalEditorProps, LexicalFieldAdminProps, LexicalRichTextAdapter } from './types.js' +export { buildEditorState } from './utilities/buildEditorState.js' export { createServerFeature } from './utilities/createServerFeature.js' -export { editorConfigFactory } from './utilities/editorConfigFactory.js' +export { editorConfigFactory } from './utilities/editorConfigFactory.js' export type { FieldsDrawerProps } from './utilities/fieldsDrawer/Drawer.js' + export { extractPropsFromJSXPropsString } from './utilities/jsx/extractPropsFromJSXPropsString.js' export { @@ -1067,5 +1070,4 @@ export { objectToFrontmatter, propsToJSXString, } from './utilities/jsx/jsx.js' - export { upgradeLexicalData } from './utilities/upgradeLexicalData/index.js' diff --git a/packages/richtext-lexical/src/nodeTypes.ts b/packages/richtext-lexical/src/nodeTypes.ts index 277bbc34c..878cd2ffa 100644 --- a/packages/richtext-lexical/src/nodeTypes.ts +++ b/packages/richtext-lexical/src/nodeTypes.ts @@ -78,9 +78,17 @@ type RecursiveNodes = type DecrementDepth = [0, 0, 1, 2, 3, 4][N] +/** + * Alternative type to `SerializedEditorState` that automatically types your nodes + * more strictly, narrowing down nodes based on the `type` without having to manually + * type-cast. + */ export type TypedEditorState = SerializedEditorState> +/** + * All node types included by default in a lexical editor without configuration. + */ export type DefaultNodeTypes = | SerializedAutoLinkNode //| SerializedBlockNode // Not included by default @@ -97,5 +105,12 @@ export type DefaultNodeTypes = | SerializedTextNode | SerializedUploadNode -export type DefaultTypedEditorState = - TypedEditorState +/** + * Like `TypedEditorState` but includes all default node types. + * You can pass *additional* node types as a generic parameter. + */ +export type DefaultTypedEditorState< + TAdditionalNodeTypes extends null | SerializedLexicalNode = null, +> = [TAdditionalNodeTypes] extends null + ? TypedEditorState + : TypedEditorState> diff --git a/packages/richtext-lexical/src/utilities/buildEditorState.ts b/packages/richtext-lexical/src/utilities/buildEditorState.ts new file mode 100644 index 000000000..d2788ac3a --- /dev/null +++ b/packages/richtext-lexical/src/utilities/buildEditorState.ts @@ -0,0 +1,99 @@ +import type { SerializedLexicalNode } from 'lexical' + +import type { DefaultTypedEditorState, TypedEditorState } from '../nodeTypes.js' + +export function buildEditorState(args: { + nodes?: DefaultTypedEditorState['root']['children'] + text?: string +}): DefaultTypedEditorState + +export function buildEditorState(args: { + // If you pass children typed for a specific schema T, the return is TypedEditorState + nodes?: TypedEditorState['root']['children'] + text?: string +}): TypedEditorState + +/** + * Helper to build lexical editor state JSON from text and/or nodes. + * + * @param nodes - The nodes to include in the editor state. If you pass the `text` argument, this will append your nodes after the first paragraph node. + * @param text - The text content to include in the editor state. This will create a paragraph node with a text node for you and set that as the first node. + * @returns The constructed editor state JSON. + * + * @example + * + * just passing text: + * + * ```ts + * const editorState = buildEditorState({ text: 'Hello world' }) // result typed as DefaultTypedEditorState + * ``` + * + * @example + * + * passing nodes: + * + * ```ts + * const editorState = // result typed as TypedEditorState (or TypedEditorState) + * buildEditorState({ // or just buildEditorState if you *only* want to allow block nodes + * nodes: [ + * { + * type: 'block', + * fields: { + * id: 'id', + * blockName: 'Cool block', + * blockType: 'myBlock', + * }, + * format: 'left', + * version: 1, + * } + * ], + * }) + * ``` + */ +export function buildEditorState({ + nodes, + text, +}: { + nodes?: DefaultTypedEditorState['root']['children'] | TypedEditorState['root']['children'] + text?: string +}): DefaultTypedEditorState | TypedEditorState { + const editorJSON: DefaultTypedEditorState = { + root: { + type: 'root', + children: [], + direction: 'ltr', + format: '', + indent: 0, + version: 1, + }, + } + + if (text) { + editorJSON.root.children.push({ + type: 'paragraph', + children: [ + { + type: 'text', + detail: 0, + format: 0, + mode: 'normal', + style: '', + text, + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + textFormat: 0, + textStyle: '', + version: 1, + }) + } + + if (nodes?.length) { + editorJSON.root.children.push(...(nodes as any)) + } + + return editorJSON +} diff --git a/packages/richtext-slate/package.json b/packages/richtext-slate/package.json index d8a7d9005..a8510f721 100644 --- a/packages/richtext-slate/package.json +++ b/packages/richtext-slate/package.json @@ -67,8 +67,8 @@ "@payloadcms/eslint-config": "workspace:*", "@types/is-hotkey": "^0.1.10", "@types/node": "22.15.30", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "payload": "workspace:*" }, "peerDependencies": { diff --git a/packages/translations/package.json b/packages/translations/package.json index 4e5324252..f890555f3 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -60,8 +60,8 @@ "devDependencies": { "@payloadcms/eslint-config": "workspace:*", "@swc/core": "1.11.29", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "dotenv": "16.4.7", "prettier": "3.5.3", "typescript": "5.7.3" diff --git a/packages/ui/package.json b/packages/ui/package.json index 03ced2c66..25bb540a4 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -168,10 +168,10 @@ "@babel/preset-typescript": "7.27.1", "@hyrious/esbuild-plugin-commonjs": "0.2.6", "@payloadcms/eslint-config": "workspace:*", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "@types/uuid": "10.0.0", - "babel-plugin-react-compiler": "19.1.0-rc.2", + "babel-plugin-react-compiler": "19.1.0-rc.3", "esbuild": "0.25.5", "esbuild-sass-plugin": "3.3.1", "payload": "workspace:*" diff --git a/packages/ui/src/elements/RenderIfInViewport/index.tsx b/packages/ui/src/elements/RenderIfInViewport/index.tsx index a5c4e2ffb..0ab9b7061 100644 --- a/packages/ui/src/elements/RenderIfInViewport/index.tsx +++ b/packages/ui/src/elements/RenderIfInViewport/index.tsx @@ -1,13 +1,16 @@ 'use client' +import type { ClientComponentProps } from 'payload' + import React from 'react' import { useIntersect } from '../../hooks/useIntersect.js' -export const RenderIfInViewport: React.FC<{ - children: React.ReactNode - className?: string - forceRender?: boolean -}> = ({ children, className, forceRender }) => { +export const RenderIfInViewport: React.FC< + { + children: React.ReactNode + className?: string + } & Pick +> = ({ children, className, forceRender }) => { const [hasRendered, setHasRendered] = React.useState(Boolean(forceRender)) const [intersectionRef, entry] = useIntersect( { diff --git a/packages/ui/src/exports/client/index.ts b/packages/ui/src/exports/client/index.ts index 83670e0c4..53935cc27 100644 --- a/packages/ui/src/exports/client/index.ts +++ b/packages/ui/src/exports/client/index.ts @@ -236,12 +236,13 @@ export type { FieldAction } from '../../forms/Form/types.js' export { fieldReducer } from '../../forms/Form/fieldReducer.js' export { NullifyLocaleField } from '../../forms/NullifyField/index.js' export { RenderFields } from '../../forms/RenderFields/index.js' + export { RowLabel, type RowLabelProps } from '../../forms/RowLabel/index.js' export { RowLabelProvider, useRowLabel } from '../../forms/RowLabel/Context/index.js' export { FormSubmit } from '../../forms/Submit/index.js' export { WatchChildErrors } from '../../forms/WatchChildErrors/index.js' -export { useField } from '../../forms/useField/index.js' +export { FieldContext, useField } from '../../forms/useField/index.js' export type { FieldType, Options } from '../../forms/useField/types.js' export { withCondition } from '../../forms/withCondition/index.js' @@ -288,6 +289,8 @@ export { Warning as WarningIcon } from '../../providers/ToastContainer/icons/War export { type RenderDocumentResult, type RenderDocumentServerFunction, + ServerFunctionsContext, + type ServerFunctionsContextType, ServerFunctionsProvider, useServerFunctions, } from '../../providers/ServerFunctions/index.js' @@ -408,3 +411,7 @@ export { parseSearchParams } from '../../utilities/parseSearchParams.js' export { FieldDiffLabel } from '../../elements/FieldDiffLabel/index.js' export { FieldDiffContainer } from '../../elements/FieldDiffContainer/index.js' export { formatTimeToNow } from '../../utilities/formatDocTitle/formatDateTitle.js' +export type { + RenderFieldServerFnArgs, + RenderFieldServerFnReturnType, +} from '../../forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.js' diff --git a/packages/ui/src/exports/rsc/index.ts b/packages/ui/src/exports/rsc/index.ts index 4fbddd9ab..5839db847 100644 --- a/packages/ui/src/exports/rsc/index.ts +++ b/packages/ui/src/exports/rsc/index.ts @@ -3,6 +3,7 @@ export { FieldDiffLabel } from '../../elements/FieldDiffLabel/index.js' export { FolderTableCell } from '../../elements/FolderView/Cell/index.server.js' export { FolderField } from '../../elements/FolderView/FolderField/index.server.js' export { getHTMLDiffComponents } from '../../elements/HTMLDiff/index.js' +export { _internal_renderFieldHandler } from '../../forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.js' export { File } from '../../graphics/File/index.js' export { CheckIcon } from '../../icons/Check/index.js' export { copyDataFromLocaleHandler } from '../../utilities/copyDataFromLocale.js' diff --git a/packages/ui/src/fields/Array/ArrayRow.tsx b/packages/ui/src/fields/Array/ArrayRow.tsx index 1cc5fe11f..128327736 100644 --- a/packages/ui/src/fields/Array/ArrayRow.tsx +++ b/packages/ui/src/fields/Array/ArrayRow.tsx @@ -1,5 +1,11 @@ 'use client' -import type { ArrayField, ClientField, Row, SanitizedFieldPermissions } from 'payload' +import type { + ArrayField, + ClientComponentProps, + ClientField, + Row, + SanitizedFieldPermissions, +} from 'payload' import { getTranslation } from '@payloadcms/translations' import React from 'react' @@ -26,7 +32,6 @@ type ArrayRowProps = { readonly duplicateRow: (rowIndex: number) => void readonly errorCount: number readonly fields: ClientField[] - readonly forceRender?: boolean readonly hasMaxRows?: boolean readonly isLoading?: boolean readonly isSortable?: boolean @@ -43,7 +48,8 @@ type ArrayRowProps = { readonly rowIndex: number readonly schemaPath: string readonly setCollapse: (rowID: string, collapsed: boolean) => void -} & UseDraggableSortableReturn +} & Pick & + UseDraggableSortableReturn export const ArrayRow: React.FC = ({ addRow, diff --git a/packages/ui/src/fields/Tabs/index.tsx b/packages/ui/src/fields/Tabs/index.tsx index b8be36c96..38f86933d 100644 --- a/packages/ui/src/fields/Tabs/index.tsx +++ b/packages/ui/src/fields/Tabs/index.tsx @@ -1,5 +1,6 @@ 'use client' import type { + ClientComponentProps, ClientField, ClientTab, DocumentPreferences, @@ -249,7 +250,6 @@ export const TabsField = withCondition(TabsFieldComponent) type ActiveTabProps = { readonly description: StaticDescription readonly fields: ClientField[] - readonly forceRender?: boolean readonly hidden: boolean readonly label?: string readonly parentIndexPath: string @@ -258,7 +258,7 @@ type ActiveTabProps = { readonly path: string readonly permissions: SanitizedFieldPermissions readonly readOnly: boolean -} +} & Pick function TabContent({ description, diff --git a/packages/ui/src/forms/RenderFields/types.ts b/packages/ui/src/forms/RenderFields/types.ts index 743c9aedb..233de87ce 100644 --- a/packages/ui/src/forms/RenderFields/types.ts +++ b/packages/ui/src/forms/RenderFields/types.ts @@ -1,16 +1,8 @@ -import type { ClientField, SanitizedFieldPermissions } from 'payload' +import type { ClientComponentProps, ClientField, SanitizedFieldPermissions } from 'payload' export type RenderFieldsProps = { readonly className?: string readonly fields: ClientField[] - /** - * Controls the rendering behavior of the fields, i.e. defers rendering until they intersect with the viewport using the Intersection Observer API. - * - * If true, the fields will be rendered immediately, rather than waiting for them to intersect with the viewport. - * - * If a number is provided, will immediately render fields _up to that index_. - */ - readonly forceRender?: boolean readonly margins?: 'small' | false readonly parentIndexPath: string readonly parentPath: string @@ -21,4 +13,4 @@ export type RenderFieldsProps = { } | SanitizedFieldPermissions readonly readOnly?: boolean -} +} & Pick diff --git a/packages/ui/src/forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.ts b/packages/ui/src/forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.ts new file mode 100644 index 000000000..45ed1e948 --- /dev/null +++ b/packages/ui/src/forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.ts @@ -0,0 +1,119 @@ +import { deepMerge, type Field, type FieldState, type ServerFunction } from 'payload' + +import { getClientConfig } from '../../../utilities/getClientConfig.js' +import { getClientSchemaMap } from '../../../utilities/getClientSchemaMap.js' +import { getSchemaMap } from '../../../utilities/getSchemaMap.js' +import { renderField } from '../renderField.js' + +export type RenderFieldServerFnArgs = { + /** + * Override field config pulled from schemaPath lookup + */ + field?: Partial + /** + * Pass the value this field will receive when rendering it on the server. + * For richText, this helps provide initial state for sub-fields that are immediately rendered (like blocks) + * so that we can avoid multiple waterfall requests for each block that renders on the client. + */ + initialValue?: unknown + /** + * Path to the field to render + * @default field name + */ + path?: string + /** + * Dot schema path to a richText field declared in your config. + * Format: + * "collection.." + * "global.." + * + * Examples: + * "collection.posts.richText" + * "global.siteSettings.content" + */ + schemaPath: string +} +export type RenderFieldServerFnReturnType = {} & FieldState['customComponents'] + +/** + * @experimental - may break in minor releases + */ +export const _internal_renderFieldHandler: ServerFunction< + RenderFieldServerFnArgs, + Promise + // eslint-disable-next-line @typescript-eslint/require-await +> = async ({ field: fieldArg, initialValue, path, req, schemaPath }) => { + if (!req.user) { + throw new Error('Unauthorized') + } + + const [entityType, entitySlug, ...fieldPath] = schemaPath.split('.') + + const schemaMap = getSchemaMap({ + collectionSlug: entityType === 'collection' ? entitySlug : undefined, + config: req.payload.config, + globalSlug: entityType === 'global' ? entitySlug : undefined, + i18n: req.i18n, + }) + + // Provide client schema map as it would have been provided if the target editor field would have been rendered. + // For lexical, only then will it contain all the lexical-internal entries + const clientSchemaMap = getClientSchemaMap({ + collectionSlug: entityType === 'collection' ? entitySlug : undefined, + config: getClientConfig({ + config: req.payload.config, + i18n: req.i18n, + importMap: req.payload.importMap, + user: req.user, + }), + globalSlug: entityType === 'global' ? entitySlug : undefined, + i18n: req.i18n, + payload: req.payload, + schemaMap, + }) + + const targetField = schemaMap.get(`${entitySlug}.${fieldPath.join('.')}`) as Field | undefined + + if (!targetField) { + throw new Error(`Could not find target field at schemaPath: ${schemaPath}`) + } + + const field: Field = fieldArg ? deepMerge(targetField, fieldArg, { clone: false }) : targetField + + let data = {} + if (typeof initialValue !== 'undefined') { + if ('name' in field) { + data[field.name] = initialValue + } else { + data = initialValue + } + } + + const fieldState: FieldState = {} + renderField({ + clientFieldSchemaMap: clientSchemaMap, + collectionSlug: entityType === 'collection' && entitySlug ? entitySlug : '-', + data, + fieldConfig: field, + fieldSchemaMap: schemaMap, + fieldState, // TODO, + formState: {}, // TODO, + indexPath: '', + lastRenderedPath: '', + operation: 'create', + parentPath: '', + parentSchemaPath: '', + path: path ?? ('name' in field ? field.name : ''), + permissions: true, + preferences: { + fields: {}, + }, + previousFieldState: undefined, + renderAllFields: true, + req, + schemaPath: `${entitySlug}.${fieldPath.join('.')}`, + siblingData: data, + }) + + return fieldState.customComponents ?? {} +} diff --git a/packages/ui/src/forms/useField/index.tsx b/packages/ui/src/forms/useField/index.tsx index e0492ad9e..f87d7ad57 100644 --- a/packages/ui/src/forms/useField/index.tsx +++ b/packages/ui/src/forms/useField/index.tsx @@ -1,7 +1,7 @@ 'use client' import type { PayloadRequest } from 'payload' -import { useCallback, useMemo, useRef } from 'react' +import React, { useCallback, useMemo, useRef } from 'react' import type { UPDATE } from '../Form/types.js' import type { FieldType, Options } from './types.js' @@ -24,12 +24,7 @@ import { } from '../Form/context.js' import { useFieldPath } from '../RenderFields/context.js' -/** - * Get and set the value of a form field. - * - * @see https://payloadcms.com/docs/admin/react-hooks#usefield - */ -export const useField = (options?: Options): FieldType => { +const useFieldInForm = (options?: Options): FieldType => { const { disableFormData = false, hasRows, @@ -229,3 +224,50 @@ export const useField = (options?: Options): FieldType => { return result } + +/** + * Context to allow providing useField value for fields directly, if managed outside the Form + * + * @experimental + */ +export const FieldContext = React.createContext | undefined>(undefined) + +/** + * Get and set the value of a form field. + * + * @see https://payloadcms.com/docs/admin/react-hooks#usefield + */ +export const useField = (options?: Options): FieldType => { + const pathFromContext = useFieldPath() + + const fieldContext = React.use(FieldContext) as FieldType | undefined + + // Lock the mode on first render so hook order is stable forever. This ensures + // that hooks are called in the same order each time a component renders => should + // not break the rule of hooks. + const hasFieldContext = React.useRef(null) + if (hasFieldContext.current === null) { + // Use field context, if a field context exists **and** the path matches. If the path + // does not match, this could be the field context of a parent field => there likely is + // a nested
we should use instead => 'form' + const currentPath = options?.path || pathFromContext || options.potentiallyStalePath + + hasFieldContext.current = + fieldContext && currentPath && fieldContext.path === currentPath ? true : false + } + + if (hasFieldContext.current === true) { + if (!fieldContext) { + // Provider was removed after mount. That violates hook guarantees. + throw new Error('FieldContext was removed after mount. This breaks hook ordering.') + } + return fieldContext + } + + // We intentionally guard this hook call with a mode that is fixed on first render. + // The order is consistent across renders. Silence the linter’s false positive. + + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/rules-of-hooks + return useFieldInForm(options) +} diff --git a/packages/ui/src/providers/ServerFunctions/index.tsx b/packages/ui/src/providers/ServerFunctions/index.tsx index 91d391e51..d7e9a543f 100644 --- a/packages/ui/src/providers/ServerFunctions/index.tsx +++ b/packages/ui/src/providers/ServerFunctions/index.tsx @@ -16,6 +16,10 @@ import type { import React, { createContext, useCallback } from 'react' +import type { + RenderFieldServerFnArgs, + RenderFieldServerFnReturnType, +} from '../../forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.js' import type { buildFormStateHandler } from '../../utilities/buildFormState.js' import type { buildTableStateHandler } from '../../utilities/buildTableState.js' import type { CopyDataFromLocaleArgs } from '../../utilities/copyDataFromLocale.js' @@ -100,7 +104,9 @@ type GetFolderResultsComponentAndDataClient = ( } & Omit, ) => ReturnType -type ServerFunctionsContextType = { +type RenderFieldClient = (args: RenderFieldServerFnArgs) => Promise +export type ServerFunctionsContextType = { + _internal_renderField: RenderFieldClient copyDataFromLocale: CopyDataFromLocaleClient getDocumentSlots: GetDocumentSlots getFolderResultsComponentAndData: GetFolderResultsComponentAndDataClient @@ -278,9 +284,26 @@ export const ServerFunctionsProvider: React.FC<{ [serverFunction], ) + const _internal_renderField = useCallback( + async (args) => { + try { + const result = (await serverFunction({ + name: 'render-field', + args, + })) as RenderFieldServerFnReturnType + + return result + } catch (_err) { + console.error(_err) // eslint-disable-line no-console + } + }, + [serverFunction], + ) + return ( = 0.25.0 < 1' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 '@mongodb-js/saslprep@1.1.9': resolution: {integrity: sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==} @@ -5173,8 +5173,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5186,8 +5186,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5199,8 +5199,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5211,7 +5211,7 @@ packages: resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5220,7 +5220,7 @@ packages: resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5229,7 +5229,7 @@ packages: resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5239,8 +5239,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5251,7 +5251,7 @@ packages: resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5261,8 +5261,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5273,7 +5273,7 @@ packages: resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5283,8 +5283,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5296,8 +5296,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5309,8 +5309,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5322,8 +5322,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5335,8 +5335,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5348,8 +5348,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5360,7 +5360,7 @@ packages: resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5369,7 +5369,7 @@ packages: resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5378,7 +5378,7 @@ packages: resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5387,7 +5387,7 @@ packages: resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5396,7 +5396,7 @@ packages: resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5405,7 +5405,7 @@ packages: resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5414,7 +5414,7 @@ packages: resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5423,7 +5423,7 @@ packages: resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5432,7 +5432,7 @@ packages: resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5442,8 +5442,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -5706,13 +5706,13 @@ packages: resolution: {integrity: sha512-fE48R/mtb/bpc4/YVvKurKSAZ0ueUI5Ma0cVSr/Fi09rFdGwLRMcweM1UydREO/ILiyt8FezyZg7L20VAp4/TQ==} engines: {node: '>=8'} peerDependencies: - react: 19.1.0 + react: 19.1.1 '@sentry/react@8.37.1': resolution: {integrity: sha512-HanDqBFTgIUhUsYztAHhSti+sEhQ8YopAymXgnpqkJ7j1PLHXZgQAre6M4Uvixu28WS5MDHC1onnAIBDgYRDYw==} engines: {node: '>=14.18'} peerDependencies: - react: 19.1.0 + react: 19.1.1 '@sentry/replay@7.119.2': resolution: {integrity: sha512-nHDsBt0mlJXTWAHjzQdCzDbhV2fv8B62PPB5mu5SpI+G5h+ir3r5lR0lZZrMT8eurVowb/HnLXAs+XYVug3blg==} @@ -6207,8 +6207,8 @@ packages: '@testing-library/dom': ^10.0.0 '@types/react': ^18.0.0 || ^19.0.0 '@types/react-dom': ^18.0.0 || ^19.0.0 - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -6398,9 +6398,17 @@ packages: peerDependencies: '@types/react': ^19.0.0 + '@types/react-dom@19.1.9': + resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==} + peerDependencies: + '@types/react': ^19.0.0 + '@types/react-transition-group@4.4.11': resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==} + '@types/react@19.1.12': + resolution: {integrity: sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==} + '@types/react@19.1.8': resolution: {integrity: sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==} @@ -7055,8 +7063,8 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-react-compiler@19.1.0-rc.2: - resolution: {integrity: sha512-kSNA//p5fMO6ypG8EkEVPIqAjwIXm5tMjfD1XRPL/sRjYSbJ6UsvORfaeolNWnZ9n310aM0xJP7peW26BuCVzA==} + babel-plugin-react-compiler@19.1.0-rc.3: + resolution: {integrity: sha512-mjRn69WuTz4adL0bXGx8Rsyk1086zFJeKmes6aK0xPuK3aaXmDJdLHqwKKMrpm6KAI1MCoUK72d2VeqQbu8YIA==} babel-plugin-transform-remove-imports@1.8.0: resolution: {integrity: sha512-QdE5ZnIjON1pSgTPU8KzLnl/LEzdq9PLmZNuHgGKTx0LOI9PBrHBj0fz9uCg2CdssiTw7v/zVRYs8GJxbvhKnQ==} @@ -9674,7 +9682,7 @@ packages: lucide-react@0.378.0: resolution: {integrity: sha512-u6EPU8juLUk9ytRcyapkWI18epAv3RU+6+TC23ivjR0e+glWKBobFeSgRwOIJihzktILQuy6E0E80P2jVTDR5g==} peerDependencies: - react: 19.1.0 + react: 19.1.1 lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} @@ -10041,8 +10049,8 @@ packages: '@opentelemetry/api': ^1.1.0 '@playwright/test': ^1.41.2 babel-plugin-react-compiler: '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -10062,8 +10070,8 @@ packages: '@opentelemetry/api': ^1.1.0 '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -10610,7 +10618,7 @@ packages: prism-react-renderer@2.4.1: resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==} peerDependencies: - react: 19.1.0 + react: 19.1.1 prismjs@1.30.0: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} @@ -10687,35 +10695,35 @@ packages: react-datepicker@7.6.0: resolution: {integrity: sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==} peerDependencies: - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 - react-dom@19.1.0: - resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + react-dom@19.1.1: + resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} peerDependencies: - react: 19.1.0 + react: 19.1.1 react-error-boundary@3.1.4: resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} engines: {node: '>=10', npm: '>=6'} peerDependencies: - react: 19.1.0 + react: 19.1.1 react-error-boundary@4.1.2: resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} peerDependencies: - react: 19.1.0 + react: 19.1.1 react-hook-form@7.45.4: resolution: {integrity: sha512-HGDV1JOOBPZj10LB3+OZgfDBTn+IeEsNOKiq/cxbQAIbKaiJUe/KV8DBUzsx0Gx/7IG/orWqRRm736JwOfUSWQ==} engines: {node: '>=12.22.0'} peerDependencies: - react: 19.1.0 + react: 19.1.1 react-image-crop@10.1.8: resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} peerDependencies: - react: 19.1.0 + react: 19.1.1 react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -10735,7 +10743,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -10745,7 +10753,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -10753,15 +10761,15 @@ packages: react-select@5.9.0: resolution: {integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==} peerDependencies: - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 react-style-singleton@2.2.3: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -10769,11 +10777,11 @@ packages: react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 - react@19.1.0: - resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + react@19.1.1: + resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} engines: {node: '>=0.10.0'} read-cache@1.0.0: @@ -11341,8 +11349,8 @@ packages: slate-react@0.92.0: resolution: {integrity: sha512-xEDKu5RKw5f0N95l1UeNQnrB0Pxh4JPjpIZR/BVsMo0ININnLAknR99gLo46bl/Ffql4mr7LeaxQRoXxbFtJOQ==} peerDependencies: - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 slate: '>=0.65.3' slate@0.91.4: @@ -11373,8 +11381,8 @@ packages: sonner@1.7.2: resolution: {integrity: sha512-zMbseqjrOzQD1a93lxahm+qMGxWovdMxBlkTbbnZdNqVLt4j+amF9PQxUCL32WfztOFt9t9ADYkejAL3jF9iNA==} peerDependencies: - react: 19.1.0 - react-dom: 19.1.0 + react: 19.1.1 + react-dom: 19.1.1 sort-keys-length@1.0.1: resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==} @@ -11622,7 +11630,7 @@ packages: peerDependencies: '@babel/core': '*' babel-plugin-macros: '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@babel/core': optional: true @@ -11894,8 +11902,8 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tstyche@3.1.1: - resolution: {integrity: sha512-GB1GEApaoYHPREwbFuzx0D/dY3ohZdZ7tNbZJNjxoe3Xv1ibR6c+D8agOou6dYK3pOiSl1peaHCpbu9N40WQiw==} + tstyche@3.5.0: + resolution: {integrity: sha512-N4SUp/ZWaMGEcglpVFIzKez0GQEiBdfFDgcnqwv9O1mePZgos8N1cZCzNgGtPGo/w0ym04MjJcDnsw1sorEzgA==} engines: {node: '>=18.19'} hasBin: true peerDependencies: @@ -12143,7 +12151,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -12151,14 +12159,14 @@ packages: use-context-selector@2.0.0: resolution: {integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==} peerDependencies: - react: 19.1.0 + react: 19.1.1 scheduler: '>=0.19.0' use-isomorphic-layout-effect@1.2.0: resolution: {integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -12168,7 +12176,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 19.1.0 + react: 19.1.1 peerDependenciesMeta: '@types/react': optional: true @@ -14343,29 +14351,29 @@ snapshots: '@discoveryjs/json-ext@0.5.7': {} - '@dnd-kit/accessibility@3.1.0(react@19.1.0)': + '@dnd-kit/accessibility@3.1.0(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@dnd-kit/core@6.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@dnd-kit/accessibility': 3.1.0(react@19.1.0) - '@dnd-kit/utilities': 3.2.2(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@dnd-kit/accessibility': 3.1.0(react@19.1.1) + '@dnd-kit/utilities': 3.2.2(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@dnd-kit/utilities': 3.2.2(react@19.1.0) - react: 19.1.0 + '@dnd-kit/core': 6.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@dnd-kit/utilities': 3.2.2(react@19.1.1) + react: 19.1.1 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.1.0)': + '@dnd-kit/utilities@3.2.2(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 tslib: 2.8.1 '@drizzle-team/brocli@0.10.2': {} @@ -14430,19 +14438,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.1.8)(react@19.1.0)': + '@emotion/react@11.14.0(@types/react@19.1.12)(react@19.1.1)': dependencies: '@babel/runtime': 7.26.0 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.0) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.1) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.1.0 + react: 19.1.1 optionalDependencies: - '@types/react': 19.1.8 + '@types/react': 19.1.12 transitivePeerDependencies: - supports-color @@ -14458,9 +14466,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.1.0)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 '@emotion/utils@1.4.2': {} @@ -14826,23 +14834,23 @@ snapshots: '@eslint/core': 0.12.0 levn: 0.4.1 - '@faceless-ui/modal@3.0.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@faceless-ui/modal@3.0.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - react-transition-group: 4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@faceless-ui/scroll-info@2.0.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@faceless-ui/scroll-info@2.0.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@faceless-ui/window-info@3.0.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@faceless-ui/window-info@3.0.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) '@fastify/busboy@2.1.1': {} @@ -14864,32 +14872,32 @@ snapshots: '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 - '@floating-ui/react-dom@2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@floating-ui/react-dom@2.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@floating-ui/dom': 1.6.12 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@floating-ui/react-dom@2.1.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@floating-ui/react-dom@2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@floating-ui/dom': 1.7.4 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@floating-ui/react@0.27.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@floating-ui/react@0.27.16(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@floating-ui/react-dom': 2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@floating-ui/utils': 0.2.10 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) tabbable: 6.2.0 - '@floating-ui/react@0.27.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@floating-ui/react@0.27.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@floating-ui/react-dom': 2.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@floating-ui/utils': 0.2.8 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) tabbable: 6.2.0 '@floating-ui/utils@0.2.10': {} @@ -15416,7 +15424,7 @@ snapshots: lexical: 0.35.0 prismjs: 1.30.0 - '@lexical/devtools-core@0.35.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@lexical/devtools-core@0.35.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@lexical/html': 0.35.0 '@lexical/link': 0.35.0 @@ -15424,8 +15432,8 @@ snapshots: '@lexical/table': 0.35.0 '@lexical/utils': 0.35.0 lexical: 0.35.0 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) '@lexical/dragon@0.35.0': dependencies: @@ -15496,10 +15504,10 @@ snapshots: '@lexical/utils': 0.35.0 lexical: 0.35.0 - '@lexical/react@0.35.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(yjs@13.6.20)': + '@lexical/react@0.35.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(yjs@13.6.20)': dependencies: - '@floating-ui/react': 0.27.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@lexical/devtools-core': 0.35.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@floating-ui/react': 0.27.16(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@lexical/devtools-core': 0.35.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@lexical/dragon': 0.35.0 '@lexical/hashtag': 0.35.0 '@lexical/history': 0.35.0 @@ -15515,9 +15523,9 @@ snapshots: '@lexical/utils': 0.35.0 '@lexical/yjs': 0.35.0(yjs@13.6.20) lexical: 0.35.0 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - react-error-boundary: 3.1.4(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-error-boundary: 3.1.4(react@19.1.1) transitivePeerDependencies: - yjs @@ -15616,12 +15624,12 @@ snapshots: dependencies: state-local: 1.0.7 - '@monaco-editor/react@4.7.0(monaco-editor@0.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@monaco-editor/react@4.7.0(monaco-editor@0.52.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@monaco-editor/loader': 1.5.0 monaco-editor: 0.52.0 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) '@mongodb-js/saslprep@1.1.9': dependencies: @@ -16139,249 +16147,249 @@ snapshots: '@radix-ui/primitive@1.1.2': {} - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-checkbox@1.3.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-checkbox@1.3.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.8)(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-context@1.1.2(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-context@1.1.2(@types/react@19.1.8)(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-direction@1.1.1(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-direction@1.1.1(@types/react@19.1.8)(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-focus-guards@1.1.2(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-focus-guards@1.1.2(@types/react@19.1.8)(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-id@1.1.1(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-id@1.1.1(@types/react@19.1.8)(react@19.1.1)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-popper@1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-popper@1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@19.1.0) + '@floating-ui/react-dom': 2.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@19.1.1) '@radix-ui/rect': 1.1.1 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-select@2.2.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-select@2.2.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) aria-hidden: 1.2.6 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - react-remove-scroll: 2.7.1(@types/react@19.1.8)(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-remove-scroll: 2.7.1(@types/react@19.1.8)(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) - '@radix-ui/react-slot@1.2.3(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-slot@1.2.3(@types/react@19.1.8)(react@19.1.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.8)(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.8)(react@19.1.1)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.8)(react@19.1.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.8)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.8)(react@19.1.1)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.8)(react@19.1.1)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.8)(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-use-previous@1.1.1(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-use-previous@1.1.1(@types/react@19.1.8)(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.8)(react@19.1.1)': dependencies: '@radix-ui/rect': 1.1.1 - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-use-size@1.1.1(@types/react@19.1.8)(react@19.1.0)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.1.8)(react@19.1.1)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0) - react: 19.1.0 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.1) + react: 19.1.1 optionalDependencies: '@types/react': 19.1.8 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) @@ -16612,7 +16620,7 @@ snapshots: '@sentry/utils': 7.119.2 localforage: 1.10.0 - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4))(react@19.1.0)(webpack@5.96.1(@swc/core@1.11.29))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4))(react@19.1.1)(webpack@5.96.1(@swc/core@1.11.29))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -16622,13 +16630,13 @@ snapshots: '@sentry/core': 8.37.1 '@sentry/node': 8.37.1 '@sentry/opentelemetry': 8.37.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.27.0) - '@sentry/react': 8.37.1(react@19.1.0) + '@sentry/react': 8.37.1(react@19.1.1) '@sentry/types': 8.37.1 '@sentry/utils': 8.37.1 '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.11.29)) chalk: 3.0.0 - next: 15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) + next: 15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -16692,23 +16700,23 @@ snapshots: '@sentry/types': 8.37.1 '@sentry/utils': 8.37.1 - '@sentry/react@7.119.2(react@19.1.0)': + '@sentry/react@7.119.2(react@19.1.1)': dependencies: '@sentry/browser': 7.119.2 '@sentry/core': 7.119.2 '@sentry/types': 7.119.2 '@sentry/utils': 7.119.2 hoist-non-react-statics: 3.3.2 - react: 19.1.0 + react: 19.1.1 - '@sentry/react@8.37.1(react@19.1.0)': + '@sentry/react@8.37.1(react@19.1.1)': dependencies: '@sentry/browser': 8.37.1 '@sentry/core': 8.37.1 '@sentry/types': 8.37.1 '@sentry/utils': 8.37.1 hoist-non-react-statics: 3.3.2 - react: 19.1.0 + react: 19.1.1 '@sentry/replay@7.119.2': dependencies: @@ -17392,12 +17400,12 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/react@16.3.0(@testing-library/dom@10.4.0)(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@testing-library/react@16.3.0(@testing-library/dom@10.4.0)(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@babel/runtime': 7.26.0 '@testing-library/dom': 10.4.0 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 '@types/react-dom': 19.1.6(@types/react@19.1.8) @@ -17622,9 +17630,17 @@ snapshots: dependencies: '@types/react': 19.1.8 + '@types/react-dom@19.1.9(@types/react@19.1.12)': + dependencies: + '@types/react': 19.1.12 + '@types/react-transition-group@4.4.11': dependencies: - '@types/react': 19.1.8 + '@types/react': 19.1.12 + + '@types/react@19.1.12': + dependencies: + csstype: 3.1.3 '@types/react@19.1.8': dependencies: @@ -18464,9 +18480,9 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-react-compiler@19.1.0-rc.2: + babel-plugin-react-compiler@19.1.0-rc.3: dependencies: - '@babel/types': 7.26.7 + '@babel/types': 7.27.3 babel-plugin-transform-remove-imports@1.8.0(@babel/core@7.27.3): dependencies: @@ -20264,9 +20280,9 @@ snapshots: - encoding - supports-color - geist@1.4.2(next@15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4)): + geist@1.4.2(next@15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4)): dependencies: - next: 15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) + next: 15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4) gel@2.0.1: dependencies: @@ -21574,9 +21590,9 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@0.378.0(react@19.1.0): + lucide-react@0.378.0(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 lz-string@1.5.0: {} @@ -22051,15 +22067,15 @@ snapshots: transitivePeerDependencies: - supports-color - next-sitemap@4.2.3(next@15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4)): + next-sitemap@4.2.3(next@15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4)): dependencies: '@corex/deepmerge': 4.0.43 '@next/env': 13.5.11 fast-glob: 3.3.2 minimist: 1.2.8 - next: 15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) + next: 15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4) - next@15.2.3(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4): + next@15.2.3(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4): dependencies: '@next/env': 15.2.3 '@swc/counter': 0.1.3 @@ -22067,9 +22083,9 @@ snapshots: busboy: 1.6.0 caniuse-lite: 1.0.30001678 postcss: 8.4.31 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - styled-jsx: 5.1.6(@babel/core@7.27.3)(babel-plugin-macros@3.1.0)(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + styled-jsx: 5.1.6(@babel/core@7.27.3)(babel-plugin-macros@3.1.0)(react@19.1.1) optionalDependencies: '@next/swc-darwin-arm64': 15.2.3 '@next/swc-darwin-x64': 15.2.3 @@ -22081,14 +22097,14 @@ snapshots: '@next/swc-win32-x64-msvc': 15.2.3 '@opentelemetry/api': 1.9.0 '@playwright/test': 1.54.1 - babel-plugin-react-compiler: 19.1.0-rc.2 + babel-plugin-react-compiler: 19.1.0-rc.3 sass: 1.77.4 sharp: 0.33.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4): + next@15.2.3(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4): dependencies: '@next/env': 15.2.3 '@swc/counter': 0.1.3 @@ -22096,9 +22112,9 @@ snapshots: busboy: 1.6.0 caniuse-lite: 1.0.30001678 postcss: 8.4.31 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - styled-jsx: 5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + styled-jsx: 5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.1.1) optionalDependencies: '@next/swc-darwin-arm64': 15.2.3 '@next/swc-darwin-x64': 15.2.3 @@ -22116,15 +22132,15 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4): + next@15.4.4(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4): dependencies: '@next/env': 15.4.4 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001720 postcss: 8.4.31 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - styled-jsx: 5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + styled-jsx: 5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.1.1) optionalDependencies: '@next/swc-darwin-arm64': 15.4.4 '@next/swc-darwin-x64': 15.4.4 @@ -22142,15 +22158,15 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4): + next@15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4): dependencies: '@next/env': 15.4.4 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001720 postcss: 8.4.31 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - styled-jsx: 5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + styled-jsx: 5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.1.1) optionalDependencies: '@next/swc-darwin-arm64': 15.4.4 '@next/swc-darwin-x64': 15.4.4 @@ -22162,7 +22178,7 @@ snapshots: '@next/swc-win32-x64-msvc': 15.4.4 '@opentelemetry/api': 1.9.0 '@playwright/test': 1.54.1 - babel-plugin-react-compiler: 19.1.0-rc.2 + babel-plugin-react-compiler: 19.1.0-rc.3 sass: 1.77.4 sharp: 0.34.3 transitivePeerDependencies: @@ -22705,11 +22721,11 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - prism-react-renderer@2.4.1(react@19.1.0): + prism-react-renderer@2.4.1(react@19.1.1): dependencies: '@types/prismjs': 1.26.5 clsx: 2.1.1 - react: 19.1.0 + react: 19.1.1 prismjs@1.30.0: {} @@ -22775,36 +22791,36 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-datepicker@7.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + react-datepicker@7.6.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: - '@floating-ui/react': 0.27.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@floating-ui/react': 0.27.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) clsx: 2.1.1 date-fns: 3.6.0 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - react-dom@19.1.0(react@19.1.0): + react-dom@19.1.1(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 scheduler: 0.26.0 - react-error-boundary@3.1.4(react@19.1.0): + react-error-boundary@3.1.4(react@19.1.1): dependencies: '@babel/runtime': 7.26.0 - react: 19.1.0 + react: 19.1.1 - react-error-boundary@4.1.2(react@19.1.0): + react-error-boundary@4.1.2(react@19.1.1): dependencies: '@babel/runtime': 7.26.0 - react: 19.1.0 + react: 19.1.1 - react-hook-form@7.45.4(react@19.1.0): + react-hook-form@7.45.4(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 - react-image-crop@10.1.8(react@19.1.0): + react-image-crop@10.1.8(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 react-is@16.13.1: {} @@ -22814,60 +22830,60 @@ snapshots: react-refresh@0.17.0: {} - react-remove-scroll-bar@2.3.8(@types/react@19.1.8)(react@19.1.0): + react-remove-scroll-bar@2.3.8(@types/react@19.1.8)(react@19.1.1): dependencies: - react: 19.1.0 - react-style-singleton: 2.2.3(@types/react@19.1.8)(react@19.1.0) + react: 19.1.1 + react-style-singleton: 2.2.3(@types/react@19.1.8)(react@19.1.1) tslib: 2.8.1 optionalDependencies: '@types/react': 19.1.8 - react-remove-scroll@2.7.1(@types/react@19.1.8)(react@19.1.0): + react-remove-scroll@2.7.1(@types/react@19.1.8)(react@19.1.1): dependencies: - react: 19.1.0 - react-remove-scroll-bar: 2.3.8(@types/react@19.1.8)(react@19.1.0) - react-style-singleton: 2.2.3(@types/react@19.1.8)(react@19.1.0) + react: 19.1.1 + react-remove-scroll-bar: 2.3.8(@types/react@19.1.8)(react@19.1.1) + react-style-singleton: 2.2.3(@types/react@19.1.8)(react@19.1.1) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.1.8)(react@19.1.0) - use-sidecar: 1.1.3(@types/react@19.1.8)(react@19.1.0) + use-callback-ref: 1.3.3(@types/react@19.1.8)(react@19.1.1) + use-sidecar: 1.1.3(@types/react@19.1.8)(react@19.1.1) optionalDependencies: '@types/react': 19.1.8 - react-select@5.9.0(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + react-select@5.9.0(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: '@babel/runtime': 7.26.0 '@emotion/cache': 11.14.0 - '@emotion/react': 11.14.0(@types/react@19.1.8)(react@19.1.0) + '@emotion/react': 11.14.0(@types/react@19.1.12)(react@19.1.1) '@floating-ui/dom': 1.6.12 '@types/react-transition-group': 4.4.11 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - react-transition-group: 4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - use-isomorphic-layout-effect: 1.2.0(@types/react@19.1.8)(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + use-isomorphic-layout-effect: 1.2.0(@types/react@19.1.12)(react@19.1.1) transitivePeerDependencies: - '@types/react' - supports-color - react-style-singleton@2.2.3(@types/react@19.1.8)(react@19.1.0): + react-style-singleton@2.2.3(@types/react@19.1.8)(react@19.1.1): dependencies: get-nonce: 1.0.1 - react: 19.1.0 + react: 19.1.1 tslib: 2.8.1 optionalDependencies: '@types/react': 19.1.8 - react-transition-group@4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + react-transition-group@4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: '@babel/runtime': 7.26.0 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - react@19.1.0: {} + react@19.1.1: {} read-cache@1.0.0: dependencies: @@ -23546,7 +23562,7 @@ snapshots: is-plain-object: 5.0.0 slate: 0.91.4 - slate-react@0.92.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(slate@0.91.4): + slate-react@0.92.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(slate@0.91.4): dependencies: '@juggle/resize-observer': 3.4.0 '@types/is-hotkey': 0.1.10 @@ -23555,8 +23571,8 @@ snapshots: is-hotkey: 0.1.8 is-plain-object: 5.0.0 lodash: 4.17.21 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) scroll-into-view-if-needed: 2.2.31 slate: 0.91.4 tiny-invariant: 1.0.6 @@ -23592,10 +23608,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + sonner@1.7.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) sort-keys-length@1.0.1: dependencies: @@ -23879,18 +23895,18 @@ snapshots: stubs@3.0.0: {} - styled-jsx@5.1.6(@babel/core@7.27.3)(babel-plugin-macros@3.1.0)(react@19.1.0): + styled-jsx@5.1.6(@babel/core@7.27.3)(babel-plugin-macros@3.1.0)(react@19.1.1): dependencies: client-only: 0.0.1 - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@babel/core': 7.27.3 babel-plugin-macros: 3.1.0 - styled-jsx@5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.1.0): + styled-jsx@5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.1.1): dependencies: client-only: 0.0.1 - react: 19.1.0 + react: 19.1.1 optionalDependencies: '@babel/core': 7.27.4 babel-plugin-macros: 3.1.0 @@ -24191,7 +24207,7 @@ snapshots: tslib@2.8.1: {} - tstyche@3.1.1(typescript@5.7.3): + tstyche@3.5.0(typescript@5.7.3): optionalDependencies: typescript: 5.7.3 @@ -24451,42 +24467,42 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - uploadthing@7.3.0(next@15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4))(tailwindcss@3.4.17): + uploadthing@7.3.0(next@15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4))(tailwindcss@3.4.17): dependencies: '@effect/platform': 0.69.8(effect@3.10.3) '@uploadthing/mime-types': 0.3.2 '@uploadthing/shared': 7.1.1 effect: 3.10.3 optionalDependencies: - next: 15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) + next: 15.4.4(@opentelemetry/api@1.9.0)(@playwright/test@1.54.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.77.4) tailwindcss: 3.4.17 uri-js@4.4.1: dependencies: punycode: 2.3.1 - use-callback-ref@1.3.3(@types/react@19.1.8)(react@19.1.0): + use-callback-ref@1.3.3(@types/react@19.1.8)(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 tslib: 2.8.1 optionalDependencies: '@types/react': 19.1.8 - use-context-selector@2.0.0(react@19.1.0)(scheduler@0.25.0): + use-context-selector@2.0.0(react@19.1.1)(scheduler@0.25.0): dependencies: - react: 19.1.0 + react: 19.1.1 scheduler: 0.25.0 - use-isomorphic-layout-effect@1.2.0(@types/react@19.1.8)(react@19.1.0): + use-isomorphic-layout-effect@1.2.0(@types/react@19.1.12)(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 optionalDependencies: - '@types/react': 19.1.8 + '@types/react': 19.1.12 - use-sidecar@1.1.3(@types/react@19.1.8)(react@19.1.0): + use-sidecar@1.1.3(@types/react@19.1.8)(react@19.1.1): dependencies: detect-node-es: 1.1.0 - react: 19.1.0 + react: 19.1.1 tslib: 2.8.1 optionalDependencies: '@types/react': 19.1.8 diff --git a/templates/website/src/blocks/Form/Component.tsx b/templates/website/src/blocks/Form/Component.tsx index b0b5d38cb..428265ed7 100644 --- a/templates/website/src/blocks/Form/Component.tsx +++ b/templates/website/src/blocks/Form/Component.tsx @@ -6,7 +6,7 @@ import React, { useCallback, useState } from 'react' import { useForm, FormProvider } from 'react-hook-form' import RichText from '@/components/RichText' import { Button } from '@/components/ui/button' -import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical' +import type { DefaultTypedEditorState } from '@payloadcms/richtext-lexical' import { fields } from './fields' import { getClientSideURL } from '@/utilities/getURL' @@ -16,7 +16,7 @@ export type FormBlockType = { blockType?: 'formBlock' enableIntro: boolean form: FormType - introContent?: SerializedEditorState + introContent?: DefaultTypedEditorState } export const FormBlock: React.FC< diff --git a/templates/website/src/blocks/Form/Message/index.tsx b/templates/website/src/blocks/Form/Message/index.tsx index 5924cf95f..85f5f7534 100644 --- a/templates/website/src/blocks/Form/Message/index.tsx +++ b/templates/website/src/blocks/Form/Message/index.tsx @@ -2,9 +2,9 @@ import RichText from '@/components/RichText' import React from 'react' import { Width } from '../Width' -import { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical' +import { DefaultTypedEditorState } from '@payloadcms/richtext-lexical' -export const Message: React.FC<{ message: SerializedEditorState }> = ({ message }) => { +export const Message: React.FC<{ message: DefaultTypedEditorState }> = ({ message }) => { return ( {message && } diff --git a/templates/website/src/blocks/RelatedPosts/Component.tsx b/templates/website/src/blocks/RelatedPosts/Component.tsx index 8d8c9798b..976c0cb1b 100644 --- a/templates/website/src/blocks/RelatedPosts/Component.tsx +++ b/templates/website/src/blocks/RelatedPosts/Component.tsx @@ -5,12 +5,12 @@ import RichText from '@/components/RichText' import type { Post } from '@/payload-types' import { Card } from '../../components/Card' -import { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical' +import { DefaultTypedEditorState } from '@payloadcms/richtext-lexical' export type RelatedPostsProps = { className?: string docs?: Post[] - introContent?: SerializedEditorState + introContent?: DefaultTypedEditorState } export const RelatedPosts: React.FC = (props) => { diff --git a/templates/website/src/payload-types.ts b/templates/website/src/payload-types.ts index 8f61fdc6c..1196d9c68 100644 --- a/templates/website/src/payload-types.ts +++ b/templates/website/src/payload-types.ts @@ -154,7 +154,7 @@ export interface Page { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -219,7 +219,7 @@ export interface Post { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -265,7 +265,7 @@ export interface Media { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -401,7 +401,7 @@ export interface CallToActionBlock { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -452,7 +452,7 @@ export interface ContentBlock { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -509,7 +509,7 @@ export interface ArchiveBlock { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -545,7 +545,7 @@ export interface FormBlock { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -602,7 +602,7 @@ export interface Form { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -685,7 +685,7 @@ export interface Form { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -717,7 +717,7 @@ export interface Form { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -1682,7 +1682,7 @@ export interface BannerBlock { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; diff --git a/templates/with-vercel-website/src/blocks/Form/Component.tsx b/templates/with-vercel-website/src/blocks/Form/Component.tsx index b0b5d38cb..428265ed7 100644 --- a/templates/with-vercel-website/src/blocks/Form/Component.tsx +++ b/templates/with-vercel-website/src/blocks/Form/Component.tsx @@ -6,7 +6,7 @@ import React, { useCallback, useState } from 'react' import { useForm, FormProvider } from 'react-hook-form' import RichText from '@/components/RichText' import { Button } from '@/components/ui/button' -import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical' +import type { DefaultTypedEditorState } from '@payloadcms/richtext-lexical' import { fields } from './fields' import { getClientSideURL } from '@/utilities/getURL' @@ -16,7 +16,7 @@ export type FormBlockType = { blockType?: 'formBlock' enableIntro: boolean form: FormType - introContent?: SerializedEditorState + introContent?: DefaultTypedEditorState } export const FormBlock: React.FC< diff --git a/templates/with-vercel-website/src/blocks/Form/Message/index.tsx b/templates/with-vercel-website/src/blocks/Form/Message/index.tsx index 5924cf95f..85f5f7534 100644 --- a/templates/with-vercel-website/src/blocks/Form/Message/index.tsx +++ b/templates/with-vercel-website/src/blocks/Form/Message/index.tsx @@ -2,9 +2,9 @@ import RichText from '@/components/RichText' import React from 'react' import { Width } from '../Width' -import { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical' +import { DefaultTypedEditorState } from '@payloadcms/richtext-lexical' -export const Message: React.FC<{ message: SerializedEditorState }> = ({ message }) => { +export const Message: React.FC<{ message: DefaultTypedEditorState }> = ({ message }) => { return ( {message && } diff --git a/templates/with-vercel-website/src/blocks/RelatedPosts/Component.tsx b/templates/with-vercel-website/src/blocks/RelatedPosts/Component.tsx index 8d8c9798b..976c0cb1b 100644 --- a/templates/with-vercel-website/src/blocks/RelatedPosts/Component.tsx +++ b/templates/with-vercel-website/src/blocks/RelatedPosts/Component.tsx @@ -5,12 +5,12 @@ import RichText from '@/components/RichText' import type { Post } from '@/payload-types' import { Card } from '../../components/Card' -import { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical' +import { DefaultTypedEditorState } from '@payloadcms/richtext-lexical' export type RelatedPostsProps = { className?: string docs?: Post[] - introContent?: SerializedEditorState + introContent?: DefaultTypedEditorState } export const RelatedPosts: React.FC = (props) => { diff --git a/test/access-control/config.ts b/test/access-control/config.ts index 3081766ca..d5901594f 100644 --- a/test/access-control/config.ts +++ b/test/access-control/config.ts @@ -4,11 +4,12 @@ const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) import type { FieldAccess } from 'payload' +import { buildEditorState } from '@payloadcms/richtext-lexical' + import type { Config, User } from './payload-types.js' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { devUser } from '../credentials.js' -import { textToLexicalJSON } from '../lexical/collections/LexicalLocalized/textToLexicalJSON.js' import { Auth } from './collections/Auth/index.js' import { Disabled } from './collections/Disabled/index.js' import { Hooks } from './collections/hooks/index.js' @@ -718,33 +719,33 @@ export default buildConfigWithDefaults( await payload.create({ collection: 'regression1', data: { - richText4: textToLexicalJSON({ text: 'Text1' }), - array: [{ art: textToLexicalJSON({ text: 'Text2' }) }], - arrayWithAccessFalse: [{ richText6: textToLexicalJSON({ text: 'Text3' }) }], + richText4: buildEditorState({ text: 'Text1' }), + array: [{ art: buildEditorState({ text: 'Text2' }) }], + arrayWithAccessFalse: [{ richText6: buildEditorState({ text: 'Text3' }) }], group1: { text: 'Text4', - richText1: textToLexicalJSON({ text: 'Text5' }), + richText1: buildEditorState({ text: 'Text5' }), }, blocks: [ { blockType: 'myBlock3', - richText7: textToLexicalJSON({ text: 'Text6' }), + richText7: buildEditorState({ text: 'Text6' }), blockName: 'My Block 1', }, ], blocks3: [ { blockType: 'myBlock2', - richText5: textToLexicalJSON({ text: 'Text7' }), + richText5: buildEditorState({ text: 'Text7' }), blockName: 'My Block 2', }, ], tab1: { - richText2: textToLexicalJSON({ text: 'Text8' }), + richText2: buildEditorState({ text: 'Text8' }), blocks2: [ { blockType: 'myBlock', - richText3: textToLexicalJSON({ text: 'Text9' }), + richText3: buildEditorState({ text: 'Text9' }), blockName: 'My Block 3', }, ], @@ -757,12 +758,12 @@ export default buildConfigWithDefaults( data: { array: [ { - richText2: textToLexicalJSON({ text: 'Text1' }), + richText2: buildEditorState({ text: 'Text1' }), }, ], group: { text: 'Text2', - richText1: textToLexicalJSON({ text: 'Text3' }), + richText1: buildEditorState({ text: 'Text3' }), }, }, }) diff --git a/test/lexical/baseConfig.ts b/test/lexical/baseConfig.ts index fcb2c040e..cffae565f 100644 --- a/test/lexical/baseConfig.ts +++ b/test/lexical/baseConfig.ts @@ -17,6 +17,8 @@ import { LexicalLocalizedFields } from './collections/LexicalLocalized/index.js' import { LexicalMigrateFields } from './collections/LexicalMigrate/index.js' import { LexicalObjectReferenceBugCollection } from './collections/LexicalObjectReferenceBug/index.js' import { LexicalRelationshipsFields } from './collections/LexicalRelationships/index.js' +import { OnDemandForm } from './collections/OnDemandForm/index.js' +import { OnDemandOutsideForm } from './collections/OnDemandOutsideForm/index.js' import RichTextFields from './collections/RichText/index.js' import TextFields from './collections/Text/index.js' import Uploads from './collections/Upload/index.js' @@ -46,6 +48,8 @@ export const baseConfig: Partial = { TextFields, Uploads, ArrayFields, + OnDemandForm, + OnDemandOutsideForm, ], globals: [TabsWithRichText], diff --git a/test/lexical/collections/LexicalLocalized/textToLexicalJSON.ts b/test/lexical/collections/LexicalLocalized/textToLexicalJSON.ts deleted file mode 100644 index e7a2ae467..000000000 --- a/test/lexical/collections/LexicalLocalized/textToLexicalJSON.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { SerializedRelationshipNode } from '@payloadcms/richtext-lexical' -import type { - SerializedEditorState, - SerializedParagraphNode, - SerializedTextNode, -} from '@payloadcms/richtext-lexical/lexical' - -import { lexicalLocalizedFieldsSlug } from '../../slugs.js' - -export function textToLexicalJSON({ - text, - lexicalLocalizedRelID, -}: { - lexicalLocalizedRelID?: number | string - text: string -}): any { - const editorJSON: SerializedEditorState = { - root: { - type: 'root', - format: '', - indent: 0, - version: 1, - direction: 'ltr', - children: [ - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text, - type: 'text', - version: 1, - } as SerializedTextNode, - ], - direction: 'ltr', - format: '', - indent: 0, - textFormat: 0, - type: 'paragraph', - textStyle: '', - version: 1, - } as SerializedParagraphNode, - ], - }, - } - - if (lexicalLocalizedRelID) { - editorJSON.root.children.push({ - format: '', - type: 'relationship', - version: 2, - relationTo: lexicalLocalizedFieldsSlug, - value: lexicalLocalizedRelID, - } as SerializedRelationshipNode) - } - - return editorJSON -} diff --git a/test/lexical/collections/OnDemandForm/Component.tsx b/test/lexical/collections/OnDemandForm/Component.tsx new file mode 100644 index 000000000..9d4167169 --- /dev/null +++ b/test/lexical/collections/OnDemandForm/Component.tsx @@ -0,0 +1,20 @@ +'use client' + +import type { JSONFieldClientComponent } from 'payload' + +import { buildEditorState, RenderLexical } from '@payloadcms/richtext-lexical/client' + +import { lexicalFullyFeaturedSlug } from '../../slugs.js' + +export const Component: JSONFieldClientComponent = () => { + return ( +
+ Fully-Featured Component: + +
+ ) +} diff --git a/test/lexical/collections/OnDemandForm/e2e.spec.ts b/test/lexical/collections/OnDemandForm/e2e.spec.ts new file mode 100644 index 000000000..19c877133 --- /dev/null +++ b/test/lexical/collections/OnDemandForm/e2e.spec.ts @@ -0,0 +1,106 @@ +import { expect, test } from '@playwright/test' +import { AdminUrlUtil } from 'helpers/adminUrlUtil.js' +import { reInitializeDB } from 'helpers/reInitializeDB.js' +import path from 'path' +import { fileURLToPath } from 'url' + +import { ensureCompilationIsDone, saveDocAndAssert } from '../../../helpers.js' +import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js' +import { TEST_TIMEOUT_LONG } from '../../../playwright.config.js' +import { LexicalHelpers } from '../utils.js' +const filename = fileURLToPath(import.meta.url) +const currentFolder = path.dirname(filename) +const dirname = path.resolve(currentFolder, '../../') + +const { beforeAll, beforeEach, describe } = test + +const { serverURL } = await initPayloadE2ENoConfig({ + dirname, +}) + +describe('Lexical On Demand', () => { + let lexical: LexicalHelpers + beforeAll(async ({ browser }, testInfo) => { + testInfo.setTimeout(TEST_TIMEOUT_LONG) + process.env.SEED_IN_CONFIG_ONINIT = 'false' // Makes it so the payload config onInit seed is not run. Otherwise, the seed would be run unnecessarily twice for the initial test run - once for beforeEach and once for onInit + const page = await browser.newPage() + await ensureCompilationIsDone({ page, serverURL }) + await page.close() + }) + + describe('within form', () => { + beforeEach(async ({ page }) => { + await reInitializeDB({ + serverURL, + snapshotKey: 'lexicalTest', + uploadsDir: [path.resolve(dirname, './collections/Upload/uploads')], + }) + const url = new AdminUrlUtil(serverURL, 'OnDemandForm') + lexical = new LexicalHelpers(page) + await page.goto(url.create) + await lexical.editor.first().focus() + }) + test('lexical is rendered on demand within form', async ({ page }) => { + await page.keyboard.type('Hello') + + await saveDocAndAssert(page) + await page.reload() + + const paragraph = lexical.editor.locator('> p') + await expect(paragraph).toHaveText('Hello') + }) + + test('on-demand editor within form can render nested fields', async () => { + await lexical.slashCommand('table', false) + + await expect(lexical.drawer.locator('#field-rows')).toHaveValue('5') + await expect(lexical.drawer.locator('#field-columns')).toHaveValue('5') + }) + }) + + describe('outside form', () => { + beforeEach(async ({ page }) => { + await reInitializeDB({ + serverURL, + snapshotKey: 'lexicalTest', + uploadsDir: [path.resolve(dirname, './collections/Upload/uploads')], + }) + const url = new AdminUrlUtil(serverURL, 'OnDemandOutsideForm') + lexical = new LexicalHelpers(page) + await page.goto(url.create) + await lexical.editor.first().focus() + }) + test('lexical is rendered on demand outside form', async ({ page }) => { + await page.keyboard.type('Hello') + + const paragraph = lexical.editor.locator('> p') + await expect(paragraph).toHaveText('Hellostate default') + + await saveDocAndAssert(page) + await page.reload() + + const paragraphAfterSave = lexical.editor.locator('> p') + await expect(paragraphAfterSave).not.toHaveText('Hellostate default') // Outside Form => Not Saved + }) + + test('lexical value can be controlled outside form', async ({ page }) => { + await page.keyboard.type('Hello') + + const paragraph = lexical.editor.locator('> p') + await expect(paragraph).toHaveText('Hellostate default') + + // Click button with text + const button = page.getByRole('button', { name: 'Reset Editor State' }) + await button.click() + + await expect(paragraph).toHaveText('state default') + }) + + test('on-demand editor outside form can render nested fields', async () => { + await lexical.slashCommand('table', false) + + await expect(lexical.drawer.locator('#field-rows')).toHaveValue('5') + await expect(lexical.drawer.locator('#field-columns')).toHaveValue('5') + }) + }) +}) diff --git a/test/lexical/collections/OnDemandForm/index.ts b/test/lexical/collections/OnDemandForm/index.ts new file mode 100644 index 000000000..aef8a4240 --- /dev/null +++ b/test/lexical/collections/OnDemandForm/index.ts @@ -0,0 +1,16 @@ +import type { CollectionConfig } from 'payload' + +export const OnDemandForm: CollectionConfig = { + slug: 'OnDemandForm', + fields: [ + { + name: 'json', + type: 'json', + admin: { + components: { + Field: './collections/OnDemandForm/Component.js#Component', + }, + }, + }, + ], +} diff --git a/test/lexical/collections/OnDemandOutsideForm/Component.tsx b/test/lexical/collections/OnDemandOutsideForm/Component.tsx new file mode 100644 index 000000000..d5a251661 --- /dev/null +++ b/test/lexical/collections/OnDemandOutsideForm/Component.tsx @@ -0,0 +1,35 @@ +'use client' + +import type { DefaultTypedEditorState } from '@payloadcms/richtext-lexical' +import type { JSONFieldClientComponent } from 'payload' + +import { buildEditorState, RenderLexical } from '@payloadcms/richtext-lexical/client' +import React, { useState } from 'react' + +import { lexicalFullyFeaturedSlug } from '../../slugs.js' + +export const Component: JSONFieldClientComponent = () => { + const [value, setValue] = useState(() => + buildEditorState({ text: 'state default' }), + ) + + const handleReset = React.useCallback(() => { + setValue(buildEditorState({ text: 'state default' })) + }, []) + + return ( +
+ Default Component: + + +
+ ) +} diff --git a/test/lexical/collections/OnDemandOutsideForm/index.ts b/test/lexical/collections/OnDemandOutsideForm/index.ts new file mode 100644 index 000000000..d16c0d12b --- /dev/null +++ b/test/lexical/collections/OnDemandOutsideForm/index.ts @@ -0,0 +1,16 @@ +import type { CollectionConfig } from 'payload' + +export const OnDemandOutsideForm: CollectionConfig = { + slug: 'OnDemandOutsideForm', + fields: [ + { + name: 'json', + type: 'json', + admin: { + components: { + Field: './collections/OnDemandOutsideForm/Component.js#Component', + }, + }, + }, + ], +} diff --git a/test/lexical/collections/_LexicalFullyFeatured/e2e.spec.ts b/test/lexical/collections/_LexicalFullyFeatured/e2e.spec.ts index 946240713..19fdf13b9 100644 --- a/test/lexical/collections/_LexicalFullyFeatured/e2e.spec.ts +++ b/test/lexical/collections/_LexicalFullyFeatured/e2e.spec.ts @@ -16,7 +16,7 @@ const dirname = path.resolve(currentFolder, '../../') const { beforeAll, beforeEach, describe } = test // Unlike the other suites, this one runs in parallel, as they run on the `lexical-fully-featured/create` URL and are "pure" tests -test.describe.configure({ mode: 'parallel' }) +//test.describe.configure({ mode: 'parallel' }) const { serverURL } = await initPayloadE2ENoConfig({ dirname, @@ -46,6 +46,7 @@ describe('Lexical Fully Featured', () => { page, }) => { await lexical.slashCommand('block') + await expect(lexical.editor.locator('.lexical-block')).toBeVisible() await lexical.slashCommand('relationship') await lexical.drawer.locator('.list-drawer__header').getByText('Create New').click() await lexical.save('drawer') diff --git a/test/lexical/collections/utils.ts b/test/lexical/collections/utils.ts index 867acafee..29d16f55e 100644 --- a/test/lexical/collections/utils.ts +++ b/test/lexical/collections/utils.ts @@ -1,6 +1,7 @@ import type { Locator, Page } from 'playwright' import { expect } from '@playwright/test' +import { wait } from 'payload/shared' export class LexicalHelpers { page: Page @@ -98,16 +99,20 @@ export class LexicalHelpers { async slashCommand( // prettier-ignore - command: 'block' | 'check' | 'code' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' |'h6' | 'inline' - | 'link' | 'ordered' | 'paragraph' | 'quote' | 'relationship' | 'unordered' | 'upload', + command: ('block' | 'check' | 'code' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' |'h6' | 'inline' + | 'link' | 'ordered' | 'paragraph' | 'quote' | 'relationship' | 'table' | 'unordered'|'upload') | ({} & string), + expectMenuToClose = true, ) { await this.page.keyboard.press(`/`) const slashMenuPopover = this.page.locator('#slash-menu .slash-menu-popup') await expect(slashMenuPopover).toBeVisible() await this.page.keyboard.type(command) + await wait(200) await this.page.keyboard.press(`Enter`) - await expect(slashMenuPopover).toBeHidden() + if (expectMenuToClose) { + await expect(slashMenuPopover).toBeHidden() + } } get decorator() { diff --git a/test/lexical/lexical.int.spec.ts b/test/lexical/lexical.int.spec.ts index 1c06b3c94..ec8980272 100644 --- a/test/lexical/lexical.int.spec.ts +++ b/test/lexical/lexical.int.spec.ts @@ -1,16 +1,17 @@ -/* eslint-disable jest/no-conditional-in-test */ -import type { - SerializedBlockNode, - SerializedLinkNode, - SerializedRelationshipNode, - SerializedUploadNode, -} from '@payloadcms/richtext-lexical' import type { SerializedEditorState, SerializedParagraphNode, } from '@payloadcms/richtext-lexical/lexical' import type { PaginatedDocs, Payload } from 'payload' +/* eslint-disable jest/no-conditional-in-test */ +import { + buildEditorState, + type SerializedBlockNode, + type SerializedLinkNode, + type SerializedRelationshipNode, + type SerializedUploadNode, +} from '@payloadcms/richtext-lexical' import path from 'path' import { fileURLToPath } from 'url' @@ -21,7 +22,6 @@ import { initPayloadInt } from '../helpers/initPayloadInt.js' import { NextRESTClient } from '../helpers/NextRESTClient.js' import { lexicalDocData } from './collections/Lexical/data.js' import { generateLexicalLocalizedRichText } from './collections/LexicalLocalized/generateLexicalRichText.js' -import { textToLexicalJSON } from './collections/LexicalLocalized/textToLexicalJSON.js' import { lexicalMigrateDocData } from './collections/LexicalMigrate/data.js' import { richTextDocData } from './collections/RichText/data.js' import { generateLexicalRichText } from './collections/RichText/generateLexicalRichText.js' @@ -655,7 +655,7 @@ describe('Lexical', () => { locale: 'en', data: { title: 'Localized Lexical hooks', - lexicalBlocksLocalized: textToLexicalJSON({ text: 'some text' }), + lexicalBlocksLocalized: buildEditorState({ text: 'some text' }), lexicalBlocksSubLocalized: generateLexicalLocalizedRichText( 'Shared text', 'English text in block', diff --git a/test/lexical/payload-types.ts b/test/lexical/payload-types.ts index 63f9ecc24..aba744f61 100644 --- a/test/lexical/payload-types.ts +++ b/test/lexical/payload-types.ts @@ -97,6 +97,8 @@ export interface Config { 'text-fields': TextField; uploads: Upload; 'array-fields': ArrayField; + OnDemandForm: OnDemandForm; + OnDemandOutsideForm: OnDemandOutsideForm; users: User; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -118,6 +120,8 @@ export interface Config { 'text-fields': TextFieldsSelect | TextFieldsSelect; uploads: UploadsSelect | UploadsSelect; 'array-fields': ArrayFieldsSelect | ArrayFieldsSelect; + OnDemandForm: OnDemandFormSelect | OnDemandFormSelect; + OnDemandOutsideForm: OnDemandOutsideFormSelect | OnDemandOutsideFormSelect; users: UsersSelect | UsersSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -169,7 +173,7 @@ export interface LexicalFullyFeatured { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -193,7 +197,7 @@ export interface LexicalLinkFeature { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -217,7 +221,7 @@ export interface LexicalJsxConverter { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -242,7 +246,7 @@ export interface LexicalField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -257,7 +261,7 @@ export interface LexicalField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -272,7 +276,7 @@ export interface LexicalField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -298,7 +302,7 @@ export interface LexicalMigrateField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -313,7 +317,7 @@ export interface LexicalMigrateField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -328,7 +332,7 @@ export interface LexicalMigrateField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -345,7 +349,7 @@ export interface LexicalMigrateField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -364,7 +368,7 @@ export interface LexicalMigrateField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -396,7 +400,7 @@ export interface LexicalLocalizedField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -414,7 +418,7 @@ export interface LexicalLocalizedField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -438,7 +442,7 @@ export interface LexicalObjectReferenceBug { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -453,7 +457,7 @@ export interface LexicalObjectReferenceBug { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -477,7 +481,7 @@ export interface LexicalInBlock { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -494,7 +498,7 @@ export interface LexicalInBlock { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -524,7 +528,7 @@ export interface LexicalAccessControl { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -548,7 +552,7 @@ export interface LexicalRelationshipField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -563,7 +567,7 @@ export interface LexicalRelationshipField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -588,7 +592,7 @@ export interface RichTextField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -607,7 +611,7 @@ export interface RichTextField { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -828,6 +832,42 @@ export interface ArrayField { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "OnDemandForm". + */ +export interface OnDemandForm { + id: string; + json?: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "OnDemandOutsideForm". + */ +export interface OnDemandOutsideForm { + id: string; + json?: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; + updatedAt: string; + createdAt: string; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -915,6 +955,14 @@ export interface PayloadLockedDocument { relationTo: 'array-fields'; value: string | ArrayField; } | null) + | ({ + relationTo: 'OnDemandForm'; + value: string | OnDemandForm; + } | null) + | ({ + relationTo: 'OnDemandOutsideForm'; + value: string | OnDemandOutsideForm; + } | null) | ({ relationTo: 'users'; value: string | User; @@ -1286,6 +1334,24 @@ export interface ArrayFieldsSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "OnDemandForm_select". + */ +export interface OnDemandFormSelect { + json?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "OnDemandOutsideForm_select". + */ +export interface OnDemandOutsideFormSelect { + json?: T; + updatedAt?: T; + createdAt?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". @@ -1351,7 +1417,7 @@ export interface TabsWithRichText { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -1368,7 +1434,7 @@ export interface TabsWithRichText { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; diff --git a/test/lexical/seed.ts b/test/lexical/seed.ts index 3e6d0f7a5..c249b4888 100644 --- a/test/lexical/seed.ts +++ b/test/lexical/seed.ts @@ -5,7 +5,6 @@ import { fileURLToPath } from 'node:url' import { lexicalDocData } from './collections/Lexical/data.js' import { generateLexicalLocalizedRichText } from './collections/LexicalLocalized/generateLexicalRichText.js' -import { textToLexicalJSON } from './collections/LexicalLocalized/textToLexicalJSON.js' import { lexicalMigrateDocData } from './collections/LexicalMigrate/data.js' import { richTextBulletsDocData, richTextDocData } from './collections/RichText/data.js' import { @@ -23,6 +22,7 @@ import { // import type { Payload } from 'payload' +import { buildEditorState } from '@payloadcms/richtext-lexical' import { getFileByPath } from 'payload' import { devUser } from '../credentials.js' @@ -41,7 +41,6 @@ import { uploadsDoc } from './collections/Upload/shared.js' // import { jsonDoc } from './collections/JSON/shared.js' // import { lexicalDocData } from './collections/Lexical/data.js' // import { generateLexicalLocalizedRichText } from './collections/LexicalLocalized/generateLexicalRichText.js' -// import { textToLexicalJSON } from './collections/LexicalLocalized/textToLexicalJSON.js' // import { lexicalMigrateDocData } from './collections/LexicalMigrate/data.js' // import { numberDoc } from './collections/Number/shared.js' // import { pointDoc } from './collections/Point/shared.js' @@ -215,7 +214,7 @@ export const seed = async (_payload: Payload) => { collection: lexicalLocalizedFieldsSlug, data: { title: 'Localized Lexical en', - lexicalBlocksLocalized: textToLexicalJSON({ text: 'English text' }), + lexicalBlocksLocalized: buildEditorState({ text: 'English text' }), lexicalBlocksSubLocalized: generateLexicalLocalizedRichText( 'Shared text', 'English text in block', @@ -229,7 +228,7 @@ export const seed = async (_payload: Payload) => { await _payload.create({ collection: lexicalRelationshipFieldsSlug, data: { - richText: textToLexicalJSON({ text: 'English text' }), + richText: buildEditorState({ text: 'English text' }), }, depth: 0, overrideAccess: true, @@ -240,7 +239,7 @@ export const seed = async (_payload: Payload) => { id: lexicalLocalizedDoc1.id, data: { title: 'Localized Lexical es', - lexicalBlocksLocalized: textToLexicalJSON({ text: 'Spanish text' }), + lexicalBlocksLocalized: buildEditorState({ text: 'Spanish text' }), lexicalBlocksSubLocalized: generateLexicalLocalizedRichText( 'Shared text', 'Spanish text in block', @@ -257,13 +256,29 @@ export const seed = async (_payload: Payload) => { data: { title: 'Localized Lexical en 2', - lexicalBlocksLocalized: textToLexicalJSON({ + lexicalBlocksLocalized: buildEditorState({ text: 'English text 2', - lexicalLocalizedRelID: lexicalLocalizedDoc1.id, + nodes: [ + { + format: '', + type: 'relationship', + version: 2, + relationTo: lexicalLocalizedFieldsSlug, + value: lexicalLocalizedDoc1.id, + }, + ], }), - lexicalBlocksSubLocalized: textToLexicalJSON({ + lexicalBlocksSubLocalized: buildEditorState({ text: 'English text 2', - lexicalLocalizedRelID: lexicalLocalizedDoc1.id, + nodes: [ + { + format: '', + type: 'relationship', + version: 2, + relationTo: lexicalLocalizedFieldsSlug, + value: lexicalLocalizedDoc1.id, + }, + ], }), }, locale: 'en', @@ -277,9 +292,17 @@ export const seed = async (_payload: Payload) => { data: { title: 'Localized Lexical es 2', - lexicalBlocksLocalized: textToLexicalJSON({ + lexicalBlocksLocalized: buildEditorState({ text: 'Spanish text 2', - lexicalLocalizedRelID: lexicalLocalizedDoc1.id, + nodes: [ + { + format: '', + type: 'relationship', + version: 2, + relationTo: lexicalLocalizedFieldsSlug, + value: lexicalLocalizedDoc1.id, + }, + ], }), }, locale: 'es', @@ -317,7 +340,7 @@ export const seed = async (_payload: Payload) => { version: 2, fields: { id: '6773773284be8978db7a498d', - lexicalInBlock: textToLexicalJSON({ text: 'text' }), + lexicalInBlock: buildEditorState({ text: 'text' }), blockName: '', blockType: 'blockInLexical', }, @@ -334,12 +357,12 @@ export const seed = async (_payload: Payload) => { { blockType: 'lexicalInBlock2', blockName: '1', - lexical: textToLexicalJSON({ text: '1' }), + lexical: buildEditorState({ text: '1' }), }, { blockType: 'lexicalInBlock2', blockName: '2', - lexical: textToLexicalJSON({ text: '2' }), + lexical: buildEditorState({ text: '2' }), }, { blockType: 'lexicalInBlock2', diff --git a/test/package.json b/test/package.json index ea399adf4..01ab67f5d 100644 --- a/test/package.json +++ b/test/package.json @@ -63,9 +63,9 @@ "@sentry/nextjs": "^8.33.1", "@sentry/react": "^7.77.0", "@types/jest": "29.5.12", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", - "babel-plugin-react-compiler": "19.1.0-rc.2", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", + "babel-plugin-react-compiler": "19.1.0-rc.3", "comment-json": "^4.2.3", "create-payload-app": "workspace:*", "csv-parse": "^5.6.0", @@ -87,8 +87,8 @@ "payload": "workspace:*", "pg": "8.16.3", "qs-esm": "7.0.2", - "react": "19.1.0", - "react-dom": "19.1.0", + "react": "19.1.1", + "react-dom": "19.1.1", "sass": "1.77.4", "server-only": "^0.0.1", "sharp": "0.32.6", diff --git a/test/types/config.ts b/test/types/config.ts index f33cf0816..27bb87579 100644 --- a/test/types/config.ts +++ b/test/types/config.ts @@ -18,6 +18,11 @@ export default buildConfigWithDefaults({ type: 'text', name: 'text', }, + { + type: 'richText', + name: 'richText', + required: true, + }, { type: 'text', name: 'title', diff --git a/test/types/payload-types.ts b/test/types/payload-types.ts index 543350e28..59fcc859e 100644 --- a/test/types/payload-types.ts +++ b/test/types/payload-types.ts @@ -142,6 +142,21 @@ export interface UserAuthOperations { export interface Post { id: string; text?: string | null; + richText: { + root: { + type: string; + children: { + type: any; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + }; title?: string | null; selectField: MySelectOptions; insideUnnamedGroup?: string | null; @@ -193,6 +208,13 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } /** @@ -266,6 +288,7 @@ export interface PayloadMigration { */ export interface PostsSelect { text?: T; + richText?: T; title?: T; selectField?: T; insideUnnamedGroup?: T; @@ -312,6 +335,13 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; } /** * This interface was referenced by `Config`'s JSON-Schema @@ -375,6 +405,6 @@ export interface Auth { declare module 'payload' { - // @ts-ignore + // @ts-ignore export interface GeneratedTypes extends Config {} -} \ No newline at end of file +} diff --git a/test/types/types.spec.ts b/test/types/types.spec.ts index 937823569..5829ecc28 100644 --- a/test/types/types.spec.ts +++ b/test/types/types.spec.ts @@ -1,3 +1,8 @@ +import type { + DefaultNodeTypes, + DefaultTypedEditorState, + TypedEditorState, +} from '@payloadcms/richtext-lexical' import type { BulkOperationResult, CustomDocumentViewConfig, @@ -173,4 +178,107 @@ describe('Types testing', () => { }>() }) }) + + describe('lexical', () => { + type _Hardcoded_DefaultNodeTypes = + | 'autolink' + | 'heading' + | 'horizontalrule' + | 'linebreak' + | 'link' + | 'list' + | 'listitem' + | 'paragraph' + | 'quote' + | 'relationship' + | 'tab' + | 'text' + | 'upload' + + test('ensure TypedEditorState node type without generic is string', () => { + expect().type.toBe() + }) + + test('ensure TypedEditorState<1 generic> node type is correct', () => { + expect< + TypedEditorState<{ + type: 'custom-node' + version: 1 + }>['root']['children'][number]['type'] + >().type.toBe<'custom-node'>() + }) + + test('ensure TypedEditorState<2 generics> node type is correct', () => { + expect< + TypedEditorState< + | { + type: 'custom-node' + version: 1 + } + | { + type: 'custom-node-2' + version: 1 + } + >['root']['children'][number]['type'] + >().type.toBe<'custom-node' | 'custom-node-2'>() + }) + + test('ensure DefaultTypedEditorState node type is a union of all possible node types', () => { + expect< + DefaultTypedEditorState['root']['children'][number]['type'] + >().type.toBe<_Hardcoded_DefaultNodeTypes>() + }) + + test('ensure TypedEditorState node type is identical to DefaultTypedEditorState', () => { + expect< + TypedEditorState['root']['children'][number]['type'] + >().type.toBe<_Hardcoded_DefaultNodeTypes>() + }) + + test('ensure DefaultTypedEditorState adds custom node type to union of default nodes', () => { + expect< + DefaultTypedEditorState<{ + type: 'custom-node' + version: 1 + }>['root']['children'][number]['type'] + >().type.toBe<'custom-node' | _Hardcoded_DefaultNodeTypes>() + }) + + test('ensure DefaultTypedEditorState adds custom node types to union of default nodes', () => { + expect< + DefaultTypedEditorState< + | { + type: 'custom-node' + version: 1 + } + | { + type: 'custom-node-2' + version: 1 + } + >['root']['children'][number]['type'] + >().type.toBe<'custom-node' | 'custom-node-2' | _Hardcoded_DefaultNodeTypes>() + }) + + test("ensure link node automatically narrows type so that node accepts fields property if type === 'link' is checked", () => { + type NodeType = DefaultTypedEditorState['root']['children'][number] + + const node = { + type: 'link', + } as NodeType + + if (node.type === 'link') { + expect(node).type.toHaveProperty('fields') + } else { + expect(node).type.not.toHaveProperty('fields') + } + }) + + test('ensure generated richText types can be assigned to DefaultTypedEditorState type', () => { + // If there is a function that expects DefaultTypedEditorState, you should be able to assign the generated type to it + // This ensures that data can be passed directly form the payload local API to a function that expects DefaultTypedEditorState + type GeneratedRichTextType = Post['richText'] + + expect().type.toBeAssignableWith() + }) + }) }) diff --git a/test/versions/seed.ts b/test/versions/seed.ts index df5d56841..0a47bcb9b 100644 --- a/test/versions/seed.ts +++ b/test/versions/seed.ts @@ -1,3 +1,4 @@ +import { buildEditorState } from '@payloadcms/richtext-lexical' import path from 'path' import { getFileByPath, type Payload } from 'payload' import { fileURLToPath } from 'url' @@ -14,7 +15,6 @@ import { media2CollectionSlug, mediaCollectionSlug, } from './slugs.js' -import { textToLexicalJSON } from './textToLexicalJSON.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -273,7 +273,7 @@ export async function seed(_payload: Payload, parallel: boolean = false) { textID: doc1ID, updated: false, }) as any, - richtextWithCustomDiff: textToLexicalJSON({ text: 'richtextWithCustomDiff' }), + richtextWithCustomDiff: buildEditorState({ text: 'richtextWithCustomDiff' }), select: 'option1', text: 'text', textArea: 'textArea', @@ -442,7 +442,7 @@ export async function seed(_payload: Payload, parallel: boolean = false) { textID: doc2ID, updated: true, }) as any, - richtextWithCustomDiff: textToLexicalJSON({ text: 'richtextWithCustomDiff2' }), + richtextWithCustomDiff: buildEditorState({ text: 'richtextWithCustomDiff2' }), select: 'option2', text: 'text2', textArea: 'textArea2', diff --git a/test/versions/textToLexicalJSON.ts b/test/versions/textToLexicalJSON.ts deleted file mode 100644 index c2f12c9e5..000000000 --- a/test/versions/textToLexicalJSON.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { - SerializedEditorState, - SerializedParagraphNode, - SerializedTextNode, -} from '@payloadcms/richtext-lexical/lexical' - -export function textToLexicalJSON({ text }: { text: string }): any { - const editorJSON: SerializedEditorState = { - root: { - type: 'root', - format: '', - indent: 0, - version: 1, - direction: 'ltr', - children: [ - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text, - type: 'text', - version: 1, - } as SerializedTextNode, - ], - direction: 'ltr', - format: '', - indent: 0, - textFormat: 0, - type: 'paragraph', - textStyle: '', - version: 1, - } as SerializedParagraphNode, - ], - }, - } - - return editorJSON -}