From 1c89291fac54c881689009794cc92b7df9221278 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Thu, 18 Sep 2025 15:01:12 -0700 Subject: [PATCH] feat(richtext-lexical): utility render lexical field on-demand (#13657) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Why this exists 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, upload 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. ## What’s new We now ship a client component, ``, that renders a Lexical editor **on demand** 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 action. That server render gives Lexical everything it needs (including nested field schemas) and returns a ready‑to‑hydrate editor. ## Example - Rendering in custom component within existing Form ```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 (
Fully-Featured Component:
) } ``` ## Example - Rendering outside of Form, manually managing richText values ```ts '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) => { const [value, setValue] = useState(() => buildEditorState({ text: 'state default' }), ) const handleReset = React.useCallback(() => { setValue(buildEditorState({ text: 'state default' })) }, []) return (
Default Component:
) } ``` ## How it works (under the hood) - On first render, `` calls the server function `render-field` (wired into @payloadcms/next), passing a schemaPath. - The server loads the exact field config and its client schema map for that path, renders the Lexical editor server‑side (so nested features like blocks/tables/relationships are fully known), and returns the component tree. - While waiting, the client shows a small shimmer skeleton. - Inside Forms, RenderLexical plugs into the parent form via useField; outside Forms, you can fully control the value by passing value/setValue. ## Type Improvements While implementing the `buildEditorState` helper function for our test suite, I noticed some issues with our `TypedEditorState` type: - nodes were no longer narrowed by their node.type types - upon fixing this issue, the type was no longer compatible with the generated types. To address this, I had to weaken the generated type a bit. In order to ensure the type will keep functioning as intended from now on, this PR also adds some type tests --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1211110462564644 --- .github/workflows/main.yml | 4 + docs/rich-text/rendering-on-demand.mdx | 116 ++ package.json | 10 +- packages/admin-bar/package.json | 4 +- packages/live-preview-react/package.json | 4 +- packages/next/package.json | 6 +- .../src/utilities/handleServerFunctions.ts | 18 +- packages/payload/src/admin/fields/Row.ts | 5 +- packages/payload/src/admin/forms/Field.ts | 7 + packages/payload/src/admin/functions/index.ts | 25 + packages/plugin-cloud-storage/package.json | 4 +- packages/plugin-form-builder/package.json | 4 +- packages/plugin-search/package.json | 4 +- packages/plugin-sentry/package.json | 4 +- packages/plugin-seo/package.json | 4 +- packages/plugin-stripe/package.json | 4 +- packages/richtext-lexical/package.json | 6 +- .../src/exports/client/index.ts | 3 + .../src/field/RenderLexical/index.tsx | 127 ++ packages/richtext-lexical/src/index.ts | 6 +- packages/richtext-lexical/src/nodeTypes.ts | 19 +- .../src/utilities/buildEditorState.ts | 99 ++ packages/richtext-slate/package.json | 4 +- packages/translations/package.json | 4 +- packages/ui/package.json | 6 +- .../src/elements/RenderIfInViewport/index.tsx | 13 +- packages/ui/src/exports/client/index.ts | 9 +- packages/ui/src/exports/rsc/index.ts | 1 + packages/ui/src/fields/Array/ArrayRow.tsx | 12 +- packages/ui/src/fields/Tabs/index.tsx | 4 +- packages/ui/src/forms/RenderFields/types.ts | 12 +- .../serverFunctions/renderFieldServerFn.ts | 119 ++ packages/ui/src/forms/useField/index.tsx | 56 +- .../src/providers/ServerFunctions/index.tsx | 25 +- pnpm-lock.yaml | 1118 +++++++++-------- .../website/src/blocks/Form/Component.tsx | 4 +- .../website/src/blocks/Form/Message/index.tsx | 4 +- .../src/blocks/RelatedPosts/Component.tsx | 4 +- templates/website/src/payload-types.ts | 22 +- .../src/blocks/Form/Component.tsx | 4 +- .../src/blocks/Form/Message/index.tsx | 4 +- .../src/blocks/RelatedPosts/Component.tsx | 4 +- test/access-control/config.ts | 23 +- test/lexical/baseConfig.ts | 4 + .../LexicalLocalized/textToLexicalJSON.ts | 60 - .../collections/OnDemandForm/Component.tsx | 20 + .../collections/OnDemandForm/e2e.spec.ts | 106 ++ .../lexical/collections/OnDemandForm/index.ts | 16 + .../OnDemandOutsideForm/Component.tsx | 35 + .../collections/OnDemandOutsideForm/index.ts | 16 + .../_LexicalFullyFeatured/e2e.spec.ts | 3 +- test/lexical/collections/utils.ts | 11 +- test/lexical/lexical.int.spec.ts | 18 +- test/lexical/payload-types.ts | 114 +- test/lexical/seed.ts | 51 +- test/package.json | 10 +- test/types/config.ts | 5 + test/types/payload-types.ts | 34 +- test/types/types.spec.ts | 108 ++ test/versions/seed.ts | 6 +- test/versions/textToLexicalJSON.ts | 41 - 61 files changed, 1773 insertions(+), 820 deletions(-) create mode 100644 docs/rich-text/rendering-on-demand.mdx create mode 100644 packages/richtext-lexical/src/field/RenderLexical/index.tsx create mode 100644 packages/richtext-lexical/src/utilities/buildEditorState.ts create mode 100644 packages/ui/src/forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.ts delete mode 100644 test/lexical/collections/LexicalLocalized/textToLexicalJSON.ts create mode 100644 test/lexical/collections/OnDemandForm/Component.tsx create mode 100644 test/lexical/collections/OnDemandForm/e2e.spec.ts create mode 100644 test/lexical/collections/OnDemandForm/index.ts create mode 100644 test/lexical/collections/OnDemandOutsideForm/Component.tsx create mode 100644 test/lexical/collections/OnDemandOutsideForm/index.ts delete mode 100644 test/versions/textToLexicalJSON.ts 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 -}