@byline/richtext-lexical 4.16.0 → 4.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/field/extensions/inline-image/inline-image-modal.js +3 -2
- package/dist/field/extensions/link/link-modal.js +6 -4
- package/dist/field/extensions/vimeo/vimeo-node.d.ts +1 -2
- package/dist/field/extensions/vimeo/vimeo-node.js +1 -4
- package/dist/field/extensions/youtube/youtube-node.d.ts +1 -2
- package/dist/field/extensions/youtube/youtube-node.js +1 -4
- package/package.json +8 -10
- package/src/field/extensions/inline-image/inline-image-modal.tsx +5 -3
- package/src/field/extensions/link/link-modal.tsx +19 -8
- package/src/field/extensions/vimeo/vimeo-node.tsx +0 -5
- package/src/field/extensions/youtube/youtube-node.tsx +0 -7
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useMemo, useState } from "react";
|
|
4
4
|
import { RelationPicker } from "@byline/admin/react";
|
|
5
|
-
import { getCollectionDefinition } from "@byline/core";
|
|
5
|
+
import { getCollectionDefinition, isSingleton } from "@byline/core";
|
|
6
6
|
import { Button, Checkbox, CloseIcon, ErrorText, IconButton, Input, Label, Modal, RadioGroup, RadioGroupItem } from "@byline/ui/react";
|
|
7
7
|
import { useModalFormState } from "../../shared/useModalFormState.js";
|
|
8
8
|
import { isAltTextValid, positionOptions } from "./fields.js";
|
|
@@ -49,7 +49,8 @@ const InlineImageModal = ({ isOpen, collection, data: dataFromProps, onSubmit, o
|
|
|
49
49
|
setAltError(null);
|
|
50
50
|
setImageError(null);
|
|
51
51
|
});
|
|
52
|
-
const
|
|
52
|
+
const targetDefinition = getCollectionDefinition(collection);
|
|
53
|
+
const targetDef = null == targetDefinition || isSingleton(targetDefinition) ? null : targetDefinition;
|
|
53
54
|
const pickedImage = useMemo(()=>{
|
|
54
55
|
const img = state.documentRelation?.document?.image;
|
|
55
56
|
return img ?? null;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useMemo, useState } from "react";
|
|
4
4
|
import { RelationPicker } from "@byline/admin/react";
|
|
5
|
-
import { getAdminConfig, getCollectionDefinition } from "@byline/core";
|
|
5
|
+
import { getAdminConfig, getCollectionDefinition, isSingleton } from "@byline/core";
|
|
6
6
|
import { Button, Checkbox, CloseIcon, IconButton, Input, Label, Modal, RadioGroup, RadioGroupItem, Select } from "@byline/ui/react";
|
|
7
7
|
import { useModalFormState } from "../../shared/useModalFormState.js";
|
|
8
8
|
import { validateUrl } from "../../utils/url.js";
|
|
@@ -41,11 +41,12 @@ function fromLinkData(data, linkable) {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
const LinkModal = ({ isOpen = false, onSubmit, onClose, data: dataFromProps })=>{
|
|
44
|
-
const linkable = useMemo(()=>getAdminConfig().collections.filter((
|
|
44
|
+
const linkable = useMemo(()=>getAdminConfig().collections.filter((collection)=>!isSingleton(collection) && true === collection.linksInEditor), []);
|
|
45
45
|
const [pickerOpen, setPickerOpen] = useState(false);
|
|
46
46
|
const [urlError, setUrlError] = useState(null);
|
|
47
47
|
const [state, setState] = useModalFormState(isOpen, ()=>fromLinkData(dataFromProps, linkable), ()=>setUrlError(null));
|
|
48
|
-
const
|
|
48
|
+
const targetDefinition = state.targetCollection ? getCollectionDefinition(state.targetCollection) : null;
|
|
49
|
+
const targetDef = null == targetDefinition || isSingleton(targetDefinition) ? null : targetDefinition;
|
|
49
50
|
const collectionItems = useMemo(()=>linkable.map((c)=>({
|
|
50
51
|
label: c.labels.singular,
|
|
51
52
|
value: c.path
|
|
@@ -56,7 +57,8 @@ const LinkModal = ({ isOpen = false, onSubmit, onClose, data: dataFromProps })=>
|
|
|
56
57
|
if ('internal' !== state.linkType || !state.picked) return null;
|
|
57
58
|
const title = state.picked.document?.title;
|
|
58
59
|
if ('string' == typeof title && title.length > 0) return title;
|
|
59
|
-
const
|
|
60
|
+
const pickedDefinition = getCollectionDefinition(state.picked.targetCollectionPath);
|
|
61
|
+
const pickedDef = null == pickedDefinition || isSingleton(pickedDefinition) ? null : pickedDefinition;
|
|
60
62
|
const short = state.picked.targetDocumentId.slice(0, 8);
|
|
61
63
|
return `${pickedDef?.labels.singular ?? state.picked.targetCollectionPath} · ${short}…`;
|
|
62
64
|
}, [
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type * as React from 'react';
|
|
9
9
|
import { DecoratorBlockNode, type SerializedDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode';
|
|
10
|
-
import type { DOMConversionMap, DOMExportOutput, EditorConfig, ElementFormatType, LexicalEditor,
|
|
10
|
+
import type { DOMConversionMap, DOMExportOutput, EditorConfig, ElementFormatType, LexicalEditor, NodeKey, Spread } from 'lexical';
|
|
11
11
|
export type SerializedVimeoNode = Spread<{
|
|
12
12
|
videoID: string;
|
|
13
13
|
}, SerializedDecoratorBlockNode>;
|
|
@@ -26,4 +26,3 @@ export declare class VimeoNode extends DecoratorBlockNode {
|
|
|
26
26
|
decorate(_editor: LexicalEditor, config: EditorConfig): React.JSX.Element;
|
|
27
27
|
}
|
|
28
28
|
export declare function $createVimeoNode(videoID: string): VimeoNode;
|
|
29
|
-
export declare function $isVimeoNode(node: VimeoNode | LexicalNode | null | undefined): node is VimeoNode;
|
|
@@ -103,7 +103,4 @@ class VimeoNode extends DecoratorBlockNode {
|
|
|
103
103
|
function $createVimeoNode(videoID) {
|
|
104
104
|
return new VimeoNode(videoID);
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
return node instanceof VimeoNode;
|
|
108
|
-
}
|
|
109
|
-
export { $createVimeoNode, $isVimeoNode, VimeoNode };
|
|
106
|
+
export { $createVimeoNode, VimeoNode };
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type * as React from 'react';
|
|
9
9
|
import { DecoratorBlockNode, type SerializedDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode';
|
|
10
|
-
import type { DOMConversionMap, DOMExportOutput, EditorConfig, ElementFormatType, LexicalEditor,
|
|
10
|
+
import type { DOMConversionMap, DOMExportOutput, EditorConfig, ElementFormatType, LexicalEditor, NodeKey, Spread } from 'lexical';
|
|
11
11
|
export type SerializedYouTubeNode = Spread<{
|
|
12
12
|
videoID: string;
|
|
13
13
|
}, SerializedDecoratorBlockNode>;
|
|
@@ -26,4 +26,3 @@ export declare class YouTubeNode extends DecoratorBlockNode {
|
|
|
26
26
|
decorate(_editor: LexicalEditor, config: EditorConfig): React.JSX.Element;
|
|
27
27
|
}
|
|
28
28
|
export declare function $createYouTubeNode(videoID: string): YouTubeNode;
|
|
29
|
-
export declare function $isYouTubeNode(node: YouTubeNode | LexicalNode | null | undefined): node is YouTubeNode;
|
|
@@ -104,7 +104,4 @@ class YouTubeNode extends DecoratorBlockNode {
|
|
|
104
104
|
function $createYouTubeNode(videoID) {
|
|
105
105
|
return new YouTubeNode(videoID);
|
|
106
106
|
}
|
|
107
|
-
|
|
108
|
-
return node instanceof YouTubeNode;
|
|
109
|
-
}
|
|
110
|
-
export { $createYouTubeNode, $isYouTubeNode, YouTubeNode };
|
|
107
|
+
export { $createYouTubeNode, YouTubeNode };
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": false,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
|
-
"version": "4.
|
|
6
|
+
"version": "4.18.0",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=20.9.0"
|
|
9
9
|
},
|
|
@@ -72,28 +72,26 @@
|
|
|
72
72
|
"clsx": "^2.1.1",
|
|
73
73
|
"lexical": "0.49.0",
|
|
74
74
|
"react-error-boundary": "^6.1.3",
|
|
75
|
-
"@byline/admin": "4.
|
|
76
|
-
"@byline/
|
|
77
|
-
"@byline/
|
|
78
|
-
"@byline/
|
|
75
|
+
"@byline/admin": "4.18.0",
|
|
76
|
+
"@byline/core": "4.18.0",
|
|
77
|
+
"@byline/ui": "4.18.0",
|
|
78
|
+
"@byline/client": "4.18.0"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
81
|
"react": "^19.0.0",
|
|
82
82
|
"react-dom": "^19.0.0"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
|
-
"@biomejs/biome": "2.5.
|
|
85
|
+
"@biomejs/biome": "2.5.10",
|
|
86
86
|
"@rsbuild/plugin-react": "^2.1.0",
|
|
87
87
|
"@rslib/core": "^0.23.2",
|
|
88
|
-
"@types/node": "^26.
|
|
88
|
+
"@types/node": "^26.4.0",
|
|
89
89
|
"@types/react": "19.2.18",
|
|
90
|
-
"@types/react-dom": "19.2.
|
|
90
|
+
"@types/react-dom": "19.2.5",
|
|
91
91
|
"@vitejs/plugin-react": "^6.1.0",
|
|
92
|
-
"lightningcss": "^1.33.0",
|
|
93
92
|
"npm-run-all": "^4.1.5",
|
|
94
93
|
"react": "^19.2.8",
|
|
95
94
|
"react-dom": "^19.2.8",
|
|
96
|
-
"rimraf": "^6.1.3",
|
|
97
95
|
"typescript": "^7.0.2",
|
|
98
96
|
"typescript-plugin-css-modules": "^5.2.0",
|
|
99
97
|
"vite": "^8.2.2",
|
|
@@ -12,8 +12,8 @@ import type * as React from 'react'
|
|
|
12
12
|
import { useMemo, useState } from 'react'
|
|
13
13
|
|
|
14
14
|
import { RelationPicker } from '@byline/admin/react'
|
|
15
|
-
import type {
|
|
16
|
-
import { getCollectionDefinition } from '@byline/core'
|
|
15
|
+
import type { MultiCollectionDefinition, StoredFileValue } from '@byline/core'
|
|
16
|
+
import { getCollectionDefinition, isSingleton } from '@byline/core'
|
|
17
17
|
import {
|
|
18
18
|
Button,
|
|
19
19
|
Checkbox,
|
|
@@ -106,7 +106,9 @@ export const InlineImageModal: React.FC<InlineImageModalProps> = ({
|
|
|
106
106
|
}
|
|
107
107
|
)
|
|
108
108
|
|
|
109
|
-
const
|
|
109
|
+
const targetDefinition = getCollectionDefinition(collection)
|
|
110
|
+
const targetDef: MultiCollectionDefinition | null =
|
|
111
|
+
targetDefinition != null && !isSingleton(targetDefinition) ? targetDefinition : null
|
|
110
112
|
|
|
111
113
|
// The image StoredFileValue lives inside the picked media doc's denormalised
|
|
112
114
|
// `documentRelation.document.image` field — see `handlePickerSelect` below.
|
|
@@ -12,8 +12,8 @@ import type * as React from 'react'
|
|
|
12
12
|
import { useMemo, useState } from 'react'
|
|
13
13
|
|
|
14
14
|
import { RelationPicker } from '@byline/admin/react'
|
|
15
|
-
import type {
|
|
16
|
-
import { getAdminConfig, getCollectionDefinition } from '@byline/core'
|
|
15
|
+
import type { MultiCollectionDefinition } from '@byline/core'
|
|
16
|
+
import { getAdminConfig, getCollectionDefinition, isSingleton } from '@byline/core'
|
|
17
17
|
import {
|
|
18
18
|
Button,
|
|
19
19
|
Checkbox,
|
|
@@ -48,7 +48,7 @@ interface FormState {
|
|
|
48
48
|
picked: DocumentRelation | null
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function emptyState(linkable:
|
|
51
|
+
function emptyState(linkable: MultiCollectionDefinition[]): FormState {
|
|
52
52
|
return {
|
|
53
53
|
text: '',
|
|
54
54
|
linkType: linkable.length > 0 ? 'internal' : 'custom',
|
|
@@ -59,7 +59,10 @@ function emptyState(linkable: CollectionDefinition[]): FormState {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
function fromLinkData(
|
|
62
|
+
function fromLinkData(
|
|
63
|
+
data: LinkData | undefined,
|
|
64
|
+
linkable: MultiCollectionDefinition[]
|
|
65
|
+
): FormState {
|
|
63
66
|
const base = emptyState(linkable)
|
|
64
67
|
if (!data) return base
|
|
65
68
|
const fields = data.fields
|
|
@@ -101,8 +104,12 @@ export const LinkModal: React.FC<LinkModalProps> = ({
|
|
|
101
104
|
onClose,
|
|
102
105
|
data: dataFromProps,
|
|
103
106
|
}) => {
|
|
104
|
-
const linkable = useMemo<
|
|
105
|
-
() =>
|
|
107
|
+
const linkable = useMemo<MultiCollectionDefinition[]>(
|
|
108
|
+
() =>
|
|
109
|
+
getAdminConfig().collections.filter(
|
|
110
|
+
(collection): collection is MultiCollectionDefinition =>
|
|
111
|
+
!isSingleton(collection) && collection.linksInEditor === true
|
|
112
|
+
),
|
|
106
113
|
[]
|
|
107
114
|
)
|
|
108
115
|
|
|
@@ -115,9 +122,11 @@ export const LinkModal: React.FC<LinkModalProps> = ({
|
|
|
115
122
|
() => setUrlError(null)
|
|
116
123
|
)
|
|
117
124
|
|
|
118
|
-
const
|
|
125
|
+
const targetDefinition = state.targetCollection
|
|
119
126
|
? getCollectionDefinition(state.targetCollection)
|
|
120
127
|
: null
|
|
128
|
+
const targetDef: MultiCollectionDefinition | null =
|
|
129
|
+
targetDefinition != null && !isSingleton(targetDefinition) ? targetDefinition : null
|
|
121
130
|
|
|
122
131
|
const collectionItems: SelectValue<string>[] = useMemo(
|
|
123
132
|
() => linkable.map((c) => ({ label: c.labels.singular, value: c.path })),
|
|
@@ -129,7 +138,9 @@ export const LinkModal: React.FC<LinkModalProps> = ({
|
|
|
129
138
|
const title = state.picked.document?.title
|
|
130
139
|
if (typeof title === 'string' && title.length > 0) return title
|
|
131
140
|
// No title cached — show a stable stub keyed off the collection.
|
|
132
|
-
const
|
|
141
|
+
const pickedDefinition = getCollectionDefinition(state.picked.targetCollectionPath)
|
|
142
|
+
const pickedDef =
|
|
143
|
+
pickedDefinition != null && !isSingleton(pickedDefinition) ? pickedDefinition : null
|
|
133
144
|
const short = state.picked.targetDocumentId.slice(0, 8)
|
|
134
145
|
return `${pickedDef?.labels.singular ?? state.picked.targetCollectionPath} · ${short}…`
|
|
135
146
|
}, [state.linkType, state.picked])
|
|
@@ -20,7 +20,6 @@ import type {
|
|
|
20
20
|
EditorConfig,
|
|
21
21
|
ElementFormatType,
|
|
22
22
|
LexicalEditor,
|
|
23
|
-
LexicalNode,
|
|
24
23
|
NodeKey,
|
|
25
24
|
Spread,
|
|
26
25
|
} from 'lexical'
|
|
@@ -166,7 +165,3 @@ export class VimeoNode extends DecoratorBlockNode {
|
|
|
166
165
|
export function $createVimeoNode(videoID: string): VimeoNode {
|
|
167
166
|
return new VimeoNode(videoID)
|
|
168
167
|
}
|
|
169
|
-
|
|
170
|
-
export function $isVimeoNode(node: VimeoNode | LexicalNode | null | undefined): node is VimeoNode {
|
|
171
|
-
return node instanceof VimeoNode
|
|
172
|
-
}
|
|
@@ -20,7 +20,6 @@ import type {
|
|
|
20
20
|
EditorConfig,
|
|
21
21
|
ElementFormatType,
|
|
22
22
|
LexicalEditor,
|
|
23
|
-
LexicalNode,
|
|
24
23
|
NodeKey,
|
|
25
24
|
Spread,
|
|
26
25
|
} from 'lexical'
|
|
@@ -170,9 +169,3 @@ export class YouTubeNode extends DecoratorBlockNode {
|
|
|
170
169
|
export function $createYouTubeNode(videoID: string): YouTubeNode {
|
|
171
170
|
return new YouTubeNode(videoID)
|
|
172
171
|
}
|
|
173
|
-
|
|
174
|
-
export function $isYouTubeNode(
|
|
175
|
-
node: YouTubeNode | LexicalNode | null | undefined
|
|
176
|
-
): node is YouTubeNode {
|
|
177
|
-
return node instanceof YouTubeNode
|
|
178
|
-
}
|