@railway/inkwell 1.4.0 → 2.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/index.cjs +78 -4
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +78 -4
- package/package.json +1 -1
- package/src/styles.css +98 -37
package/dist/index.cjs
CHANGED
|
@@ -3163,6 +3163,71 @@ function CopyCodeBlock({
|
|
|
3163
3163
|
/* @__PURE__ */ jsxRuntime.jsx("pre", { ref: preRef, ...props, children })
|
|
3164
3164
|
] });
|
|
3165
3165
|
}
|
|
3166
|
+
function splitTextOnNewlines(text) {
|
|
3167
|
+
if (!text.value.includes("\n")) return [text];
|
|
3168
|
+
const parts = text.value.split("\n");
|
|
3169
|
+
const result = [];
|
|
3170
|
+
for (let i = 0; i < parts.length; i++) {
|
|
3171
|
+
if (parts[i] !== "") {
|
|
3172
|
+
result.push({ type: "text", value: parts[i] });
|
|
3173
|
+
}
|
|
3174
|
+
if (i < parts.length - 1) {
|
|
3175
|
+
result.push({ type: "break" });
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
return result;
|
|
3179
|
+
}
|
|
3180
|
+
function expandParagraphChildren(children) {
|
|
3181
|
+
let changed = false;
|
|
3182
|
+
const next = [];
|
|
3183
|
+
for (const child of children) {
|
|
3184
|
+
if (child.type === "text" && child.value.includes("\n")) {
|
|
3185
|
+
next.push(...splitTextOnNewlines(child));
|
|
3186
|
+
changed = true;
|
|
3187
|
+
} else {
|
|
3188
|
+
next.push(child);
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
return changed ? next : null;
|
|
3192
|
+
}
|
|
3193
|
+
function remarkSoftBreakAsBreak() {
|
|
3194
|
+
return (tree) => {
|
|
3195
|
+
unistUtilVisit.visit(tree, "paragraph", (node) => {
|
|
3196
|
+
const expanded = expandParagraphChildren(node.children);
|
|
3197
|
+
if (expanded) node.children = expanded;
|
|
3198
|
+
});
|
|
3199
|
+
};
|
|
3200
|
+
}
|
|
3201
|
+
function remarkSoftBreakAsParagraph() {
|
|
3202
|
+
return (tree) => {
|
|
3203
|
+
unistUtilVisit.visit(tree, "paragraph", (node, index, parent) => {
|
|
3204
|
+
if (!parent || index == null) return;
|
|
3205
|
+
const expanded = expandParagraphChildren(node.children) ?? node.children.slice();
|
|
3206
|
+
const breakIndices = [];
|
|
3207
|
+
for (let i = 0; i < expanded.length; i++) {
|
|
3208
|
+
if (expanded[i].type === "break") breakIndices.push(i);
|
|
3209
|
+
}
|
|
3210
|
+
if (breakIndices.length === 0) {
|
|
3211
|
+
return;
|
|
3212
|
+
}
|
|
3213
|
+
const newParagraphs = [];
|
|
3214
|
+
let start = 0;
|
|
3215
|
+
for (const breakIdx of [...breakIndices, expanded.length]) {
|
|
3216
|
+
if (breakIdx > start) {
|
|
3217
|
+
newParagraphs.push({
|
|
3218
|
+
type: "paragraph",
|
|
3219
|
+
children: expanded.slice(start, breakIdx)
|
|
3220
|
+
});
|
|
3221
|
+
}
|
|
3222
|
+
start = breakIdx + 1;
|
|
3223
|
+
}
|
|
3224
|
+
parent.children.splice(index, 1, ...newParagraphs);
|
|
3225
|
+
return [unistUtilVisit.SKIP, index + newParagraphs.length];
|
|
3226
|
+
});
|
|
3227
|
+
};
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
// src/renderer/markdown-parser.ts
|
|
3166
3231
|
var MENTION_TAG_PREFIX = "inkwell-mention-";
|
|
3167
3232
|
function rehypeMentions(mentions) {
|
|
3168
3233
|
return () => (tree) => {
|
|
@@ -3225,7 +3290,14 @@ function rehypeMentions(mentions) {
|
|
|
3225
3290
|
};
|
|
3226
3291
|
}
|
|
3227
3292
|
function createProcessor2(options = {}) {
|
|
3228
|
-
const proc = unified.unified().use(remarkParse__default.default).use(remarkGfm__default.default).use(remarkNoTables).use(remarkFlattenBlockquotes)
|
|
3293
|
+
const proc = unified.unified().use(remarkParse__default.default).use(remarkGfm__default.default).use(remarkNoTables).use(remarkFlattenBlockquotes);
|
|
3294
|
+
const softBreak = options.softBreak ?? "paragraph";
|
|
3295
|
+
if (softBreak === "br") {
|
|
3296
|
+
proc.use(remarkSoftBreakAsBreak);
|
|
3297
|
+
} else if (softBreak === "paragraph") {
|
|
3298
|
+
proc.use(remarkSoftBreakAsParagraph);
|
|
3299
|
+
}
|
|
3300
|
+
proc.use(remarkRehype__default.default);
|
|
3229
3301
|
const plugins = options.rehypePlugins ?? [
|
|
3230
3302
|
[rehypeHighlight__default.default, { detect: true }]
|
|
3231
3303
|
];
|
|
@@ -3284,7 +3356,8 @@ function InkwellRenderer({
|
|
|
3284
3356
|
className,
|
|
3285
3357
|
components,
|
|
3286
3358
|
rehypePlugins,
|
|
3287
|
-
mentions
|
|
3359
|
+
mentions,
|
|
3360
|
+
softBreak
|
|
3288
3361
|
}) {
|
|
3289
3362
|
const mergedComponents = react.useMemo(
|
|
3290
3363
|
() => ({ pre: CopyCodeBlock, ...components }),
|
|
@@ -3294,9 +3367,10 @@ function InkwellRenderer({
|
|
|
3294
3367
|
() => parseMarkdown(content, {
|
|
3295
3368
|
components: mergedComponents,
|
|
3296
3369
|
rehypePlugins,
|
|
3297
|
-
mentions
|
|
3370
|
+
mentions,
|
|
3371
|
+
softBreak
|
|
3298
3372
|
}),
|
|
3299
|
-
[content, mergedComponents, rehypePlugins, mentions]
|
|
3373
|
+
[content, mergedComponents, rehypePlugins, mentions, softBreak]
|
|
3300
3374
|
);
|
|
3301
3375
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `inkwell-renderer ${className ?? ""}`, children: rendered });
|
|
3302
3376
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -110,6 +110,16 @@ interface InkwellEditorProps {
|
|
|
110
110
|
/** Called when submitOnEnter handles Enter. */
|
|
111
111
|
onSubmit?: (content: string) => void;
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* How `InkwellRenderer` handles single-newline soft breaks in source markdown.
|
|
115
|
+
* - `"paragraph"` (default): split the enclosing paragraph at the soft break,
|
|
116
|
+
* producing two `<p>` elements with normal paragraph margins.
|
|
117
|
+
* - `"br"`: emit a `<br />`. Matches GFM-style behavior (and Showdown with
|
|
118
|
+
* `simpleLineBreaks: true`).
|
|
119
|
+
* - `"preserve"`: keep as a literal `\n` text node. The browser collapses it
|
|
120
|
+
* to whitespace per CSS. Matches strict CommonMark.
|
|
121
|
+
*/
|
|
122
|
+
type InkwellSoftBreakBehavior = "preserve" | "br" | "paragraph";
|
|
113
123
|
interface InkwellRendererProps {
|
|
114
124
|
/** Markdown source content string. */
|
|
115
125
|
content: string;
|
|
@@ -121,11 +131,15 @@ interface InkwellRendererProps {
|
|
|
121
131
|
rehypePlugins?: RehypePluginConfig[];
|
|
122
132
|
/** Mention patterns to expand in rendered text. */
|
|
123
133
|
mentions?: MentionRenderer[];
|
|
134
|
+
/** How to render single-newline soft breaks. Defaults to `"paragraph"`. */
|
|
135
|
+
softBreak?: InkwellSoftBreakBehavior;
|
|
124
136
|
}
|
|
125
137
|
interface ParseMarkdownOptions {
|
|
126
138
|
components?: InkwellComponents;
|
|
127
139
|
rehypePlugins?: RehypePluginConfig[];
|
|
128
140
|
mentions?: MentionRenderer[];
|
|
141
|
+
/** How to render single-newline soft breaks. Defaults to `"paragraph"`. */
|
|
142
|
+
softBreak?: InkwellSoftBreakBehavior;
|
|
129
143
|
}
|
|
130
144
|
interface MentionRenderer {
|
|
131
145
|
/** Regular expression applied to text-node content. */
|
|
@@ -482,11 +496,11 @@ declare function createSnippetsPlugin({ snippets, name, trigger, }: SnippetsPlug
|
|
|
482
496
|
*/
|
|
483
497
|
declare function htmlToMarkdown(html: string): string;
|
|
484
498
|
|
|
485
|
-
declare function InkwellRenderer({ content, className, components, rehypePlugins, mentions, }: InkwellRendererProps): ReactNode;
|
|
499
|
+
declare function InkwellRenderer({ content, className, components, rehypePlugins, mentions, softBreak, }: InkwellRendererProps): ReactNode;
|
|
486
500
|
|
|
487
501
|
/**
|
|
488
502
|
* Parse a markdown string into React elements synchronously
|
|
489
503
|
*/
|
|
490
504
|
declare function parseMarkdown(content: string, options?: ParseMarkdownOptions): ReactNode;
|
|
491
505
|
|
|
492
|
-
export { type Attachment, type AttachmentUploadResult, type AttachmentsHandle, type AttachmentsPluginOptions, type BubbleMenuItem, type BubbleMenuItemProps, type BubbleMenuOptions, type CompletionsPluginOptions, type EmojiItem, type EmojiPluginOptions, type InkwellComponents, InkwellEditor, type InkwellEditorClassNames, type InkwellEditorFocusOptions, type InkwellEditorHandle, type InkwellEditorProps, type InkwellEditorState, type InkwellEditorStyles, type InkwellFeatures, type InkwellPlugin, type InkwellPluginActivation, type InkwellPluginEditor, type InkwellPluginPlaceholder, InkwellRenderer, type InkwellRendererProps, type MentionItem, type MentionRenderer, type MentionsPluginOptions, type ParseMarkdownOptions, type PluginInsertDataContext, type PluginKeyDownContext, type PluginRenderProps, type RehypePluginConfig, type SlashCommandArg, type SlashCommandChoice, type SlashCommandExecution, type SlashCommandItem, type SlashCommandsPluginOptions, type Snippet, type SnippetsPluginOptions, type SubscribeForwardedKey, createAttachmentsPlugin, createBubbleMenuPlugin, createCompletionsPlugin, createEmojiPlugin, createMentionsPlugin, createSlashCommandsPlugin, createSnippetsPlugin, defaultBubbleMenuItems, defaultEmojis, htmlToMarkdown, parseMarkdown };
|
|
506
|
+
export { type Attachment, type AttachmentUploadResult, type AttachmentsHandle, type AttachmentsPluginOptions, type BubbleMenuItem, type BubbleMenuItemProps, type BubbleMenuOptions, type CompletionsPluginOptions, type EmojiItem, type EmojiPluginOptions, type InkwellComponents, InkwellEditor, type InkwellEditorClassNames, type InkwellEditorFocusOptions, type InkwellEditorHandle, type InkwellEditorProps, type InkwellEditorState, type InkwellEditorStyles, type InkwellFeatures, type InkwellPlugin, type InkwellPluginActivation, type InkwellPluginEditor, type InkwellPluginPlaceholder, InkwellRenderer, type InkwellRendererProps, type InkwellSoftBreakBehavior, type MentionItem, type MentionRenderer, type MentionsPluginOptions, type ParseMarkdownOptions, type PluginInsertDataContext, type PluginKeyDownContext, type PluginRenderProps, type RehypePluginConfig, type SlashCommandArg, type SlashCommandChoice, type SlashCommandExecution, type SlashCommandItem, type SlashCommandsPluginOptions, type Snippet, type SnippetsPluginOptions, type SubscribeForwardedKey, createAttachmentsPlugin, createBubbleMenuPlugin, createCompletionsPlugin, createEmojiPlugin, createMentionsPlugin, createSlashCommandsPlugin, createSnippetsPlugin, defaultBubbleMenuItems, defaultEmojis, htmlToMarkdown, parseMarkdown };
|
package/dist/index.d.ts
CHANGED
|
@@ -110,6 +110,16 @@ interface InkwellEditorProps {
|
|
|
110
110
|
/** Called when submitOnEnter handles Enter. */
|
|
111
111
|
onSubmit?: (content: string) => void;
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* How `InkwellRenderer` handles single-newline soft breaks in source markdown.
|
|
115
|
+
* - `"paragraph"` (default): split the enclosing paragraph at the soft break,
|
|
116
|
+
* producing two `<p>` elements with normal paragraph margins.
|
|
117
|
+
* - `"br"`: emit a `<br />`. Matches GFM-style behavior (and Showdown with
|
|
118
|
+
* `simpleLineBreaks: true`).
|
|
119
|
+
* - `"preserve"`: keep as a literal `\n` text node. The browser collapses it
|
|
120
|
+
* to whitespace per CSS. Matches strict CommonMark.
|
|
121
|
+
*/
|
|
122
|
+
type InkwellSoftBreakBehavior = "preserve" | "br" | "paragraph";
|
|
113
123
|
interface InkwellRendererProps {
|
|
114
124
|
/** Markdown source content string. */
|
|
115
125
|
content: string;
|
|
@@ -121,11 +131,15 @@ interface InkwellRendererProps {
|
|
|
121
131
|
rehypePlugins?: RehypePluginConfig[];
|
|
122
132
|
/** Mention patterns to expand in rendered text. */
|
|
123
133
|
mentions?: MentionRenderer[];
|
|
134
|
+
/** How to render single-newline soft breaks. Defaults to `"paragraph"`. */
|
|
135
|
+
softBreak?: InkwellSoftBreakBehavior;
|
|
124
136
|
}
|
|
125
137
|
interface ParseMarkdownOptions {
|
|
126
138
|
components?: InkwellComponents;
|
|
127
139
|
rehypePlugins?: RehypePluginConfig[];
|
|
128
140
|
mentions?: MentionRenderer[];
|
|
141
|
+
/** How to render single-newline soft breaks. Defaults to `"paragraph"`. */
|
|
142
|
+
softBreak?: InkwellSoftBreakBehavior;
|
|
129
143
|
}
|
|
130
144
|
interface MentionRenderer {
|
|
131
145
|
/** Regular expression applied to text-node content. */
|
|
@@ -482,11 +496,11 @@ declare function createSnippetsPlugin({ snippets, name, trigger, }: SnippetsPlug
|
|
|
482
496
|
*/
|
|
483
497
|
declare function htmlToMarkdown(html: string): string;
|
|
484
498
|
|
|
485
|
-
declare function InkwellRenderer({ content, className, components, rehypePlugins, mentions, }: InkwellRendererProps): ReactNode;
|
|
499
|
+
declare function InkwellRenderer({ content, className, components, rehypePlugins, mentions, softBreak, }: InkwellRendererProps): ReactNode;
|
|
486
500
|
|
|
487
501
|
/**
|
|
488
502
|
* Parse a markdown string into React elements synchronously
|
|
489
503
|
*/
|
|
490
504
|
declare function parseMarkdown(content: string, options?: ParseMarkdownOptions): ReactNode;
|
|
491
505
|
|
|
492
|
-
export { type Attachment, type AttachmentUploadResult, type AttachmentsHandle, type AttachmentsPluginOptions, type BubbleMenuItem, type BubbleMenuItemProps, type BubbleMenuOptions, type CompletionsPluginOptions, type EmojiItem, type EmojiPluginOptions, type InkwellComponents, InkwellEditor, type InkwellEditorClassNames, type InkwellEditorFocusOptions, type InkwellEditorHandle, type InkwellEditorProps, type InkwellEditorState, type InkwellEditorStyles, type InkwellFeatures, type InkwellPlugin, type InkwellPluginActivation, type InkwellPluginEditor, type InkwellPluginPlaceholder, InkwellRenderer, type InkwellRendererProps, type MentionItem, type MentionRenderer, type MentionsPluginOptions, type ParseMarkdownOptions, type PluginInsertDataContext, type PluginKeyDownContext, type PluginRenderProps, type RehypePluginConfig, type SlashCommandArg, type SlashCommandChoice, type SlashCommandExecution, type SlashCommandItem, type SlashCommandsPluginOptions, type Snippet, type SnippetsPluginOptions, type SubscribeForwardedKey, createAttachmentsPlugin, createBubbleMenuPlugin, createCompletionsPlugin, createEmojiPlugin, createMentionsPlugin, createSlashCommandsPlugin, createSnippetsPlugin, defaultBubbleMenuItems, defaultEmojis, htmlToMarkdown, parseMarkdown };
|
|
506
|
+
export { type Attachment, type AttachmentUploadResult, type AttachmentsHandle, type AttachmentsPluginOptions, type BubbleMenuItem, type BubbleMenuItemProps, type BubbleMenuOptions, type CompletionsPluginOptions, type EmojiItem, type EmojiPluginOptions, type InkwellComponents, InkwellEditor, type InkwellEditorClassNames, type InkwellEditorFocusOptions, type InkwellEditorHandle, type InkwellEditorProps, type InkwellEditorState, type InkwellEditorStyles, type InkwellFeatures, type InkwellPlugin, type InkwellPluginActivation, type InkwellPluginEditor, type InkwellPluginPlaceholder, InkwellRenderer, type InkwellRendererProps, type InkwellSoftBreakBehavior, type MentionItem, type MentionRenderer, type MentionsPluginOptions, type ParseMarkdownOptions, type PluginInsertDataContext, type PluginKeyDownContext, type PluginRenderProps, type RehypePluginConfig, type SlashCommandArg, type SlashCommandChoice, type SlashCommandExecution, type SlashCommandItem, type SlashCommandsPluginOptions, type Snippet, type SnippetsPluginOptions, type SubscribeForwardedKey, createAttachmentsPlugin, createBubbleMenuPlugin, createCompletionsPlugin, createEmojiPlugin, createMentionsPlugin, createSlashCommandsPlugin, createSnippetsPlugin, defaultBubbleMenuItems, defaultEmojis, htmlToMarkdown, parseMarkdown };
|
package/dist/index.js
CHANGED
|
@@ -3148,6 +3148,71 @@ function CopyCodeBlock({
|
|
|
3148
3148
|
/* @__PURE__ */ jsx("pre", { ref: preRef, ...props, children })
|
|
3149
3149
|
] });
|
|
3150
3150
|
}
|
|
3151
|
+
function splitTextOnNewlines(text) {
|
|
3152
|
+
if (!text.value.includes("\n")) return [text];
|
|
3153
|
+
const parts = text.value.split("\n");
|
|
3154
|
+
const result = [];
|
|
3155
|
+
for (let i = 0; i < parts.length; i++) {
|
|
3156
|
+
if (parts[i] !== "") {
|
|
3157
|
+
result.push({ type: "text", value: parts[i] });
|
|
3158
|
+
}
|
|
3159
|
+
if (i < parts.length - 1) {
|
|
3160
|
+
result.push({ type: "break" });
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
return result;
|
|
3164
|
+
}
|
|
3165
|
+
function expandParagraphChildren(children) {
|
|
3166
|
+
let changed = false;
|
|
3167
|
+
const next = [];
|
|
3168
|
+
for (const child of children) {
|
|
3169
|
+
if (child.type === "text" && child.value.includes("\n")) {
|
|
3170
|
+
next.push(...splitTextOnNewlines(child));
|
|
3171
|
+
changed = true;
|
|
3172
|
+
} else {
|
|
3173
|
+
next.push(child);
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
return changed ? next : null;
|
|
3177
|
+
}
|
|
3178
|
+
function remarkSoftBreakAsBreak() {
|
|
3179
|
+
return (tree) => {
|
|
3180
|
+
visit(tree, "paragraph", (node) => {
|
|
3181
|
+
const expanded = expandParagraphChildren(node.children);
|
|
3182
|
+
if (expanded) node.children = expanded;
|
|
3183
|
+
});
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3186
|
+
function remarkSoftBreakAsParagraph() {
|
|
3187
|
+
return (tree) => {
|
|
3188
|
+
visit(tree, "paragraph", (node, index, parent) => {
|
|
3189
|
+
if (!parent || index == null) return;
|
|
3190
|
+
const expanded = expandParagraphChildren(node.children) ?? node.children.slice();
|
|
3191
|
+
const breakIndices = [];
|
|
3192
|
+
for (let i = 0; i < expanded.length; i++) {
|
|
3193
|
+
if (expanded[i].type === "break") breakIndices.push(i);
|
|
3194
|
+
}
|
|
3195
|
+
if (breakIndices.length === 0) {
|
|
3196
|
+
return;
|
|
3197
|
+
}
|
|
3198
|
+
const newParagraphs = [];
|
|
3199
|
+
let start = 0;
|
|
3200
|
+
for (const breakIdx of [...breakIndices, expanded.length]) {
|
|
3201
|
+
if (breakIdx > start) {
|
|
3202
|
+
newParagraphs.push({
|
|
3203
|
+
type: "paragraph",
|
|
3204
|
+
children: expanded.slice(start, breakIdx)
|
|
3205
|
+
});
|
|
3206
|
+
}
|
|
3207
|
+
start = breakIdx + 1;
|
|
3208
|
+
}
|
|
3209
|
+
parent.children.splice(index, 1, ...newParagraphs);
|
|
3210
|
+
return [SKIP, index + newParagraphs.length];
|
|
3211
|
+
});
|
|
3212
|
+
};
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
// src/renderer/markdown-parser.ts
|
|
3151
3216
|
var MENTION_TAG_PREFIX = "inkwell-mention-";
|
|
3152
3217
|
function rehypeMentions(mentions) {
|
|
3153
3218
|
return () => (tree) => {
|
|
@@ -3210,7 +3275,14 @@ function rehypeMentions(mentions) {
|
|
|
3210
3275
|
};
|
|
3211
3276
|
}
|
|
3212
3277
|
function createProcessor2(options = {}) {
|
|
3213
|
-
const proc = unified().use(remarkParse).use(remarkGfm).use(remarkNoTables).use(remarkFlattenBlockquotes)
|
|
3278
|
+
const proc = unified().use(remarkParse).use(remarkGfm).use(remarkNoTables).use(remarkFlattenBlockquotes);
|
|
3279
|
+
const softBreak = options.softBreak ?? "paragraph";
|
|
3280
|
+
if (softBreak === "br") {
|
|
3281
|
+
proc.use(remarkSoftBreakAsBreak);
|
|
3282
|
+
} else if (softBreak === "paragraph") {
|
|
3283
|
+
proc.use(remarkSoftBreakAsParagraph);
|
|
3284
|
+
}
|
|
3285
|
+
proc.use(remarkRehype);
|
|
3214
3286
|
const plugins = options.rehypePlugins ?? [
|
|
3215
3287
|
[rehypeHighlight, { detect: true }]
|
|
3216
3288
|
];
|
|
@@ -3269,7 +3341,8 @@ function InkwellRenderer({
|
|
|
3269
3341
|
className,
|
|
3270
3342
|
components,
|
|
3271
3343
|
rehypePlugins,
|
|
3272
|
-
mentions
|
|
3344
|
+
mentions,
|
|
3345
|
+
softBreak
|
|
3273
3346
|
}) {
|
|
3274
3347
|
const mergedComponents = useMemo(
|
|
3275
3348
|
() => ({ pre: CopyCodeBlock, ...components }),
|
|
@@ -3279,9 +3352,10 @@ function InkwellRenderer({
|
|
|
3279
3352
|
() => parseMarkdown(content, {
|
|
3280
3353
|
components: mergedComponents,
|
|
3281
3354
|
rehypePlugins,
|
|
3282
|
-
mentions
|
|
3355
|
+
mentions,
|
|
3356
|
+
softBreak
|
|
3283
3357
|
}),
|
|
3284
|
-
[content, mergedComponents, rehypePlugins, mentions]
|
|
3358
|
+
[content, mergedComponents, rehypePlugins, mentions, softBreak]
|
|
3285
3359
|
);
|
|
3286
3360
|
return /* @__PURE__ */ jsx("div", { className: `inkwell-renderer ${className ?? ""}`, children: rendered });
|
|
3287
3361
|
}
|
package/package.json
CHANGED
package/src/styles.css
CHANGED
|
@@ -62,6 +62,34 @@
|
|
|
62
62
|
"JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo,
|
|
63
63
|
Consolas, monospace;
|
|
64
64
|
--inkwell-radius: 6px;
|
|
65
|
+
|
|
66
|
+
/* Typography & spacing. Defined once and consumed by both
|
|
67
|
+
`.inkwell-editor` and `.inkwell-renderer` so the two surfaces stay
|
|
68
|
+
WYSIWYG — what you type matches what renders. Override any token
|
|
69
|
+
on either surface to retune both (or use a per-surface selector
|
|
70
|
+
to retune just one). For chat-composer or compact embeds, set
|
|
71
|
+
`--inkwell-space-paragraph: 0` on the editor surface. */
|
|
72
|
+
--inkwell-font-size: 0.95rem;
|
|
73
|
+
--inkwell-line-height: 1.6;
|
|
74
|
+
--inkwell-heading-weight: 600;
|
|
75
|
+
--inkwell-heading-line-height: 1.3;
|
|
76
|
+
--inkwell-h1-size: 1.75em;
|
|
77
|
+
--inkwell-h2-size: 1.4em;
|
|
78
|
+
--inkwell-h3-size: 1.2em;
|
|
79
|
+
--inkwell-h4-size: 1em;
|
|
80
|
+
--inkwell-h5-size: 0.9em;
|
|
81
|
+
--inkwell-h6-size: 0.8em;
|
|
82
|
+
--inkwell-code-font-size: 0.85em;
|
|
83
|
+
|
|
84
|
+
--inkwell-space-paragraph: 0.5em;
|
|
85
|
+
--inkwell-space-heading: 0.75em;
|
|
86
|
+
--inkwell-space-blockquote: 1em;
|
|
87
|
+
--inkwell-space-list: 1em;
|
|
88
|
+
--inkwell-space-list-item: 0.25em;
|
|
89
|
+
--inkwell-list-indent: 1.5em;
|
|
90
|
+
--inkwell-space-code-block: 1em;
|
|
91
|
+
--inkwell-space-image: 1em;
|
|
92
|
+
--inkwell-space-hr: 2em;
|
|
65
93
|
}
|
|
66
94
|
|
|
67
95
|
@media (prefers-color-scheme: dark) {
|
|
@@ -118,8 +146,8 @@
|
|
|
118
146
|
border-radius: var(--inkwell-radius);
|
|
119
147
|
background: var(--inkwell-bg);
|
|
120
148
|
color: var(--inkwell-text);
|
|
121
|
-
line-height:
|
|
122
|
-
font-size:
|
|
149
|
+
line-height: var(--inkwell-line-height);
|
|
150
|
+
font-size: var(--inkwell-font-size);
|
|
123
151
|
transition: border-color 0.15s ease;
|
|
124
152
|
}
|
|
125
153
|
:where(.inkwell-editor:focus-within) {
|
|
@@ -127,8 +155,20 @@
|
|
|
127
155
|
}
|
|
128
156
|
|
|
129
157
|
/* `position: relative` on paragraphs is structural — Slate decorations and
|
|
130
|
-
inline children position against it.
|
|
131
|
-
|
|
158
|
+
inline children position against it.
|
|
159
|
+
|
|
160
|
+
Margin stays at `0` here even though the renderer's paragraphs use
|
|
161
|
+
`--inkwell-space-paragraph`. Reason: the editor's content model emits
|
|
162
|
+
one `<p>` per source line, so a blank line in Markdown becomes an
|
|
163
|
+
empty `<p>` node between two paragraphs (a cursor target, kept for
|
|
164
|
+
round-trip fidelity). With a non-zero paragraph margin, those empty
|
|
165
|
+
paragraphs add their own top/bottom margin on top of the real
|
|
166
|
+
paragraphs' margins — visually multiplying the gap and breaking the
|
|
167
|
+
WYSIWYG promise in the other direction (editor looks more airy than
|
|
168
|
+
the renderer). Until the empty-paragraph encoding is reworked, the
|
|
169
|
+
editor opts out of the shared paragraph-spacing token. Consumers
|
|
170
|
+
who want non-zero spacing in the editor can set the margin
|
|
171
|
+
themselves with a higher-specificity rule. */
|
|
132
172
|
.inkwell-editor p {
|
|
133
173
|
position: relative;
|
|
134
174
|
}
|
|
@@ -152,42 +192,43 @@
|
|
|
152
192
|
padding: 0.1em 0.35em;
|
|
153
193
|
border-radius: 4px;
|
|
154
194
|
font-family: var(--inkwell-font-mono);
|
|
155
|
-
font-size:
|
|
195
|
+
font-size: var(--inkwell-code-font-size);
|
|
156
196
|
}
|
|
157
197
|
|
|
158
198
|
:where(.inkwell-editor-blockquote) {
|
|
159
199
|
border-left: 3px solid var(--inkwell-border-strong);
|
|
160
200
|
padding-left: 0.85em;
|
|
161
|
-
margin:
|
|
201
|
+
margin: var(--inkwell-space-blockquote) 0;
|
|
162
202
|
color: var(--inkwell-text-muted);
|
|
163
203
|
}
|
|
164
204
|
|
|
165
205
|
:where(.inkwell-editor-heading) {
|
|
166
|
-
font-weight:
|
|
167
|
-
line-height:
|
|
206
|
+
font-weight: var(--inkwell-heading-weight);
|
|
207
|
+
line-height: var(--inkwell-heading-line-height);
|
|
208
|
+
margin: var(--inkwell-space-heading) 0;
|
|
168
209
|
color: var(--inkwell-text);
|
|
169
210
|
}
|
|
170
211
|
:where(.inkwell-editor-heading-1) {
|
|
171
|
-
font-size:
|
|
212
|
+
font-size: var(--inkwell-h1-size);
|
|
172
213
|
}
|
|
173
214
|
:where(.inkwell-editor-heading-2) {
|
|
174
|
-
font-size:
|
|
215
|
+
font-size: var(--inkwell-h2-size);
|
|
175
216
|
}
|
|
176
217
|
:where(.inkwell-editor-heading-3) {
|
|
177
|
-
font-size:
|
|
218
|
+
font-size: var(--inkwell-h3-size);
|
|
178
219
|
}
|
|
179
220
|
:where(.inkwell-editor-heading-4) {
|
|
180
|
-
font-size:
|
|
221
|
+
font-size: var(--inkwell-h4-size);
|
|
181
222
|
}
|
|
182
223
|
:where(.inkwell-editor-heading-5) {
|
|
183
|
-
font-size:
|
|
224
|
+
font-size: var(--inkwell-h5-size);
|
|
184
225
|
}
|
|
185
226
|
:where(.inkwell-editor-heading-6) {
|
|
186
|
-
font-size:
|
|
227
|
+
font-size: var(--inkwell-h6-size);
|
|
187
228
|
}
|
|
188
229
|
|
|
189
230
|
:where(.inkwell-editor-image) {
|
|
190
|
-
margin:
|
|
231
|
+
margin: var(--inkwell-space-image) 0;
|
|
191
232
|
border-radius: var(--inkwell-radius);
|
|
192
233
|
overflow: hidden;
|
|
193
234
|
border: 1px solid transparent;
|
|
@@ -257,7 +298,7 @@
|
|
|
257
298
|
:where(.inkwell-editor .inkwell-editor-code-fence),
|
|
258
299
|
:where(.inkwell-renderer pre code) {
|
|
259
300
|
font-family: var(--inkwell-font-mono);
|
|
260
|
-
font-size:
|
|
301
|
+
font-size: var(--inkwell-code-font-size);
|
|
261
302
|
line-height: 1.55;
|
|
262
303
|
}
|
|
263
304
|
/* Wrapping behavior for code lines stays structural — Slate emits one
|
|
@@ -442,40 +483,61 @@
|
|
|
442
483
|
`!important`. */
|
|
443
484
|
:where(.inkwell-renderer) {
|
|
444
485
|
color: var(--inkwell-text);
|
|
445
|
-
line-height:
|
|
446
|
-
font-size:
|
|
486
|
+
line-height: var(--inkwell-line-height);
|
|
487
|
+
font-size: var(--inkwell-font-size);
|
|
447
488
|
}
|
|
448
489
|
:where(.inkwell-renderer :first-child) {
|
|
449
490
|
margin-top: 0;
|
|
450
491
|
}
|
|
451
492
|
:where(.inkwell-renderer h1) {
|
|
452
|
-
font-size:
|
|
453
|
-
font-weight:
|
|
454
|
-
|
|
493
|
+
font-size: var(--inkwell-h1-size);
|
|
494
|
+
font-weight: var(--inkwell-heading-weight);
|
|
495
|
+
line-height: var(--inkwell-heading-line-height);
|
|
496
|
+
margin: var(--inkwell-space-heading) 0;
|
|
455
497
|
}
|
|
456
498
|
:where(.inkwell-renderer h2) {
|
|
457
|
-
font-size:
|
|
458
|
-
font-weight:
|
|
459
|
-
|
|
499
|
+
font-size: var(--inkwell-h2-size);
|
|
500
|
+
font-weight: var(--inkwell-heading-weight);
|
|
501
|
+
line-height: var(--inkwell-heading-line-height);
|
|
502
|
+
margin: var(--inkwell-space-heading) 0;
|
|
460
503
|
}
|
|
461
504
|
:where(.inkwell-renderer h3) {
|
|
462
|
-
font-size:
|
|
463
|
-
font-weight:
|
|
464
|
-
|
|
505
|
+
font-size: var(--inkwell-h3-size);
|
|
506
|
+
font-weight: var(--inkwell-heading-weight);
|
|
507
|
+
line-height: var(--inkwell-heading-line-height);
|
|
508
|
+
margin: var(--inkwell-space-heading) 0;
|
|
509
|
+
}
|
|
510
|
+
:where(.inkwell-renderer h4) {
|
|
511
|
+
font-size: var(--inkwell-h4-size);
|
|
512
|
+
font-weight: var(--inkwell-heading-weight);
|
|
513
|
+
line-height: var(--inkwell-heading-line-height);
|
|
514
|
+
margin: var(--inkwell-space-heading) 0;
|
|
515
|
+
}
|
|
516
|
+
:where(.inkwell-renderer h5) {
|
|
517
|
+
font-size: var(--inkwell-h5-size);
|
|
518
|
+
font-weight: var(--inkwell-heading-weight);
|
|
519
|
+
line-height: var(--inkwell-heading-line-height);
|
|
520
|
+
margin: var(--inkwell-space-heading) 0;
|
|
521
|
+
}
|
|
522
|
+
:where(.inkwell-renderer h6) {
|
|
523
|
+
font-size: var(--inkwell-h6-size);
|
|
524
|
+
font-weight: var(--inkwell-heading-weight);
|
|
525
|
+
line-height: var(--inkwell-heading-line-height);
|
|
526
|
+
margin: var(--inkwell-space-heading) 0;
|
|
465
527
|
}
|
|
466
528
|
:where(.inkwell-renderer p) {
|
|
467
|
-
margin:
|
|
529
|
+
margin: var(--inkwell-space-paragraph) 0;
|
|
468
530
|
}
|
|
469
531
|
:where(.inkwell-renderer blockquote) {
|
|
470
532
|
border-left: 3px solid var(--inkwell-border-strong);
|
|
471
533
|
padding-left: 0.85em;
|
|
472
|
-
margin:
|
|
534
|
+
margin: var(--inkwell-space-blockquote) 0;
|
|
473
535
|
color: var(--inkwell-text-muted);
|
|
474
536
|
}
|
|
475
537
|
:where(.inkwell-renderer ul),
|
|
476
538
|
:where(.inkwell-renderer ol) {
|
|
477
|
-
padding-left:
|
|
478
|
-
margin:
|
|
539
|
+
padding-left: var(--inkwell-list-indent);
|
|
540
|
+
margin: var(--inkwell-space-list) 0;
|
|
479
541
|
}
|
|
480
542
|
:where(.inkwell-renderer ul) {
|
|
481
543
|
list-style: disc;
|
|
@@ -484,7 +546,7 @@
|
|
|
484
546
|
list-style: decimal;
|
|
485
547
|
}
|
|
486
548
|
:where(.inkwell-renderer li) {
|
|
487
|
-
margin:
|
|
549
|
+
margin: var(--inkwell-space-list-item) 0;
|
|
488
550
|
}
|
|
489
551
|
:where(.inkwell-renderer code) {
|
|
490
552
|
background: var(--inkwell-code-bg);
|
|
@@ -492,7 +554,7 @@
|
|
|
492
554
|
padding: 0.1em 0.35em;
|
|
493
555
|
border-radius: 4px;
|
|
494
556
|
font-family: var(--inkwell-font-mono);
|
|
495
|
-
font-size:
|
|
557
|
+
font-size: var(--inkwell-code-font-size);
|
|
496
558
|
}
|
|
497
559
|
/* Code-block wrapper position is structural — the copy button absolutely
|
|
498
560
|
positions inside it. */
|
|
@@ -533,7 +595,7 @@
|
|
|
533
595
|
color: var(--inkwell-text);
|
|
534
596
|
}
|
|
535
597
|
:where(.inkwell-renderer pre) {
|
|
536
|
-
margin:
|
|
598
|
+
margin: var(--inkwell-space-code-block) 0;
|
|
537
599
|
border-radius: var(--inkwell-radius);
|
|
538
600
|
overflow: auto;
|
|
539
601
|
border: 1px solid var(--inkwell-border);
|
|
@@ -544,7 +606,6 @@
|
|
|
544
606
|
padding: 0.85em 1em;
|
|
545
607
|
background: transparent;
|
|
546
608
|
color: var(--inkwell-text);
|
|
547
|
-
font-size: 0.82em;
|
|
548
609
|
}
|
|
549
610
|
:where(.inkwell-renderer a) {
|
|
550
611
|
color: var(--inkwell-accent);
|
|
@@ -554,7 +615,7 @@
|
|
|
554
615
|
:where(.inkwell-renderer hr) {
|
|
555
616
|
border: none;
|
|
556
617
|
border-top: 1px solid var(--inkwell-border);
|
|
557
|
-
margin:
|
|
618
|
+
margin: var(--inkwell-space-hr) 0;
|
|
558
619
|
}
|
|
559
620
|
:where(.inkwell-renderer strong) {
|
|
560
621
|
font-weight: 600;
|
|
@@ -569,5 +630,5 @@
|
|
|
569
630
|
max-width: 100%;
|
|
570
631
|
height: auto;
|
|
571
632
|
border-radius: var(--inkwell-radius);
|
|
572
|
-
margin:
|
|
633
|
+
margin: var(--inkwell-space-image) 0;
|
|
573
634
|
}
|