@riducms/plugin-richtext 0.2.3 → 0.3.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/README.md +7 -1
- package/package.json +7 -5
- package/src/block/rich-text-block-card.scss +139 -0
- package/src/block/rich-text-block-card.svelte +42 -21
- package/src/block/rich-text-block-clipboard.ts +1 -1
- package/src/block/rich-text-block-node.ts +1 -1
- package/src/block/rich-text-blocks-plugin.svelte +5 -2
- package/src/document-validation.ts +7 -5
- package/src/field/reference-node-placement.ts +49 -0
- package/src/field/rich-text-blocks.ts +1 -5
- package/src/field/rich-text-config.ts +1 -4
- package/src/field/rich-text-document.ts +1 -4
- package/src/field/rich-text-editor.svelte +105 -57
- package/src/field/rich-text-footer.svelte +7 -12
- package/src/field/rich-text-markdown.ts +62 -0
- package/src/link/link-url.ts +30 -0
- package/src/link/rich-text-link-plugin.svelte +528 -0
- package/src/link/rich-text-link.scss +144 -0
- package/src/link/safe-link-transform.ts +20 -0
- package/src/link-url-policy.ts +14 -0
- package/src/menu/rich-text-block-toolbar.svelte +403 -70
- package/src/menu/rich-text-commands.ts +10 -1
- package/src/menu/rich-text-menu.scss +92 -0
- package/src/menu/rich-text-menu.svelte +62 -69
- package/src/menu/rich-text-option-filter.ts +30 -0
- package/src/menu/rich-text-options.ts +81 -84
- package/src/menu/rich-text-slash-menu.svelte +15 -11
- package/src/messages.ts +72 -27
- package/src/relationship/rich-text-relationship-node.scss +98 -0
- package/src/relationship/rich-text-relationship-node.svelte +38 -32
- package/src/relationship/rich-text-relationship-plugin.svelte +24 -40
- package/src/render/rich-text.svelte +10 -5
- package/src/render.ts +3 -8
- package/src/styles/integration.scss +384 -0
- package/src/toolbar/PAYLOAD-LICENSE.md +22 -0
- package/src/toolbar/rich-text-floating-toolbar.svelte +331 -169
- package/src/toolbar/rich-text-toolbar.scss +80 -0
- package/src/toolbar/toolbar-icon.svelte +200 -30
- package/src/upload/rich-text-upload-node.scss +308 -0
- package/src/upload/rich-text-upload-node.svelte +96 -125
- package/src/upload/rich-text-upload-node.ts +1 -0
- package/src/upload/rich-text-upload-plugin.svelte +10 -33
- package/src/styles/integration.css +0 -83
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
useLexicalNodeSelection,
|
|
6
6
|
} from "@hvniel/lexical-svelte";
|
|
7
7
|
import { getAdminI18n } from "@riducms/plugin";
|
|
8
|
-
import type { NodeKey } from "lexical";
|
|
9
|
-
import {
|
|
8
|
+
import type { ElementFormatType, NodeKey } from "lexical";
|
|
9
|
+
import { Button, Textarea } from "@riducms/ui";
|
|
10
|
+
import ReplaceIcon from "~icons/lucide/refresh-cw";
|
|
11
|
+
import RemoveIcon from "~icons/lucide/x";
|
|
10
12
|
|
|
11
13
|
import { getRichTextAuthoringHost } from "@plugin-richtext/field/rich-text-context.svelte";
|
|
12
14
|
import {
|
|
@@ -14,13 +16,21 @@
|
|
|
14
16
|
REMOVE_UPLOAD_COMMAND,
|
|
15
17
|
UPDATE_UPLOAD_CAPTION_COMMAND,
|
|
16
18
|
} from "@plugin-richtext/menu/rich-text-commands";
|
|
19
|
+
import "@plugin-richtext/upload/rich-text-upload-node.scss";
|
|
17
20
|
|
|
18
21
|
let {
|
|
19
22
|
caption,
|
|
20
23
|
documentID,
|
|
24
|
+
format,
|
|
21
25
|
nodeKey,
|
|
22
26
|
relationTo,
|
|
23
|
-
}: {
|
|
27
|
+
}: {
|
|
28
|
+
caption: string;
|
|
29
|
+
documentID: string;
|
|
30
|
+
format: ElementFormatType;
|
|
31
|
+
nodeKey: NodeKey;
|
|
32
|
+
relationTo: string;
|
|
33
|
+
} = $props();
|
|
24
34
|
const editor = useLexicalComposerContext()[0];
|
|
25
35
|
const isEditable = useLexicalEditable();
|
|
26
36
|
const i18n = getAdminI18n();
|
|
@@ -37,17 +47,27 @@
|
|
|
37
47
|
const altText = $derived(typeof document?.alt === "string" ? document.alt.trim() : "");
|
|
38
48
|
const extension = $derived(fileExtension(filename));
|
|
39
49
|
const imageURL = $derived(
|
|
40
|
-
typeof document?.
|
|
41
|
-
typeof document.
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
typeof document?.mimeType === "string" && document.mimeType.startsWith("image/")
|
|
51
|
+
? typeof document.thumbnailURL === "string" && document.thumbnailURL !== ""
|
|
52
|
+
? document.thumbnailURL
|
|
53
|
+
: typeof document.url === "string"
|
|
54
|
+
? document.url
|
|
55
|
+
: undefined
|
|
44
56
|
: undefined
|
|
45
57
|
);
|
|
58
|
+
const mediaWidth = $derived(positiveDimension(document?.width));
|
|
59
|
+
const mediaHeight = $derived(positiveDimension(document?.height));
|
|
60
|
+
const mediaAspect = $derived(
|
|
61
|
+
mediaWidth !== undefined && mediaHeight !== undefined ? mediaWidth / mediaHeight : 1
|
|
62
|
+
);
|
|
63
|
+
const mediaWidthLimit = $derived(`${Math.min(450, Math.max(240, 450 * mediaAspect))}px`);
|
|
46
64
|
|
|
47
65
|
$effect(() => {
|
|
48
66
|
if (authoring === undefined) return;
|
|
49
67
|
void authoring.documentRevision;
|
|
50
68
|
const request = new AbortController();
|
|
69
|
+
document = undefined;
|
|
70
|
+
loadError = false;
|
|
51
71
|
authoring
|
|
52
72
|
.findDocument(relationTo, documentID, request.signal)
|
|
53
73
|
.then((value) => {
|
|
@@ -110,152 +130,103 @@
|
|
|
110
130
|
const match = /\.([a-z0-9]{1,8})$/i.exec(value);
|
|
111
131
|
return match?.[1]?.toLocaleUpperCase(i18n.language) ?? i18n.t("plugin.richtext:asset.file");
|
|
112
132
|
}
|
|
133
|
+
|
|
134
|
+
function positiveDimension(value: unknown) {
|
|
135
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
136
|
+
}
|
|
113
137
|
</script>
|
|
114
138
|
|
|
115
139
|
<figure
|
|
116
140
|
class={[
|
|
117
|
-
"
|
|
118
|
-
isSelected() && "
|
|
141
|
+
"ridu-richtext-upload-card",
|
|
142
|
+
isSelected() && "is-selected",
|
|
143
|
+
!isEditable() && "is-read-only",
|
|
119
144
|
]}
|
|
145
|
+
data-selected={isSelected() || undefined}
|
|
146
|
+
data-align={format || undefined}
|
|
147
|
+
aria-busy={authoring !== undefined && document === undefined && !loadError}
|
|
148
|
+
style:--ridu-richtext-upload-aspect={mediaAspect}
|
|
149
|
+
style:--ridu-richtext-upload-width={mediaWidthLimit}
|
|
120
150
|
role="group"
|
|
121
151
|
aria-label={i18n.t("plugin.richtext:asset.label", {
|
|
122
152
|
collection: collection?.labels.singular ?? relationTo,
|
|
123
153
|
filename,
|
|
124
154
|
})}
|
|
125
155
|
>
|
|
126
|
-
<div class="
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
]}
|
|
139
|
-
>
|
|
140
|
-
{#if imageURL !== undefined}
|
|
141
|
-
<img
|
|
142
|
-
class="absolute inset-0 block size-full object-cover"
|
|
143
|
-
src={imageURL}
|
|
144
|
-
alt={altText}
|
|
145
|
-
/>
|
|
146
|
-
{:else}
|
|
147
|
-
<span
|
|
148
|
-
class="grid max-w-[80%] place-items-center gap-[0.45rem] font-mono text-[11px] leading-normal tracking-[0.12em] text-foreground-muted uppercase"
|
|
149
|
-
aria-hidden="true"
|
|
150
|
-
>
|
|
151
|
-
<strong class="text-[13px] font-medium">
|
|
152
|
-
{loadError ? i18n.t("plugin.richtext:asset.unavailable") : extension}
|
|
153
|
-
</strong>
|
|
154
|
-
<span class="max-w-full truncate text-foreground-faint">
|
|
155
|
-
{loadError ? i18n.t("plugin.richtext:asset.couldNotLoad") : filename}
|
|
156
|
-
</span>
|
|
157
|
-
</span>
|
|
158
|
-
{/if}
|
|
159
|
-
</span>
|
|
160
|
-
</button>
|
|
161
|
-
{:else}
|
|
162
|
-
<span
|
|
163
|
-
class={[
|
|
164
|
-
"ridu-richtext-upload-preview relative grid aspect-[16/7] w-full place-items-center overflow-hidden bg-background",
|
|
165
|
-
document === undefined && !loadError && "is-loading",
|
|
166
|
-
]}
|
|
167
|
-
>
|
|
168
|
-
{#if imageURL !== undefined}
|
|
169
|
-
<img class="absolute inset-0 block size-full object-cover" src={imageURL} alt={altText} />
|
|
170
|
-
{:else}
|
|
171
|
-
<span
|
|
172
|
-
class="font-mono text-[11px] leading-normal tracking-[0.12em] text-foreground-muted uppercase"
|
|
173
|
-
>
|
|
156
|
+
<div class="ridu-richtext-upload-card__media">
|
|
157
|
+
<span
|
|
158
|
+
class={[
|
|
159
|
+
"ridu-richtext-upload-preview ridu-richtext-upload-card__preview",
|
|
160
|
+
document === undefined && !loadError && "is-loading",
|
|
161
|
+
]}
|
|
162
|
+
>
|
|
163
|
+
{#if imageURL !== undefined}
|
|
164
|
+
<img class="ridu-richtext-upload-card__image" src={imageURL} alt={altText} />
|
|
165
|
+
{:else}
|
|
166
|
+
<span class="ridu-richtext-upload-card__file-preview">
|
|
167
|
+
<strong class="ridu-richtext-upload-card__extension">
|
|
174
168
|
{loadError ? i18n.t("plugin.richtext:asset.unavailable") : extension}
|
|
169
|
+
</strong>
|
|
170
|
+
<span class="ridu-richtext-upload-card__preview-name">
|
|
171
|
+
{loadError ? i18n.t("plugin.richtext:asset.couldNotLoad") : filename}
|
|
175
172
|
</span>
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
173
|
+
</span>
|
|
174
|
+
{/if}
|
|
175
|
+
</span>
|
|
179
176
|
|
|
180
177
|
{#if isEditable()}
|
|
181
178
|
<div
|
|
182
|
-
class={[
|
|
183
|
-
|
|
184
|
-
isSelected() && "pointer-events-auto opacity-100",
|
|
185
|
-
]}
|
|
179
|
+
class={["ridu-richtext-upload-card__actions", isSelected() && "is-visible"]}
|
|
180
|
+
role="group"
|
|
186
181
|
aria-label={i18n.t("plugin.richtext:asset.actions")}
|
|
187
182
|
>
|
|
183
|
+
<Button
|
|
184
|
+
class="ridu-richtext-upload-card__action"
|
|
185
|
+
variant="ghost"
|
|
186
|
+
size="icon-sm"
|
|
187
|
+
onclick={replaceDocument}
|
|
188
|
+
aria-label={i18n.t("plugin.richtext:editor.replaceNamed", { name: filename })}
|
|
189
|
+
tooltip={i18n.t("plugin.richtext:asset.replace")}
|
|
190
|
+
>
|
|
191
|
+
<ReplaceIcon />
|
|
192
|
+
</Button>
|
|
193
|
+
<Button
|
|
194
|
+
class="ridu-richtext-upload-card__action"
|
|
195
|
+
variant="ghost"
|
|
196
|
+
size="icon-sm"
|
|
197
|
+
onclick={removeUpload}
|
|
198
|
+
aria-label={i18n.t("plugin.richtext:editor.removeNamed", { name: filename })}
|
|
199
|
+
tooltip={i18n.t("plugin.richtext:asset.remove")}
|
|
200
|
+
>
|
|
201
|
+
<RemoveIcon />
|
|
202
|
+
</Button>
|
|
203
|
+
</div>
|
|
204
|
+
{/if}
|
|
205
|
+
<div class="ridu-richtext-upload-card__metadata" aria-live="polite">
|
|
206
|
+
{#if isEditable()}
|
|
188
207
|
<button
|
|
189
208
|
type="button"
|
|
190
|
-
class="
|
|
209
|
+
class="ridu-richtext-upload-card__filename"
|
|
191
210
|
onclick={openDocument}
|
|
192
211
|
aria-label={i18n.t("plugin.richtext:editor.editNamed", { name: filename })}
|
|
193
212
|
>
|
|
194
213
|
{filename}
|
|
195
214
|
</button>
|
|
196
|
-
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
class="grid size-7 shrink-0 cursor-pointer place-items-center rounded-[3px] border-0 bg-transparent text-media-foreground/75 hover:bg-media-foreground/10 hover:text-media-foreground focus-visible:bg-media-foreground/10 focus-visible:text-media-foreground focus-visible:outline-none"
|
|
204
|
-
onclick={replaceDocument}
|
|
205
|
-
aria-label={i18n.t("plugin.richtext:editor.replaceNamed", { name: filename })}
|
|
206
|
-
>
|
|
207
|
-
<svg
|
|
208
|
-
class="size-3.5"
|
|
209
|
-
viewBox="0 0 24 24"
|
|
210
|
-
fill="none"
|
|
211
|
-
stroke="currentColor"
|
|
212
|
-
stroke-width="2"
|
|
213
|
-
aria-hidden="true"
|
|
214
|
-
>
|
|
215
|
-
<path
|
|
216
|
-
d="M20 11a8.1 8.1 0 0 0-15.5-2M4 4v5h5M4 13a8.1 8.1 0 0 0 15.5 2M20 20v-5h-5"
|
|
217
|
-
/>
|
|
218
|
-
</svg>
|
|
219
|
-
</button>
|
|
220
|
-
{/snippet}
|
|
221
|
-
</TooltipTrigger>
|
|
222
|
-
<TooltipContent>{i18n.t("plugin.richtext:asset.replace")}</TooltipContent>
|
|
223
|
-
</TooltipRoot>
|
|
224
|
-
<TooltipRoot>
|
|
225
|
-
<TooltipTrigger>
|
|
226
|
-
{#snippet child({ props })}
|
|
227
|
-
<button
|
|
228
|
-
{...props}
|
|
229
|
-
type="button"
|
|
230
|
-
class="grid size-7 shrink-0 cursor-pointer place-items-center rounded-[3px] border-0 bg-transparent text-media-foreground/75 hover:bg-destructive/25 hover:text-media-foreground focus-visible:bg-destructive/25 focus-visible:text-media-foreground focus-visible:outline-none"
|
|
231
|
-
onclick={removeUpload}
|
|
232
|
-
aria-label={i18n.t("plugin.richtext:editor.removeNamed", { name: filename })}
|
|
233
|
-
>
|
|
234
|
-
<svg
|
|
235
|
-
class="size-3.5"
|
|
236
|
-
viewBox="0 0 24 24"
|
|
237
|
-
fill="none"
|
|
238
|
-
stroke="currentColor"
|
|
239
|
-
stroke-width="2"
|
|
240
|
-
aria-hidden="true"
|
|
241
|
-
>
|
|
242
|
-
<path d="M18 6 6 18M6 6l12 12" />
|
|
243
|
-
</svg>
|
|
244
|
-
</button>
|
|
245
|
-
{/snippet}
|
|
246
|
-
</TooltipTrigger>
|
|
247
|
-
<TooltipContent>{i18n.t("plugin.richtext:asset.remove")}</TooltipContent>
|
|
248
|
-
</TooltipRoot>
|
|
249
|
-
</div>
|
|
250
|
-
{/if}
|
|
215
|
+
{:else}
|
|
216
|
+
<strong class="ridu-richtext-upload-card__filename">{filename}</strong>
|
|
217
|
+
{/if}
|
|
218
|
+
<span class="ridu-richtext-upload-card__collection">
|
|
219
|
+
{collection?.labels.singular ?? relationTo}
|
|
220
|
+
</span>
|
|
221
|
+
</div>
|
|
251
222
|
</div>
|
|
252
223
|
|
|
253
224
|
{#if isEditable() || caption !== ""}
|
|
254
|
-
<figcaption class="
|
|
225
|
+
<figcaption class="ridu-richtext-upload-card__caption">
|
|
255
226
|
{#if isEditable()}
|
|
256
|
-
<div class="
|
|
227
|
+
<div class="ridu-richtext-upload-card__caption-editor">
|
|
257
228
|
<svg
|
|
258
|
-
class="
|
|
229
|
+
class="ridu-richtext-upload-card__caption-icon"
|
|
259
230
|
viewBox="0 0 24 24"
|
|
260
231
|
fill="none"
|
|
261
232
|
stroke="currentColor"
|
|
@@ -265,7 +236,7 @@
|
|
|
265
236
|
<path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L8 18l-4 1 1-4Z" />
|
|
266
237
|
</svg>
|
|
267
238
|
<Textarea
|
|
268
|
-
class="
|
|
239
|
+
class="ridu-richtext-upload-card__caption-input"
|
|
269
240
|
rows={1}
|
|
270
241
|
value={caption}
|
|
271
242
|
oninput={updateCaption}
|
|
@@ -275,7 +246,7 @@
|
|
|
275
246
|
/>
|
|
276
247
|
</div>
|
|
277
248
|
{:else}
|
|
278
|
-
<p class="
|
|
249
|
+
<p class="ridu-richtext-upload-card__caption-text">{caption}</p>
|
|
279
250
|
{/if}
|
|
280
251
|
</figcaption>
|
|
281
252
|
{/if}
|
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { FieldAuthoringHost } from "@riducms/plugin";
|
|
3
3
|
import type { SchemaCollection, SchemaField } from "@riducms/protocol";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
$createParagraphNode,
|
|
7
|
-
$getNodeByKey,
|
|
8
|
-
$getPreviousSelection,
|
|
9
|
-
$getRoot,
|
|
10
|
-
$getSelection,
|
|
11
|
-
$isElementNode,
|
|
12
|
-
$isParagraphNode,
|
|
13
|
-
$isRangeSelection,
|
|
14
|
-
COMMAND_PRIORITY_EDITOR,
|
|
15
|
-
type NodeKey,
|
|
16
|
-
} from "lexical";
|
|
4
|
+
import { mergeRegister } from "@lexical/utils";
|
|
5
|
+
import { $getNodeByKey, COMMAND_PRIORITY_EDITOR, type NodeKey } from "lexical";
|
|
17
6
|
import { useLexicalComposerContext } from "@hvniel/lexical-svelte";
|
|
18
7
|
|
|
19
8
|
import {
|
|
@@ -22,6 +11,10 @@
|
|
|
22
11
|
UPDATE_UPLOAD_CAPTION_COMMAND,
|
|
23
12
|
} from "@plugin-richtext/menu/rich-text-commands";
|
|
24
13
|
import type { RichTextConfig } from "@plugin-richtext/field/rich-text-config";
|
|
14
|
+
import {
|
|
15
|
+
insertReferenceNode,
|
|
16
|
+
removeReferenceNode,
|
|
17
|
+
} from "@plugin-richtext/field/reference-node-placement";
|
|
25
18
|
import {
|
|
26
19
|
createUploadNode,
|
|
27
20
|
isUploadNode,
|
|
@@ -39,7 +32,7 @@
|
|
|
39
32
|
} = $props();
|
|
40
33
|
const editor = useLexicalComposerContext()[0];
|
|
41
34
|
let browserOpen = $state(false);
|
|
42
|
-
let targetCollection = $state<SchemaCollection>();
|
|
35
|
+
let targetCollection = $state.raw<SchemaCollection>();
|
|
43
36
|
let documentID = $state<string>();
|
|
44
37
|
let browserMode = $state<"edit" | "insert" | "replace">("insert");
|
|
45
38
|
let replaceNodeKey: NodeKey | undefined;
|
|
@@ -97,16 +90,7 @@
|
|
|
97
90
|
(nodeKey) => {
|
|
98
91
|
const node = $getNodeByKey(nodeKey);
|
|
99
92
|
if (!isUploadNode(node)) return false;
|
|
100
|
-
|
|
101
|
-
const previous = node.getPreviousSibling();
|
|
102
|
-
node.remove();
|
|
103
|
-
if ($isElementNode(next)) next.selectStart();
|
|
104
|
-
else if ($isElementNode(previous)) previous.selectEnd();
|
|
105
|
-
else {
|
|
106
|
-
const paragraph = $createParagraphNode();
|
|
107
|
-
$getRoot().append(paragraph);
|
|
108
|
-
paragraph.select();
|
|
109
|
-
}
|
|
93
|
+
removeReferenceNode(node);
|
|
110
94
|
return true;
|
|
111
95
|
},
|
|
112
96
|
COMMAND_PRIORITY_EDITOR
|
|
@@ -125,18 +109,11 @@
|
|
|
125
109
|
editor.update(() => {
|
|
126
110
|
if (replaceNodeKey !== undefined) {
|
|
127
111
|
const current = $getNodeByKey(replaceNodeKey);
|
|
128
|
-
if (isUploadNode(current)) current.setReference(collection.slug, id);
|
|
112
|
+
if (isUploadNode(current)) current.setReference(collection.slug, id).setCaption("");
|
|
129
113
|
return;
|
|
130
114
|
}
|
|
131
|
-
const selection = $getSelection() ?? $getPreviousSelection();
|
|
132
|
-
if (!$isRangeSelection(selection)) $getRoot().selectEnd();
|
|
133
|
-
const focusNode = $isRangeSelection(selection) ? selection.focus.getNode() : undefined;
|
|
134
115
|
const upload = createUploadNode({ documentID: id, relationTo: collection.slug });
|
|
135
|
-
|
|
136
|
-
if ($isParagraphNode(focusNode) && focusNode.getChildrenSize() === 0) focusNode.remove();
|
|
137
|
-
const paragraph = $createParagraphNode();
|
|
138
|
-
upload.insertAfter(paragraph);
|
|
139
|
-
paragraph.select();
|
|
116
|
+
insertReferenceNode(upload);
|
|
140
117
|
});
|
|
141
118
|
closeBrowser();
|
|
142
119
|
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
.ridu-richtext-tags span + span::before {
|
|
2
|
-
margin-inline-end: 0.5rem;
|
|
3
|
-
color: var(--ink-faint);
|
|
4
|
-
content: "·";
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.ridu-richtext-content ::selection {
|
|
8
|
-
background: color-mix(in srgb, var(--primary) 28%, transparent);
|
|
9
|
-
color: var(--foreground);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.ridu-richtext-content > .ridu-richtext-heading:first-child {
|
|
13
|
-
margin-top: 0;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.ridu-richtext-list-item::marker {
|
|
17
|
-
color: var(--brand-primary-soft);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.ridu-richtext-checklist .ridu-richtext-list-item {
|
|
21
|
-
position: relative;
|
|
22
|
-
padding-inline-start: 1.75rem;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.ridu-richtext-checklist .ridu-richtext-list-item::before {
|
|
26
|
-
position: absolute;
|
|
27
|
-
top: 0.42rem;
|
|
28
|
-
inset-inline-start: 0;
|
|
29
|
-
width: 0.9rem;
|
|
30
|
-
height: 0.9rem;
|
|
31
|
-
border: 1px solid var(--border);
|
|
32
|
-
border-radius: 0.25rem;
|
|
33
|
-
content: "";
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.ridu-richtext-checklist .ridu-richtext-list-item-checked::before {
|
|
37
|
-
border-color: var(--primary);
|
|
38
|
-
background: var(--primary);
|
|
39
|
-
box-shadow: inset 0 0 0 2px var(--background);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.ridu-richtext-rule.is-selected {
|
|
43
|
-
border-top-color: color-mix(in srgb, var(--primary) 60%, transparent);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/* Lexical toggles this inline; keep the toolbar measurable while preventing interaction. */
|
|
47
|
-
.ridu-richtext-block-toolbar[style*="display: none"] {
|
|
48
|
-
opacity: 0 !important;
|
|
49
|
-
pointer-events: none;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/* Lexical positions the menu 4px into the canvas; cancel that offset and center the grip on its rule. */
|
|
53
|
-
.ridu-richtext-block-toolbar {
|
|
54
|
-
margin-inline-start: calc(-4px - 0.4rem);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.ridu-richtext-block-grip span {
|
|
58
|
-
width: 2px;
|
|
59
|
-
height: 2px;
|
|
60
|
-
border-radius: 50%;
|
|
61
|
-
background: currentColor;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.ridu-richtext-upload-preview.is-loading::after {
|
|
65
|
-
position: absolute;
|
|
66
|
-
inset: 0;
|
|
67
|
-
background: color-mix(in srgb, var(--foreground) 3%, transparent);
|
|
68
|
-
content: "";
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@keyframes ridu-richtext-menu-in {
|
|
72
|
-
from {
|
|
73
|
-
opacity: 0;
|
|
74
|
-
transform: translateY(0.25rem) scale(0.985);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
@keyframes ridu-richtext-toolbar-in {
|
|
79
|
-
from {
|
|
80
|
-
opacity: 0;
|
|
81
|
-
transform: translateY(0.2rem) scale(0.985);
|
|
82
|
-
}
|
|
83
|
-
}
|