@thebuoyant-tsdev/mui-ts-library 3.12.0 → 3.14.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.de.md +34 -1
- package/README.md +34 -1
- package/dist/components/color-picker/ColorPicker.d.ts +11 -0
- package/dist/components/color-picker/ColorPicker.js +526 -0
- package/dist/components/color-picker/ColorPicker.types.d.ts +65 -0
- package/dist/components/color-picker/ColorPicker.types.js +18 -0
- package/dist/components/color-picker/util/colorConversion.util.d.ts +51 -0
- package/dist/components/color-picker/util/colorConversion.util.js +166 -0
- package/dist/components/rich-text-editor/RichTextEditor.d.ts +1 -1
- package/dist/components/rich-text-editor/RichTextEditor.js +95 -68
- package/dist/components/rich-text-editor/RichTextEditor.types.d.ts +24 -0
- package/dist/components/rich-text-editor/RichTextEditor.types.js +2 -1
- package/dist/components/rich-text-editor/RichTextEditorMentionList.d.ts +11 -0
- package/dist/components/rich-text-editor/RichTextEditorMentionList.js +54 -0
- package/dist/components/rich-text-editor/RichTextEditorMentionSuggestion.d.ts +9 -0
- package/dist/components/rich-text-editor/RichTextEditorMentionSuggestion.js +45 -0
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/package.json +3 -2
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export type ColorPickerFormat = "hex" | "rgb" | "hsl";
|
|
2
|
+
/** Clean payload passed to `onChange` alongside the primary hex string — no internal HSV state exposed. */
|
|
3
|
+
export type ColorPickerColorInfo = {
|
|
4
|
+
hex: string;
|
|
5
|
+
rgb: {
|
|
6
|
+
r: number;
|
|
7
|
+
g: number;
|
|
8
|
+
b: number;
|
|
9
|
+
a: number;
|
|
10
|
+
};
|
|
11
|
+
hsl: {
|
|
12
|
+
h: number;
|
|
13
|
+
s: number;
|
|
14
|
+
l: number;
|
|
15
|
+
a: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export type ColorPickerTranslation = {
|
|
19
|
+
formatLabel: string;
|
|
20
|
+
hexFieldLabel: string;
|
|
21
|
+
redLabel: string;
|
|
22
|
+
greenLabel: string;
|
|
23
|
+
blueLabel: string;
|
|
24
|
+
hueFieldLabel: string;
|
|
25
|
+
saturationFieldLabel: string;
|
|
26
|
+
lightnessFieldLabel: string;
|
|
27
|
+
alphaFieldLabel: string;
|
|
28
|
+
eyeDropperLabel: string;
|
|
29
|
+
savedColorsLabel: string;
|
|
30
|
+
gradientAreaLabel: string;
|
|
31
|
+
hueSliderLabel: string;
|
|
32
|
+
};
|
|
33
|
+
export declare const DEFAULT_COLOR_PICKER_TRANSLATION: Required<ColorPickerTranslation>;
|
|
34
|
+
export type ColorPickerProps = {
|
|
35
|
+
/** Current color — accepts hex (#rgb, #rgba, #rrggbb, #rrggbbaa), rgb()/rgba(), or hsl()/hsla(). */
|
|
36
|
+
value: string;
|
|
37
|
+
/** Fires on every change — live while dragging, on every valid keystroke, and on swatch/eyedropper picks — with a normalized hex string plus a clean rgb/hsl breakdown. */
|
|
38
|
+
onChange: (hex: string, info: ColorPickerColorInfo) => void;
|
|
39
|
+
/** Fires once per "gesture" instead of continuously: on pointer-up after a drag, on blur after typing, or immediately for atomic actions (swatch click, eyedropper). Same dual-callback pattern as MUI's own `Slider` — use this instead of debouncing `onChange` yourself for expensive side effects (persisting to a backend, etc.). */
|
|
40
|
+
onChangeCommitted?: (hex: string, info: ColorPickerColorInfo) => void;
|
|
41
|
+
/** Initial display format for the value field — uncontrolled after mount (default: 'hex'). */
|
|
42
|
+
defaultFormat?: ColorPickerFormat;
|
|
43
|
+
/** Fires when the user switches the display format via the dropdown. */
|
|
44
|
+
onFormatChange?: (format: ColorPickerFormat) => void;
|
|
45
|
+
/** Shows the alpha slider and opacity field (default: true). */
|
|
46
|
+
showAlpha?: boolean;
|
|
47
|
+
/** Shows the eyedropper tool — auto-hidden when the browser doesn't support the EyeDropper API regardless of this prop (default: true). */
|
|
48
|
+
showEyeDropper?: boolean;
|
|
49
|
+
/** Shows the eyedropper button + hue/alpha slider row (default: true). Set `false` for a minimal gradient-area-only picker. */
|
|
50
|
+
showSliderSection?: boolean;
|
|
51
|
+
/** Shows the format dropdown + hex/RGB/HSL/alpha value fields row (default: true). Set `false` for a slider-only picker. */
|
|
52
|
+
showInputSection?: boolean;
|
|
53
|
+
/** Swatches shown below the picker — click to select. Purely a display list; the caller owns persistence. */
|
|
54
|
+
savedColors?: string[];
|
|
55
|
+
disabled?: boolean;
|
|
56
|
+
/** Scales the gradient area, slider thickness, and swatch size (default: 'medium'). */
|
|
57
|
+
colorGradientSize?: "small" | "medium";
|
|
58
|
+
/** Size of the format dropdown and value/alpha input fields, independent of `colorGradientSize` (default: 'medium'). */
|
|
59
|
+
inputSize?: "small" | "medium";
|
|
60
|
+
/** Overall panel width in px (default: 280). */
|
|
61
|
+
width?: number;
|
|
62
|
+
/** Form-integration: renders a hidden input so the value participates in native/React Hook Form/Formik form submission. */
|
|
63
|
+
name?: string;
|
|
64
|
+
translation?: Partial<ColorPickerTranslation>;
|
|
65
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/components/color-picker/ColorPicker.types.ts
|
|
2
|
+
var e = {
|
|
3
|
+
formatLabel: "Color format",
|
|
4
|
+
hexFieldLabel: "Hex value",
|
|
5
|
+
redLabel: "Red",
|
|
6
|
+
greenLabel: "Green",
|
|
7
|
+
blueLabel: "Blue",
|
|
8
|
+
hueFieldLabel: "Hue",
|
|
9
|
+
saturationFieldLabel: "Saturation",
|
|
10
|
+
lightnessFieldLabel: "Lightness",
|
|
11
|
+
alphaFieldLabel: "Alpha",
|
|
12
|
+
eyeDropperLabel: "Pick color from screen",
|
|
13
|
+
savedColorsLabel: "Saved colors",
|
|
14
|
+
gradientAreaLabel: "Saturation and brightness",
|
|
15
|
+
hueSliderLabel: "Hue"
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { e as DEFAULT_COLOR_PICKER_TRANSLATION };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export type RgbaColor = {
|
|
2
|
+
r: number;
|
|
3
|
+
g: number;
|
|
4
|
+
b: number;
|
|
5
|
+
a: number;
|
|
6
|
+
};
|
|
7
|
+
export type HsvaColor = {
|
|
8
|
+
h: number;
|
|
9
|
+
s: number;
|
|
10
|
+
v: number;
|
|
11
|
+
a: number;
|
|
12
|
+
};
|
|
13
|
+
export type HslaColor = {
|
|
14
|
+
h: number;
|
|
15
|
+
s: number;
|
|
16
|
+
l: number;
|
|
17
|
+
a: number;
|
|
18
|
+
};
|
|
19
|
+
export declare function clamp(value: number, min: number, max: number): number;
|
|
20
|
+
export declare function rgbaToHex({ r, g, b, a }: RgbaColor): string;
|
|
21
|
+
export declare function hexToRgba(hex: string): RgbaColor | null;
|
|
22
|
+
export declare function hsvToRgb(h: number, s: number, v: number): {
|
|
23
|
+
r: number;
|
|
24
|
+
g: number;
|
|
25
|
+
b: number;
|
|
26
|
+
};
|
|
27
|
+
export declare function rgbToHsv(r: number, g: number, b: number): {
|
|
28
|
+
h: number;
|
|
29
|
+
s: number;
|
|
30
|
+
v: number;
|
|
31
|
+
};
|
|
32
|
+
export declare function hslToRgb(h: number, s: number, l: number): {
|
|
33
|
+
r: number;
|
|
34
|
+
g: number;
|
|
35
|
+
b: number;
|
|
36
|
+
};
|
|
37
|
+
export declare function rgbToHsl(r: number, g: number, b: number): {
|
|
38
|
+
h: number;
|
|
39
|
+
s: number;
|
|
40
|
+
l: number;
|
|
41
|
+
};
|
|
42
|
+
export declare function hsvaToRgba({ h, s, v, a }: HsvaColor): RgbaColor;
|
|
43
|
+
export declare function rgbaToHsva({ r, g, b, a }: RgbaColor): HsvaColor;
|
|
44
|
+
export declare function hsvaToHsla({ h, s, v, a }: HsvaColor): HslaColor;
|
|
45
|
+
export declare function hslaToHsva({ h, s, l, a }: HslaColor): HsvaColor;
|
|
46
|
+
/** Accepts #hex (3/4/6/8 digits), rgb()/rgba(), and hsl()/hsla() — returns null when unparseable. */
|
|
47
|
+
export declare function parseColorString(input: string): RgbaColor | null;
|
|
48
|
+
export declare function formatRgbString({ r, g, b, a }: RgbaColor): string;
|
|
49
|
+
export declare function formatHslString({ h, s, l, a }: HslaColor): string;
|
|
50
|
+
/** WCAG-style luminance heuristic — picks black or white text for readable contrast on a given background. */
|
|
51
|
+
export declare function getContrastTextColor(r: number, g: number, b: number): "#000000" | "#ffffff";
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
//#region src/components/color-picker/util/colorConversion.util.ts
|
|
2
|
+
function e(e, t, n) {
|
|
3
|
+
return Math.min(n, Math.max(t, e));
|
|
4
|
+
}
|
|
5
|
+
function t(t) {
|
|
6
|
+
return e(Math.round(t), 0, 255).toString(16).padStart(2, "0");
|
|
7
|
+
}
|
|
8
|
+
function n({ r: e, g: n, b: r, a: i }) {
|
|
9
|
+
let a = `#${t(e)}${t(n)}${t(r)}`;
|
|
10
|
+
return i < 1 ? `${a}${t(i * 255)}` : a;
|
|
11
|
+
}
|
|
12
|
+
function r(e) {
|
|
13
|
+
let t = e.trim().replace(/^#/, ""), n, r, i, a = 1;
|
|
14
|
+
if (t.length === 3 || t.length === 4) n = parseInt(t[0] + t[0], 16), r = parseInt(t[1] + t[1], 16), i = parseInt(t[2] + t[2], 16), t.length === 4 && (a = parseInt(t[3] + t[3], 16) / 255);
|
|
15
|
+
else if (t.length === 6 || t.length === 8) n = parseInt(t.slice(0, 2), 16), r = parseInt(t.slice(2, 4), 16), i = parseInt(t.slice(4, 6), 16), t.length === 8 && (a = parseInt(t.slice(6, 8), 16) / 255);
|
|
16
|
+
else return null;
|
|
17
|
+
return [
|
|
18
|
+
n,
|
|
19
|
+
r,
|
|
20
|
+
i,
|
|
21
|
+
a
|
|
22
|
+
].some((e) => Number.isNaN(e)) ? null : {
|
|
23
|
+
r: n,
|
|
24
|
+
g: r,
|
|
25
|
+
b: i,
|
|
26
|
+
a
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function i(e, t, n) {
|
|
30
|
+
let r = t / 100, i = n / 100, a = i * r, o = a * (1 - Math.abs(e / 60 % 2 - 1)), s = i - a, [c, l, u] = e < 60 ? [
|
|
31
|
+
a,
|
|
32
|
+
o,
|
|
33
|
+
0
|
|
34
|
+
] : e < 120 ? [
|
|
35
|
+
o,
|
|
36
|
+
a,
|
|
37
|
+
0
|
|
38
|
+
] : e < 180 ? [
|
|
39
|
+
0,
|
|
40
|
+
a,
|
|
41
|
+
o
|
|
42
|
+
] : e < 240 ? [
|
|
43
|
+
0,
|
|
44
|
+
o,
|
|
45
|
+
a
|
|
46
|
+
] : e < 300 ? [
|
|
47
|
+
o,
|
|
48
|
+
0,
|
|
49
|
+
a
|
|
50
|
+
] : [
|
|
51
|
+
a,
|
|
52
|
+
0,
|
|
53
|
+
o
|
|
54
|
+
];
|
|
55
|
+
return {
|
|
56
|
+
r: (c + s) * 255,
|
|
57
|
+
g: (l + s) * 255,
|
|
58
|
+
b: (u + s) * 255
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function a(e, t, n) {
|
|
62
|
+
let r = e / 255, i = t / 255, a = n / 255, o = Math.max(r, i, a), s = o - Math.min(r, i, a), c = 0;
|
|
63
|
+
s !== 0 && (c = o === r ? 60 * ((i - a) / s % 6) : o === i ? 60 * ((a - r) / s + 2) : 60 * ((r - i) / s + 4)), c < 0 && (c += 360);
|
|
64
|
+
let l = o === 0 ? 0 : s / o;
|
|
65
|
+
return {
|
|
66
|
+
h: c,
|
|
67
|
+
s: l * 100,
|
|
68
|
+
v: o * 100
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function o(e, t, n) {
|
|
72
|
+
let r = t / 100, i = n / 100, a = (1 - Math.abs(2 * i - 1)) * r, o = a * (1 - Math.abs(e / 60 % 2 - 1)), s = i - a / 2, [c, l, u] = e < 60 ? [
|
|
73
|
+
a,
|
|
74
|
+
o,
|
|
75
|
+
0
|
|
76
|
+
] : e < 120 ? [
|
|
77
|
+
o,
|
|
78
|
+
a,
|
|
79
|
+
0
|
|
80
|
+
] : e < 180 ? [
|
|
81
|
+
0,
|
|
82
|
+
a,
|
|
83
|
+
o
|
|
84
|
+
] : e < 240 ? [
|
|
85
|
+
0,
|
|
86
|
+
o,
|
|
87
|
+
a
|
|
88
|
+
] : e < 300 ? [
|
|
89
|
+
o,
|
|
90
|
+
0,
|
|
91
|
+
a
|
|
92
|
+
] : [
|
|
93
|
+
a,
|
|
94
|
+
0,
|
|
95
|
+
o
|
|
96
|
+
];
|
|
97
|
+
return {
|
|
98
|
+
r: (c + s) * 255,
|
|
99
|
+
g: (l + s) * 255,
|
|
100
|
+
b: (u + s) * 255
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function s(e, t, n) {
|
|
104
|
+
let r = e / 255, i = t / 255, a = n / 255, o = Math.max(r, i, a), s = Math.min(r, i, a), c = (o + s) / 2, l = o - s, u = 0, d = 0;
|
|
105
|
+
return l !== 0 && (d = c > .5 ? l / (2 - o - s) : l / (o + s), u = o === r ? 60 * ((i - a) / l % 6) : o === i ? 60 * ((a - r) / l + 2) : 60 * ((r - i) / l + 4)), u < 0 && (u += 360), {
|
|
106
|
+
h: u,
|
|
107
|
+
s: d * 100,
|
|
108
|
+
l: c * 100
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function c({ h: e, s: t, v: n, a: r }) {
|
|
112
|
+
let { r: a, g: o, b: s } = i(e, t, n);
|
|
113
|
+
return {
|
|
114
|
+
r: a,
|
|
115
|
+
g: o,
|
|
116
|
+
b: s,
|
|
117
|
+
a: r
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function l({ r: e, g: t, b: n, a: r }) {
|
|
121
|
+
let { h: i, s: o, v: s } = a(e, t, n);
|
|
122
|
+
return {
|
|
123
|
+
h: i,
|
|
124
|
+
s: o,
|
|
125
|
+
v: s,
|
|
126
|
+
a: r
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function u({ h: e, s: t, v: n, a: r }) {
|
|
130
|
+
let { r: a, g: o, b: c } = i(e, t, n);
|
|
131
|
+
return {
|
|
132
|
+
...s(a, o, c),
|
|
133
|
+
a: r
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function d({ h: e, s: t, l: n, a: r }) {
|
|
137
|
+
let { r: i, g: s, b: c } = o(e, t, n);
|
|
138
|
+
return {
|
|
139
|
+
...a(i, s, c),
|
|
140
|
+
a: r
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function f(e) {
|
|
144
|
+
let t = e.trim();
|
|
145
|
+
if (t.startsWith("#")) return r(t);
|
|
146
|
+
let n = t.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)$/i);
|
|
147
|
+
if (n) return {
|
|
148
|
+
r: Number(n[1]),
|
|
149
|
+
g: Number(n[2]),
|
|
150
|
+
b: Number(n[3]),
|
|
151
|
+
a: n[4] === void 0 ? 1 : Number(n[4])
|
|
152
|
+
};
|
|
153
|
+
let i = t.match(/^hsla?\(\s*([\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*(?:,\s*([\d.]+)\s*)?\)$/i);
|
|
154
|
+
if (i) {
|
|
155
|
+
let { r: e, g: t, b: n } = o(Number(i[1]), Number(i[2]), Number(i[3]));
|
|
156
|
+
return {
|
|
157
|
+
r: e,
|
|
158
|
+
g: t,
|
|
159
|
+
b: n,
|
|
160
|
+
a: i[4] === void 0 ? 1 : Number(i[4])
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
//#endregion
|
|
166
|
+
export { e as clamp, r as hexToRgba, d as hslaToHsva, u as hsvaToHsla, c as hsvaToRgba, f as parseColorString, n as rgbaToHex, l as rgbaToHsva };
|
|
@@ -5,4 +5,4 @@ declare module "@tiptap/core" {
|
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
7
|
import { type RichTextEditorProps } from "./RichTextEditor.types";
|
|
8
|
-
export declare function RichTextEditor({ disabled, error, height, helperText, maxCharacters, name, placeholder, readonly, showCharacterCount, showToolbar, showWordCount, toolbarConfig, translation, value, width, onBlur, onChange, onFocus, onMarkdownChange, }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function RichTextEditor({ disabled, error, height, helperText, maxCharacters, mentionItems, mentionTriggerChar, name, onMentionSearch, placeholder, readonly, showCharacterCount, showToolbar, showWordCount, toolbarConfig, translation, value, width, onBlur, onChange, onFocus, onMarkdownChange, }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,56 +1,83 @@
|
|
|
1
1
|
import { normalizeSize as e } from "../shared/normalizeSize.js";
|
|
2
2
|
import { DEFAULT_RICH_TEXT_EDITOR_TOOLBAR_CONFIG as t, DEFAULT_RICH_TEXT_EDITOR_TRANSLATION as n } from "./RichTextEditor.types.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
3
|
+
import { buildMentionSuggestion as r } from "./RichTextEditorMentionSuggestion.js";
|
|
4
|
+
import { RichTextEditorContent as i } from "./RichTextEditorContent.js";
|
|
5
|
+
import { RichTextEditorToolbar as a } from "./RichTextEditorToolbar.js";
|
|
6
|
+
import { RichTextEditorFooter as ee } from "./RichTextEditorFooter.js";
|
|
7
|
+
import { useEffect as o, useMemo as te, useRef as s, useState as c } from "react";
|
|
8
|
+
import { Box as l, Divider as u, Paper as ne } from "@mui/material";
|
|
9
|
+
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
10
|
+
import { useEditor as re } from "@tiptap/react";
|
|
11
|
+
import { Mention as m } from "@tiptap/extension-mention";
|
|
12
|
+
import { StarterKit as h } from "@tiptap/starter-kit";
|
|
13
|
+
import { TextStyle as ie } from "@tiptap/extension-text-style";
|
|
14
|
+
import { Color as g } from "@tiptap/extension-color";
|
|
15
|
+
import { Highlight as _ } from "@tiptap/extension-highlight";
|
|
16
|
+
import { Placeholder as ae } from "@tiptap/extension-placeholder";
|
|
17
|
+
import { CharacterCount as v } from "@tiptap/extension-character-count";
|
|
18
|
+
import { TableKit as oe } from "@tiptap/extension-table";
|
|
19
|
+
import { Image as y } from "@tiptap/extension-image";
|
|
20
|
+
import { Markdown as b } from "tiptap-markdown";
|
|
19
21
|
//#region src/components/rich-text-editor/RichTextEditor.tsx
|
|
20
|
-
function
|
|
22
|
+
function x({ disabled: x = !1, error: S = !1, height: se, helperText: C, maxCharacters: w, mentionItems: T, mentionTriggerChar: E = "@", name: D, onMentionSearch: O, placeholder: k, readonly: A = !1, showCharacterCount: j = !1, showToolbar: M = !0, showWordCount: N = !1, toolbarConfig: P, translation: F, value: I, width: L, onBlur: R, onChange: z, onFocus: B, onMarkdownChange: V }) {
|
|
21
23
|
let H = {
|
|
22
24
|
...n,
|
|
23
|
-
...
|
|
25
|
+
...F
|
|
24
26
|
}, U = {
|
|
25
27
|
...t,
|
|
26
|
-
...
|
|
27
|
-
}, [W, G] = c(!1), [K,
|
|
28
|
+
...P
|
|
29
|
+
}, [W, G] = c(!1), [K, ce] = c(!1), q = s(K), J = s(T ?? []);
|
|
28
30
|
o(() => {
|
|
29
|
-
J.current =
|
|
31
|
+
J.current = T ?? [];
|
|
32
|
+
}, [T]), o(() => {
|
|
33
|
+
q.current = K;
|
|
30
34
|
}, [K]);
|
|
31
|
-
let Y = e(
|
|
35
|
+
let Y = e(se), le = e(L), X = Y === "auto", ue = X ? void 0 : Y ?? 200, Z = T !== void 0 || O !== void 0, Q = te(() => Z ? m.configure({
|
|
36
|
+
HTMLAttributes: { class: "rte-mention" },
|
|
37
|
+
renderHTML({ options: e, node: t }) {
|
|
38
|
+
return [
|
|
39
|
+
"span",
|
|
40
|
+
{
|
|
41
|
+
...e.HTMLAttributes,
|
|
42
|
+
"data-id": t.attrs.id,
|
|
43
|
+
"data-label": t.attrs.label
|
|
44
|
+
},
|
|
45
|
+
`${E}${t.attrs.label}`
|
|
46
|
+
];
|
|
47
|
+
},
|
|
48
|
+
suggestion: r({
|
|
49
|
+
getItems: () => J.current,
|
|
50
|
+
onMentionSearch: O,
|
|
51
|
+
noResultsLabel: H.mentionNoResults ?? "No results"
|
|
52
|
+
})
|
|
53
|
+
}) : null, [
|
|
54
|
+
Z,
|
|
55
|
+
E,
|
|
56
|
+
O
|
|
57
|
+
]), de = w !== void 0 && w > 0 || j || N, $ = re({
|
|
32
58
|
shouldRerenderOnTransaction: !0,
|
|
33
59
|
extensions: [
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
60
|
+
h.configure({ link: { openOnClick: !1 } }),
|
|
61
|
+
ie,
|
|
62
|
+
g,
|
|
63
|
+
_.configure({ multicolor: !0 }),
|
|
64
|
+
b.configure({
|
|
39
65
|
transformPastedText: !0,
|
|
40
66
|
transformCopiedText: !1
|
|
41
67
|
}),
|
|
42
|
-
|
|
43
|
-
...U.showTableButton ? [
|
|
44
|
-
...U.showImageButton ? [
|
|
68
|
+
ae.configure({ placeholder: k ?? "" }),
|
|
69
|
+
...U.showTableButton ? [oe] : [],
|
|
70
|
+
...U.showImageButton ? [y.configure({
|
|
45
71
|
inline: !1,
|
|
46
72
|
allowBase64: !0
|
|
47
73
|
})] : [],
|
|
48
|
-
...
|
|
74
|
+
...Q ? [Q] : [],
|
|
75
|
+
...de ? w !== void 0 && w > 0 ? [v.configure({ limit: w })] : [v] : []
|
|
49
76
|
],
|
|
50
|
-
content:
|
|
51
|
-
editable: !
|
|
77
|
+
content: I ?? "",
|
|
78
|
+
editable: !x && !A,
|
|
52
79
|
editorProps: { handlePaste(e, t) {
|
|
53
|
-
if (!
|
|
80
|
+
if (!q.current) return !1;
|
|
54
81
|
let n = t.clipboardData?.getData("text/plain");
|
|
55
82
|
if (!n) return !1;
|
|
56
83
|
t.preventDefault();
|
|
@@ -58,26 +85,26 @@ function w({ disabled: w = !1, error: T = !1, height: E, helperText: D, maxChara
|
|
|
58
85
|
return e.dispatch(r.tr.insertText(n, r.selection.from, r.selection.to)), !0;
|
|
59
86
|
} },
|
|
60
87
|
onUpdate({ editor: e }) {
|
|
61
|
-
|
|
88
|
+
z?.(e.getHTML()), V?.(e.storage.markdown.getMarkdown());
|
|
62
89
|
},
|
|
63
90
|
onBlur() {
|
|
64
|
-
|
|
91
|
+
R?.();
|
|
65
92
|
},
|
|
66
93
|
onFocus() {
|
|
67
|
-
|
|
94
|
+
B?.();
|
|
68
95
|
}
|
|
69
96
|
});
|
|
70
97
|
o(() => {
|
|
71
|
-
!$ ||
|
|
72
|
-
}, [$,
|
|
73
|
-
$ && $.setEditable(!
|
|
98
|
+
!$ || I === void 0 || $.getHTML() !== I && $.commands.setContent(I, { emitUpdate: !1 });
|
|
99
|
+
}, [$, I]), o(() => {
|
|
100
|
+
$ && $.setEditable(!x && !A);
|
|
74
101
|
}, [
|
|
75
102
|
$,
|
|
76
|
-
|
|
77
|
-
|
|
103
|
+
x,
|
|
104
|
+
A
|
|
78
105
|
]);
|
|
79
|
-
let
|
|
80
|
-
return /* @__PURE__ */
|
|
106
|
+
let fe = $?.storage.characterCount?.characters?.() ?? 0, pe = $?.storage.characterCount?.words?.() ?? 0, me = j || w !== void 0 && w > 0 || N || !!C;
|
|
107
|
+
return /* @__PURE__ */ p(l, {
|
|
81
108
|
sx: W ? {
|
|
82
109
|
position: "fixed",
|
|
83
110
|
top: 0,
|
|
@@ -90,60 +117,60 @@ function w({ disabled: w = !1, error: T = !1, height: E, helperText: D, maxChara
|
|
|
90
117
|
bgcolor: "background.default",
|
|
91
118
|
p: 1
|
|
92
119
|
} : {
|
|
93
|
-
width:
|
|
94
|
-
...
|
|
120
|
+
width: le ?? "100%",
|
|
121
|
+
...X ? {
|
|
95
122
|
display: "flex",
|
|
96
123
|
flexDirection: "column",
|
|
97
124
|
flex: 1
|
|
98
125
|
} : {}
|
|
99
126
|
},
|
|
100
127
|
children: [
|
|
101
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ p(ne, {
|
|
102
129
|
variant: "outlined",
|
|
103
130
|
sx: {
|
|
104
131
|
display: "flex",
|
|
105
132
|
flexDirection: "column",
|
|
106
133
|
overflow: "hidden",
|
|
107
|
-
...W ||
|
|
108
|
-
borderColor:
|
|
134
|
+
...W || X ? { flex: 1 } : { height: ue },
|
|
135
|
+
borderColor: S ? "error.main" : void 0,
|
|
109
136
|
"&:focus-within": {
|
|
110
|
-
borderColor:
|
|
137
|
+
borderColor: S ? "error.main" : "primary.main",
|
|
111
138
|
borderWidth: 2
|
|
112
139
|
}
|
|
113
140
|
},
|
|
114
|
-
children: [
|
|
141
|
+
children: [M && !A && /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(a, {
|
|
115
142
|
editor: $,
|
|
116
143
|
toolbarConfig: U,
|
|
117
144
|
translation: H,
|
|
118
|
-
disabled:
|
|
145
|
+
disabled: x,
|
|
119
146
|
isFullscreen: W,
|
|
120
147
|
onToggleFullscreen: () => G((e) => !e),
|
|
121
148
|
pasteAsPlainText: K,
|
|
122
|
-
onTogglePasteAsPlainText: () =>
|
|
123
|
-
}), /* @__PURE__ */
|
|
149
|
+
onTogglePasteAsPlainText: () => ce((e) => !e)
|
|
150
|
+
}), /* @__PURE__ */ f(u, {})] }), /* @__PURE__ */ f(i, {
|
|
124
151
|
editor: $,
|
|
125
|
-
error:
|
|
126
|
-
disabled:
|
|
127
|
-
readonly:
|
|
152
|
+
error: S,
|
|
153
|
+
disabled: x,
|
|
154
|
+
readonly: A
|
|
128
155
|
})]
|
|
129
156
|
}),
|
|
130
|
-
|
|
131
|
-
helperText:
|
|
132
|
-
error:
|
|
133
|
-
showCharacterCount:
|
|
134
|
-
charCount:
|
|
135
|
-
maxCharacters:
|
|
136
|
-
showWordCount:
|
|
137
|
-
wordCount:
|
|
157
|
+
me && /* @__PURE__ */ f(ee, {
|
|
158
|
+
helperText: C,
|
|
159
|
+
error: S,
|
|
160
|
+
showCharacterCount: j || w !== void 0 && w > 0,
|
|
161
|
+
charCount: fe,
|
|
162
|
+
maxCharacters: w && w > 0 ? w : void 0,
|
|
163
|
+
showWordCount: N,
|
|
164
|
+
wordCount: pe,
|
|
138
165
|
translation: H
|
|
139
166
|
}),
|
|
140
|
-
|
|
167
|
+
D && /* @__PURE__ */ f("input", {
|
|
141
168
|
type: "hidden",
|
|
142
|
-
name:
|
|
169
|
+
name: D,
|
|
143
170
|
value: $ ? $.getHTML() : ""
|
|
144
171
|
})
|
|
145
172
|
]
|
|
146
173
|
});
|
|
147
174
|
}
|
|
148
175
|
//#endregion
|
|
149
|
-
export {
|
|
176
|
+
export { x as RichTextEditor };
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export type MentionItem = {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
};
|
|
1
5
|
export type RichTextEditorToolbarConfig = {
|
|
2
6
|
showBold?: boolean;
|
|
3
7
|
showItalic?: boolean;
|
|
@@ -99,6 +103,8 @@ export type RichTextEditorTranslation = {
|
|
|
99
103
|
markdownDialogCopy?: string;
|
|
100
104
|
/** @since 3.8.0 */
|
|
101
105
|
markdownDialogCopied?: string;
|
|
106
|
+
/** Text shown in mention dropdown when no items match the query @since 3.14.0 */
|
|
107
|
+
mentionNoResults?: string;
|
|
102
108
|
};
|
|
103
109
|
export declare const DEFAULT_RICH_TEXT_EDITOR_TRANSLATION: Required<RichTextEditorTranslation>;
|
|
104
110
|
export type RichTextEditorProps = {
|
|
@@ -121,6 +127,24 @@ export type RichTextEditorProps = {
|
|
|
121
127
|
value?: string;
|
|
122
128
|
/** Breite des Editors. Zahlen → px. "auto" oder leer → 100% des Elternelements. */
|
|
123
129
|
width?: number | string;
|
|
130
|
+
/**
|
|
131
|
+
* List of items for @-mention autocomplete. The Mention extension is only active when this prop is provided.
|
|
132
|
+
* Used for client-side filtering when `onMentionSearch` is not provided.
|
|
133
|
+
* @since 3.14.0
|
|
134
|
+
*/
|
|
135
|
+
mentionItems?: MentionItem[];
|
|
136
|
+
/**
|
|
137
|
+
* Custom search/filter function called on each keystroke after @.
|
|
138
|
+
* When provided, `mentionItems` is ignored for filtering — return the relevant subset.
|
|
139
|
+
* Supports async for server-side search.
|
|
140
|
+
* @since 3.14.0
|
|
141
|
+
*/
|
|
142
|
+
onMentionSearch?: (query: string) => MentionItem[] | Promise<MentionItem[]>;
|
|
143
|
+
/**
|
|
144
|
+
* Character that triggers the mention autocomplete popup. Default: "@"
|
|
145
|
+
* @since 3.14.0
|
|
146
|
+
*/
|
|
147
|
+
mentionTriggerChar?: string;
|
|
124
148
|
onBlur?: () => void;
|
|
125
149
|
onChange?: (value: string) => void;
|
|
126
150
|
onFocus?: () => void;
|
|
@@ -79,7 +79,8 @@ var e = {
|
|
|
79
79
|
markdownDialogApply: "Apply",
|
|
80
80
|
markdownDialogCancel: "Cancel",
|
|
81
81
|
markdownDialogCopy: "Copy",
|
|
82
|
-
markdownDialogCopied: "Copied!"
|
|
82
|
+
markdownDialogCopied: "Copied!",
|
|
83
|
+
mentionNoResults: "No results"
|
|
83
84
|
};
|
|
84
85
|
//#endregion
|
|
85
86
|
export { e as DEFAULT_RICH_TEXT_EDITOR_TOOLBAR_CONFIG, t as DEFAULT_RICH_TEXT_EDITOR_TRANSLATION };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MentionItem } from "./RichTextEditor.types";
|
|
2
|
+
export type MentionListProps = {
|
|
3
|
+
items: MentionItem[];
|
|
4
|
+
noResultsLabel: string;
|
|
5
|
+
clientRect: (() => DOMRect | null) | null;
|
|
6
|
+
onSelect: (item: MentionItem) => void;
|
|
7
|
+
};
|
|
8
|
+
export type MentionListRef = {
|
|
9
|
+
onKeyDown: (event: KeyboardEvent) => boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare const RichTextEditorMentionList: import("react").ForwardRefExoticComponent<MentionListProps & import("react").RefAttributes<MentionListRef>>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { forwardRef as e, useEffect as t, useImperativeHandle as n, useRef as r, useState as i } from "react";
|
|
2
|
+
import { List as a, ListItemButton as o, Paper as s, Popper as c, Typography as l } from "@mui/material";
|
|
3
|
+
import { jsx as u } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/rich-text-editor/RichTextEditorMentionList.tsx
|
|
5
|
+
var d = e(function({ items: e, noResultsLabel: d, clientRect: f, onSelect: p }, m) {
|
|
6
|
+
let [h, g] = i(0), [_, v] = i(e), y = r(null);
|
|
7
|
+
e !== _ && (v(e), g(0)), t(() => {
|
|
8
|
+
(y.current?.children[h])?.scrollIntoView({ block: "nearest" });
|
|
9
|
+
}, [h]), n(m, () => ({ onKeyDown(t) {
|
|
10
|
+
return t.key === "ArrowUp" ? (g((t) => (t - 1 + e.length) % e.length), !0) : t.key === "ArrowDown" ? (g((t) => (t + 1) % e.length), !0) : t.key === "Enter" ? (e[h] && p(e[h]), !0) : !1;
|
|
11
|
+
} }));
|
|
12
|
+
let b = f ? { getBoundingClientRect: f } : null;
|
|
13
|
+
return /* @__PURE__ */ u(c, {
|
|
14
|
+
open: !!b,
|
|
15
|
+
anchorEl: b,
|
|
16
|
+
placement: "bottom-start",
|
|
17
|
+
modifiers: [{
|
|
18
|
+
name: "offset",
|
|
19
|
+
options: { offset: [0, 4] }
|
|
20
|
+
}],
|
|
21
|
+
style: { zIndex: 1400 },
|
|
22
|
+
children: /* @__PURE__ */ u(s, {
|
|
23
|
+
elevation: 4,
|
|
24
|
+
sx: {
|
|
25
|
+
maxHeight: 240,
|
|
26
|
+
overflow: "auto",
|
|
27
|
+
minWidth: 180
|
|
28
|
+
},
|
|
29
|
+
children: e.length === 0 ? /* @__PURE__ */ u(l, {
|
|
30
|
+
variant: "body2",
|
|
31
|
+
sx: {
|
|
32
|
+
px: 2,
|
|
33
|
+
py: 1,
|
|
34
|
+
color: "text.secondary"
|
|
35
|
+
},
|
|
36
|
+
children: d
|
|
37
|
+
}) : /* @__PURE__ */ u(a, {
|
|
38
|
+
ref: y,
|
|
39
|
+
dense: !0,
|
|
40
|
+
disablePadding: !0,
|
|
41
|
+
children: e.map((e, t) => /* @__PURE__ */ u(o, {
|
|
42
|
+
selected: t === h,
|
|
43
|
+
onMouseDown: (t) => {
|
|
44
|
+
t.preventDefault(), p(e);
|
|
45
|
+
},
|
|
46
|
+
onMouseEnter: () => g(t),
|
|
47
|
+
children: e.label
|
|
48
|
+
}, e.id))
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
//#endregion
|
|
54
|
+
export { d as RichTextEditorMentionList };
|