@byline/cli 5.1.4 → 6.0.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/templates/byline-examples/fields/lexical-richtext-ai.tsx +2 -2
- package/dist/templates/byline-examples/fields/lexical-richtext-compact-admin.tsx +87 -0
- package/dist/templates/byline-examples/fields/lexical-richtext-compact.ts +21 -11
- package/dist/templates-editor-api-drift.test.d.ts +9 -0
- package/dist/templates-editor-api-drift.test.d.ts.map +1 -0
- package/dist/templates-editor-api-drift.test.js +87 -0
- package/dist/templates-editor-api-drift.test.js.map +1 -0
- package/package.json +4 -4
|
@@ -55,11 +55,11 @@ export const LexicalRichTextAi = lexicalEditor((c) => {
|
|
|
55
55
|
// registration config so every richtext field keeps the AI assistant AND
|
|
56
56
|
// the markdown toggle — a schema-side `editorConfig` would override this
|
|
57
57
|
// baked config and strip the AI extension (it can't carry extensions).
|
|
58
|
-
c.settings.
|
|
58
|
+
c.settings.controls.markdownToggle = true
|
|
59
59
|
// Inline as-you-type markdown shortcuts (`# ` → H1, `- ` → list, `**x**`
|
|
60
60
|
// → bold, `| a | b |` → table, `:::note` → admonition, …). Uses the same
|
|
61
61
|
// BYLINE_TRANSFORMERS set as the source toggle. Remove this line to disable.
|
|
62
|
-
c.settings.
|
|
62
|
+
c.settings.markdownShortcuts = true
|
|
63
63
|
return c
|
|
64
64
|
}) satisfies (props: RichTextEditorProps) => React.JSX.Element
|
|
65
65
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* **Admin-side half of the compact editor.** Pair with the
|
|
11
|
+
* `lexicalRichTextCompact()` schema helper, which carries the JSON-safe
|
|
12
|
+
* toolbar preferences; this file carries the extension set, which is not
|
|
13
|
+
* JSON-safe and so cannot live in a schema.
|
|
14
|
+
*
|
|
15
|
+
* Compact sits between a strictly inline field and the full editor: no
|
|
16
|
+
* block structures, but links and inline images survive, because a
|
|
17
|
+
* caption or a credit line usually wants both. Adjust the removals below
|
|
18
|
+
* to suit your own fields — this is an example, not a fixed policy.
|
|
19
|
+
*
|
|
20
|
+
* Removing an extension decides what the field ACCEPTS as well as what
|
|
21
|
+
* it offers, since each extension owns its node classes. Without this
|
|
22
|
+
* half, a compact field hid the block-format dropdown while still
|
|
23
|
+
* storing a heading that arrived by paste.
|
|
24
|
+
*
|
|
25
|
+
* Bold, italic and inline code cannot be constrained here: they are
|
|
26
|
+
* `TextNode` formats rather than node types, so they have no node to
|
|
27
|
+
* unregister and still arrive by paste.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import type { FieldAdminConfig, RichTextEditorProps } from '@byline/core'
|
|
31
|
+
import { builtInExtensions, lexicalEditor } from '@byline/richtext-lexical/config'
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The extension narrowing, exported separately from the component.
|
|
35
|
+
*
|
|
36
|
+
* `lexicalEditor()` closes over its callback inside a lazy component, so
|
|
37
|
+
* the resolved list is not reachable from the outside. Naming the
|
|
38
|
+
* callback lets a test assert which extensions this preset removes —
|
|
39
|
+
* which is the whole of its contract now that removal decides what a
|
|
40
|
+
* field accepts.
|
|
41
|
+
*/
|
|
42
|
+
export function configureCompactEditor<T extends { extensions?: any }>(c: T): T {
|
|
43
|
+
c.extensions
|
|
44
|
+
// Block structures — a caption is not a place for a heading, a
|
|
45
|
+
// quote, a list or a table.
|
|
46
|
+
.remove(builtInExtensions.Heading)
|
|
47
|
+
.remove(builtInExtensions.Quote)
|
|
48
|
+
.remove(builtInExtensions.List)
|
|
49
|
+
.remove(builtInExtensions.CheckList)
|
|
50
|
+
.remove(builtInExtensions.Table)
|
|
51
|
+
.remove(builtInExtensions.Layout)
|
|
52
|
+
.remove(builtInExtensions.Admonition)
|
|
53
|
+
.remove(builtInExtensions.HorizontalRule)
|
|
54
|
+
.remove(builtInExtensions.CodeHighlight)
|
|
55
|
+
// Embeds — a compact field is not a place to drop a video.
|
|
56
|
+
.remove(builtInExtensions.AutoEmbed)
|
|
57
|
+
.remove(builtInExtensions.YouTube)
|
|
58
|
+
.remove(builtInExtensions.Vimeo)
|
|
59
|
+
// Link, AutoLink and InlineImage stay on purpose: captions carry
|
|
60
|
+
// credits, and credits carry links.
|
|
61
|
+
return c
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const LexicalRichTextCompact = lexicalEditor(configureCompactEditor) satisfies (
|
|
65
|
+
props: RichTextEditorProps
|
|
66
|
+
) => React.JSX.Element
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns a `FieldAdminConfig` that opts a single richText field into the
|
|
70
|
+
* compact editor. Drop into a `CollectionAdminConfig.fields` map, keyed
|
|
71
|
+
* by the schema field's name.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* // byline/collections/<collection>/admin.tsx
|
|
76
|
+
* import { compactRichTextAdmin } from '../../fields/lexical-richtext-compact-admin.jsx'
|
|
77
|
+
*
|
|
78
|
+
* fields: {
|
|
79
|
+
* caption: compactRichTextAdmin(),
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function compactRichTextAdmin(): FieldAdminConfig {
|
|
84
|
+
return {
|
|
85
|
+
editor: LexicalRichTextCompact,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -52,19 +52,29 @@ type Options = Partial<Omit<RichTextField, 'type' | 'editorConfig'>> & {
|
|
|
52
52
|
* captions, byline strap-lines, or compact form fields. Bold / italic /
|
|
53
53
|
* link editing remain on.
|
|
54
54
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
55
|
+
* This half hides CONTROLS and nothing more. It does not decide what the
|
|
56
|
+
* field accepts: a heading can still arrive by paste, by Markdown, or
|
|
57
|
+
* from storage, and `controls.blockFormat = false` only removes the
|
|
58
|
+
* dropdown that would have offered one.
|
|
59
|
+
*
|
|
60
|
+
* To narrow what the field ACCEPTS, pair this with
|
|
61
|
+
* `compactRichTextAdmin()` (`./lexical-richtext-compact-admin.js`), which
|
|
62
|
+
* removes the extensions owning those node classes — removing an
|
|
63
|
+
* extension removes its node registration along with its controls.
|
|
64
|
+
* Extension references are not JSON-safe, so they cannot be baked into a
|
|
65
|
+
* schema and must travel through `FieldAdminConfig.editor`, the same
|
|
66
|
+
* pattern as `aiRichTextAdmin()`.
|
|
67
|
+
*
|
|
68
|
+
* Neither half can constrain bold, italic or inline code: they are
|
|
69
|
+
* `TextNode` formats rather than node types, so there is no node to
|
|
70
|
+
* unregister and they still arrive by paste.
|
|
61
71
|
*/
|
|
62
72
|
function applyCompactPreset(config: EditorConfig): EditorConfig {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
const c = config.settings.controls
|
|
74
|
+
c.textAlignment = false
|
|
75
|
+
c.blockFormat = false
|
|
76
|
+
c.inlineCode = false
|
|
77
|
+
c.undoRedo = false
|
|
68
78
|
return config
|
|
69
79
|
}
|
|
70
80
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=templates-editor-api-drift.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates-editor-api-drift.test.d.ts","sourceRoot":"","sources":["../src/templates-editor-api-drift.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Shipped examples must not use editor APIs that no longer exist.
|
|
10
|
+
*
|
|
11
|
+
* `tsconfig.json` excludes `src/templates` from typechecking — templates
|
|
12
|
+
* are source for a generated app, not for this package, and their
|
|
13
|
+
* imports only resolve once scaffolded. That exclusion is reasonable and
|
|
14
|
+
* it has a cost: nothing tells you when an example drifts away from the
|
|
15
|
+
* API it demonstrates. It is how `settings.options` survived in two
|
|
16
|
+
* templates through the 6.0 rename, where it would have generated a
|
|
17
|
+
* broken install.
|
|
18
|
+
*
|
|
19
|
+
* This is a blunt guard rather than a typecheck, but it catches the
|
|
20
|
+
* class of drift that matters: an example calling into a surface that
|
|
21
|
+
* was removed.
|
|
22
|
+
*/
|
|
23
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
24
|
+
import { dirname, join, resolve } from 'node:path';
|
|
25
|
+
import { fileURLToPath } from 'node:url';
|
|
26
|
+
import { describe, expect, it } from 'vitest';
|
|
27
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
const templatesRoot = resolve(here, 'templates');
|
|
29
|
+
/**
|
|
30
|
+
* Editor APIs removed in 6.0, with what replaced them.
|
|
31
|
+
*
|
|
32
|
+
* `textStyle` is deliberately absent: it is also the name of a property
|
|
33
|
+
* on serialized Lexical text nodes, which the seed and Markdown-import
|
|
34
|
+
* templates legitimately set. Matching it here would fail on those.
|
|
35
|
+
*/
|
|
36
|
+
const REMOVED = [
|
|
37
|
+
{
|
|
38
|
+
pattern: /settings\.options\b/,
|
|
39
|
+
was: 'EditorSettings.options',
|
|
40
|
+
now: 'settings.mode / settings.markdownShortcuts / settings.controls / settings.debug',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pattern: /\bmarkdownShortcutPlugin\b/,
|
|
44
|
+
was: 'options.markdownShortcutPlugin',
|
|
45
|
+
now: 'settings.markdownShortcuts',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
pattern: /\bshowTreeView\b/,
|
|
49
|
+
was: 'options.showTreeView',
|
|
50
|
+
now: 'settings.controls.treeView',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
pattern: /\bfrom '@byline\/richtext-lexical'[\s\S]{0,80}\bNodes\b/,
|
|
54
|
+
was: 'the Nodes export',
|
|
55
|
+
now: 'READABLE_NODES, which is a read vocabulary rather than a registration list',
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
function sourceFiles(dir) {
|
|
59
|
+
const found = [];
|
|
60
|
+
for (const entry of readdirSync(dir)) {
|
|
61
|
+
const full = join(dir, entry);
|
|
62
|
+
if (statSync(full).isDirectory()) {
|
|
63
|
+
found.push(...sourceFiles(full));
|
|
64
|
+
}
|
|
65
|
+
else if (/\.tsx?$/.test(entry)) {
|
|
66
|
+
found.push(full);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return found;
|
|
70
|
+
}
|
|
71
|
+
describe('shipped templates track the editor API', () => {
|
|
72
|
+
const files = sourceFiles(templatesRoot);
|
|
73
|
+
it('finds templates to check', () => {
|
|
74
|
+
// Guards the guard: a walk that silently returns nothing would make
|
|
75
|
+
// every assertion below vacuous.
|
|
76
|
+
expect(files.length).toBeGreaterThan(20);
|
|
77
|
+
});
|
|
78
|
+
for (const { pattern, was, now } of REMOVED) {
|
|
79
|
+
it(`uses no ${was}`, () => {
|
|
80
|
+
const offenders = files
|
|
81
|
+
.filter((file) => pattern.test(readFileSync(file, 'utf8')))
|
|
82
|
+
.map((file) => file.slice(templatesRoot.length + 1));
|
|
83
|
+
expect(offenders, `${was} was removed in 6.0 — use ${now}`).toEqual([]);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=templates-editor-api-drift.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates-editor-api-drift.test.js","sourceRoot":"","sources":["../src/templates-editor-api-drift.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACpD,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;AAEhD;;;;;;GAMG;AACH,MAAM,OAAO,GAAyD;IACpE;QACE,OAAO,EAAE,qBAAqB;QAC9B,GAAG,EAAE,wBAAwB;QAC7B,GAAG,EAAE,iFAAiF;KACvF;IACD;QACE,OAAO,EAAE,4BAA4B;QACrC,GAAG,EAAE,gCAAgC;QACrC,GAAG,EAAE,4BAA4B;KAClC;IACD;QACE,OAAO,EAAE,kBAAkB;QAC3B,GAAG,EAAE,sBAAsB;QAC3B,GAAG,EAAE,4BAA4B;KAClC;IACD;QACE,OAAO,EAAE,yDAAyD;QAClE,GAAG,EAAE,kBAAkB;QACvB,GAAG,EAAE,4EAA4E;KAClF;CACF,CAAA;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC7B,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAA;QAClC,CAAC;aAAM,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,MAAM,KAAK,GAAG,WAAW,CAAC,aAAa,CAAC,CAAA;IAExC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,oEAAoE;QACpE,iCAAiC;QACjC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;IAEF,KAAK,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,OAAO,EAAE,CAAC;QAC5C,EAAE,CAAC,WAAW,GAAG,EAAE,EAAE,GAAG,EAAE;YACxB,MAAM,SAAS,GAAG,KAAK;iBACpB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;iBAC1D,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAA;YAEtD,MAAM,CAAC,SAAS,EAAE,GAAG,GAAG,6BAA6B,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACzE,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@byline/cli",
|
|
3
3
|
"private": false,
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "6.0.0",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=20.9.0"
|
|
8
8
|
},
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"yaml": "^2.9.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@biomejs/biome": "2.5.
|
|
51
|
+
"@biomejs/biome": "2.5.13",
|
|
52
52
|
"@types/mdast": "^4.0.4",
|
|
53
|
-
"@types/node": "^26.5.
|
|
53
|
+
"@types/node": "^26.5.1",
|
|
54
54
|
"@types/pg": "^8.23.1",
|
|
55
55
|
"@types/semver": "^7.8.0",
|
|
56
56
|
"dotenv": "^17.4.2",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"typescript": "^7.0.2",
|
|
62
62
|
"unified": "^11.0.5",
|
|
63
63
|
"vitest": "^5.0.0",
|
|
64
|
-
"@byline/core": "
|
|
64
|
+
"@byline/core": "6.0.0"
|
|
65
65
|
},
|
|
66
66
|
"publishConfig": {
|
|
67
67
|
"access": "public",
|