@thebuoyant-tsdev/mui-ts-library 3.17.0 → 3.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.de.md +14 -0
- package/README.md +14 -0
- package/dist/components/gantt-chart/GanttToolbar.js +1 -1
- package/dist/components/rich-text-editor/RichTextEditor.d.ts +1 -1
- package/dist/components/rich-text-editor/RichTextEditor.js +98 -91
- package/dist/components/rich-text-editor/RichTextEditor.types.d.ts +6 -0
- package/dist/index.cjs +2 -2
- package/package.json +1 -1
package/README.de.md
CHANGED
|
@@ -475,6 +475,20 @@ Dieses Projekt folgt [Semantic Versioning](https://semver.org/). In der Praxis b
|
|
|
475
475
|
|
|
476
476
|
## Changelog
|
|
477
477
|
|
|
478
|
+
### [3.18.0] — 2026-07-08
|
|
479
|
+
|
|
480
|
+
**Hinzugefügt**
|
|
481
|
+
- `RichTextEditor`: neue Prop `onSave?: () => void` — feuert wenn der Nutzer **Ctrl+S** (Windows/Linux) oder **Cmd+S** (macOS) im Editor drückt. Der native „Seite speichern"-Dialog des Browsers wird im Editor immer unterdrückt. Rein additiv — kein bestehendes Verhalten ändert sich. Siehe [Full Changelog](https://github.com/thebuoyant/mui-ts-library/blob/main/CHANGELOG.md) für Details.
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
### [3.17.1] — 2026-07-05
|
|
486
|
+
|
|
487
|
+
**Behoben**
|
|
488
|
+
- `GanttChart`: Reset-View-Button (`showResetView`) aktiviert sich jetzt wenn ein Assignee-Filter gesetzt ist — bisher blieb der Button inaktiv obwohl ein Klick den Filter korrekt zurückgesetzt hätte. `isViewChanged` berücksichtigt nun korrekt den Assignee-Filter-Zustand.
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
478
492
|
### [3.17.0] — 2026-07-05
|
|
479
493
|
|
|
480
494
|
**Hinzugefügt**
|
package/README.md
CHANGED
|
@@ -475,6 +475,20 @@ This project follows [Semantic Versioning](https://semver.org/). In practice:
|
|
|
475
475
|
|
|
476
476
|
## Changelog
|
|
477
477
|
|
|
478
|
+
### [3.18.0] — 2026-07-08
|
|
479
|
+
|
|
480
|
+
**Added**
|
|
481
|
+
- `RichTextEditor`: new `onSave?: () => void` prop — fires when the user presses **Ctrl+S** (Windows/Linux) or **Cmd+S** (macOS) inside the editor. The browser's native "Save Page" dialog is always suppressed within the editor. Purely additive — no existing behaviour changes. See [Full Changelog](https://github.com/thebuoyant/mui-ts-library/blob/main/CHANGELOG.md) for details.
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
### [3.17.1] — 2026-07-05
|
|
486
|
+
|
|
487
|
+
**Fixed**
|
|
488
|
+
- `GanttChart`: Reset View button (`showResetView`) now activates when an assignee filter is set — previously the button stayed disabled even though clicking it would have cleared the filter. `isViewChanged` now correctly includes the assignee filter state.
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
478
492
|
### [3.17.0] — 2026-07-05
|
|
479
493
|
|
|
480
494
|
**Added**
|
|
@@ -17,7 +17,7 @@ function C(e) {
|
|
|
17
17
|
return !t || !n || !r ? null : new Date(t, n - 1, r, 0, 0, 0, 0);
|
|
18
18
|
}
|
|
19
19
|
function w({ onScrollToToday: w, config: T, onExportCSV: E }) {
|
|
20
|
-
let D = t(), O = e((e) => e.timeScale), k = e((e) => e.defaultTimeScale), A = e((e) => e.setTimeScale), j = e((e) => e.timelineRange), M = e((e) => e.isRangeCustomized), N = e((e) => e.isExpandedCustomized), P = e((e) => e.setTimelineRange), F = e((e) => e.resetTimelineRange), I = e((e) => e.resetView), L = e((e) => e.tasks), R = e((e) => e.expandedIds), z = e((e) => e.expandAll), B = e((e) => e.collapseAll), V = e((e) => e.assigneeFilter), H = e((e) => e.setAssigneeFilter), U = n(() => [...new Set(L.flatMap((e) => e.assignee ? [e.assignee] : []))].sort(), [L]), W = L.length > 0 && L.every((e) => R.has(e.id)), G = O !== k || M || N, K = n(() => Date.now(), []), q = K >= j.start.getTime() && K <= j.end.getTime(), J = {
|
|
20
|
+
let D = t(), O = e((e) => e.timeScale), k = e((e) => e.defaultTimeScale), A = e((e) => e.setTimeScale), j = e((e) => e.timelineRange), M = e((e) => e.isRangeCustomized), N = e((e) => e.isExpandedCustomized), P = e((e) => e.setTimelineRange), F = e((e) => e.resetTimelineRange), I = e((e) => e.resetView), L = e((e) => e.tasks), R = e((e) => e.expandedIds), z = e((e) => e.expandAll), B = e((e) => e.collapseAll), V = e((e) => e.assigneeFilter), H = e((e) => e.setAssigneeFilter), U = n(() => [...new Set(L.flatMap((e) => e.assignee ? [e.assignee] : []))].sort(), [L]), W = L.length > 0 && L.every((e) => R.has(e.id)), G = O !== k || M || N || V !== "", K = n(() => Date.now(), []), q = K >= j.start.getTime() && K <= j.end.getTime(), J = {
|
|
21
21
|
days: D.scaleDays,
|
|
22
22
|
weeks: D.scaleWeeks,
|
|
23
23
|
months: D.scaleMonths,
|
|
@@ -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, mentionItems, mentionTriggerChar, name, onMentionSearch, 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, onSave, }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,37 +2,39 @@ 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
3
|
import { buildMentionSuggestion as r } from "./RichTextEditorMentionSuggestion.js";
|
|
4
4
|
import { RichTextEditorContent as i } from "./RichTextEditorContent.js";
|
|
5
|
-
import { RichTextEditorToolbar as
|
|
6
|
-
import { RichTextEditorFooter as
|
|
5
|
+
import { RichTextEditorToolbar as ee } from "./RichTextEditorToolbar.js";
|
|
6
|
+
import { RichTextEditorFooter as a } from "./RichTextEditorFooter.js";
|
|
7
7
|
import { useEffect as o, useMemo as te, useRef as s, useState as c } from "react";
|
|
8
|
-
import { Box as l, Divider as
|
|
9
|
-
import { Fragment as
|
|
10
|
-
import { useEditor as
|
|
11
|
-
import { Mention as
|
|
12
|
-
import { StarterKit as
|
|
13
|
-
import { TextStyle as
|
|
14
|
-
import { Color as
|
|
15
|
-
import { Highlight as
|
|
16
|
-
import { Placeholder as
|
|
17
|
-
import { CharacterCount as
|
|
18
|
-
import { TableKit as
|
|
19
|
-
import { Image as
|
|
20
|
-
import { Markdown as
|
|
8
|
+
import { Box as l, Divider as ne, Paper as re } from "@mui/material";
|
|
9
|
+
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
10
|
+
import { useEditor as p } from "@tiptap/react";
|
|
11
|
+
import { Mention as ie } from "@tiptap/extension-mention";
|
|
12
|
+
import { StarterKit as ae } from "@tiptap/starter-kit";
|
|
13
|
+
import { TextStyle as oe } from "@tiptap/extension-text-style";
|
|
14
|
+
import { Color as se } from "@tiptap/extension-color";
|
|
15
|
+
import { Highlight as ce } from "@tiptap/extension-highlight";
|
|
16
|
+
import { Placeholder as m } from "@tiptap/extension-placeholder";
|
|
17
|
+
import { CharacterCount as h } from "@tiptap/extension-character-count";
|
|
18
|
+
import { TableKit as g } from "@tiptap/extension-table";
|
|
19
|
+
import { Image as _ } from "@tiptap/extension-image";
|
|
20
|
+
import { Markdown as v } from "tiptap-markdown";
|
|
21
21
|
//#region src/components/rich-text-editor/RichTextEditor.tsx
|
|
22
|
-
function
|
|
23
|
-
let
|
|
22
|
+
function y({ disabled: y = !1, error: b = !1, height: le, helperText: x, maxCharacters: S, mentionItems: C, mentionTriggerChar: w = "@", name: T, onMentionSearch: E, placeholder: D, readonly: O = !1, showCharacterCount: k = !1, showToolbar: A = !0, showWordCount: j = !1, toolbarConfig: M, translation: N, value: P, width: F, onBlur: I, onChange: L, onFocus: R, onMarkdownChange: z, onSave: B }) {
|
|
23
|
+
let V = {
|
|
24
24
|
...n,
|
|
25
|
-
...
|
|
26
|
-
},
|
|
25
|
+
...N
|
|
26
|
+
}, H = {
|
|
27
27
|
...t,
|
|
28
|
-
...
|
|
29
|
-
}, [
|
|
28
|
+
...M
|
|
29
|
+
}, [U, W] = c(!1), [G, ue] = c(!1), K = s(G), q = s(B), J = s(C ?? []);
|
|
30
30
|
o(() => {
|
|
31
|
-
J.current =
|
|
32
|
-
}, [
|
|
33
|
-
|
|
34
|
-
}, [
|
|
35
|
-
|
|
31
|
+
J.current = C ?? [];
|
|
32
|
+
}, [C]), o(() => {
|
|
33
|
+
K.current = G;
|
|
34
|
+
}, [G]), o(() => {
|
|
35
|
+
q.current = B;
|
|
36
|
+
}, [B]);
|
|
37
|
+
let Y = e(le), de = e(F), X = Y === "auto", fe = X ? void 0 : Y ?? 200, Z = C !== void 0 || E !== void 0, Q = te(() => Z ? ie.configure({
|
|
36
38
|
HTMLAttributes: { class: "rte-mention" },
|
|
37
39
|
renderHTML({ options: e, node: t }) {
|
|
38
40
|
return [
|
|
@@ -42,70 +44,75 @@ function x({ disabled: x = !1, error: S = !1, height: se, helperText: C, maxChar
|
|
|
42
44
|
"data-id": t.attrs.id,
|
|
43
45
|
"data-label": t.attrs.label
|
|
44
46
|
},
|
|
45
|
-
`${
|
|
47
|
+
`${w}${t.attrs.label}`
|
|
46
48
|
];
|
|
47
49
|
},
|
|
48
50
|
suggestion: r({
|
|
49
51
|
getItems: () => J.current,
|
|
50
|
-
onMentionSearch:
|
|
51
|
-
noResultsLabel:
|
|
52
|
+
onMentionSearch: E,
|
|
53
|
+
noResultsLabel: V.mentionNoResults ?? "No results"
|
|
52
54
|
})
|
|
53
55
|
}) : null, [
|
|
54
56
|
Z,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
]),
|
|
57
|
+
w,
|
|
58
|
+
E
|
|
59
|
+
]), pe = S !== void 0 && S > 0 || k || j, $ = p({
|
|
58
60
|
shouldRerenderOnTransaction: !0,
|
|
59
61
|
extensions: [
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
ae.configure({ link: { openOnClick: !1 } }),
|
|
63
|
+
oe,
|
|
64
|
+
se,
|
|
65
|
+
ce.configure({ multicolor: !0 }),
|
|
66
|
+
v.configure({
|
|
65
67
|
transformPastedText: !0,
|
|
66
68
|
transformCopiedText: !1
|
|
67
69
|
}),
|
|
68
|
-
|
|
69
|
-
...
|
|
70
|
-
...
|
|
70
|
+
m.configure({ placeholder: D ?? "" }),
|
|
71
|
+
...H.showTableButton ? [g] : [],
|
|
72
|
+
...H.showImageButton ? [_.configure({
|
|
71
73
|
inline: !1,
|
|
72
74
|
allowBase64: !0
|
|
73
75
|
})] : [],
|
|
74
76
|
...Q ? [Q] : [],
|
|
75
|
-
...
|
|
77
|
+
...pe ? S !== void 0 && S > 0 ? [h.configure({ limit: S })] : [h] : []
|
|
76
78
|
],
|
|
77
|
-
content:
|
|
78
|
-
editable: !
|
|
79
|
-
editorProps: {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
content: P ?? "",
|
|
80
|
+
editable: !y && !O,
|
|
81
|
+
editorProps: {
|
|
82
|
+
handlePaste(e, t) {
|
|
83
|
+
if (!K.current) return !1;
|
|
84
|
+
let n = t.clipboardData?.getData("text/plain");
|
|
85
|
+
if (!n) return !1;
|
|
86
|
+
t.preventDefault();
|
|
87
|
+
let { state: r } = e;
|
|
88
|
+
return e.dispatch(r.tr.insertText(n, r.selection.from, r.selection.to)), !0;
|
|
89
|
+
},
|
|
90
|
+
handleKeyDown(e, t) {
|
|
91
|
+
return (t.ctrlKey || t.metaKey) && t.key === "s" ? (t.preventDefault(), q.current?.(), !0) : !1;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
87
94
|
onUpdate({ editor: e }) {
|
|
88
|
-
|
|
95
|
+
L?.(e.getHTML()), z?.(e.storage.markdown.getMarkdown());
|
|
89
96
|
},
|
|
90
97
|
onBlur() {
|
|
91
|
-
|
|
98
|
+
I?.();
|
|
92
99
|
},
|
|
93
100
|
onFocus() {
|
|
94
|
-
|
|
101
|
+
R?.();
|
|
95
102
|
}
|
|
96
103
|
});
|
|
97
104
|
o(() => {
|
|
98
|
-
!$ ||
|
|
99
|
-
}, [$,
|
|
100
|
-
$ && $.setEditable(!
|
|
105
|
+
!$ || P === void 0 || $.getHTML() !== P && $.commands.setContent(P, { emitUpdate: !1 });
|
|
106
|
+
}, [$, P]), o(() => {
|
|
107
|
+
$ && $.setEditable(!y && !O);
|
|
101
108
|
}, [
|
|
102
109
|
$,
|
|
103
|
-
|
|
104
|
-
|
|
110
|
+
y,
|
|
111
|
+
O
|
|
105
112
|
]);
|
|
106
|
-
let
|
|
107
|
-
return /* @__PURE__ */
|
|
108
|
-
sx:
|
|
113
|
+
let me = $?.storage.characterCount?.characters?.() ?? 0, he = $?.storage.characterCount?.words?.() ?? 0, ge = k || S !== void 0 && S > 0 || j || !!x;
|
|
114
|
+
return /* @__PURE__ */ f(l, {
|
|
115
|
+
sx: U ? {
|
|
109
116
|
position: "fixed",
|
|
110
117
|
top: 0,
|
|
111
118
|
left: 0,
|
|
@@ -117,7 +124,7 @@ function x({ disabled: x = !1, error: S = !1, height: se, helperText: C, maxChar
|
|
|
117
124
|
bgcolor: "background.default",
|
|
118
125
|
p: 1
|
|
119
126
|
} : {
|
|
120
|
-
width:
|
|
127
|
+
width: de ?? "100%",
|
|
121
128
|
...X ? {
|
|
122
129
|
display: "flex",
|
|
123
130
|
flexDirection: "column",
|
|
@@ -125,52 +132,52 @@ function x({ disabled: x = !1, error: S = !1, height: se, helperText: C, maxChar
|
|
|
125
132
|
} : {}
|
|
126
133
|
},
|
|
127
134
|
children: [
|
|
128
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ f(re, {
|
|
129
136
|
variant: "outlined",
|
|
130
137
|
sx: {
|
|
131
138
|
display: "flex",
|
|
132
139
|
flexDirection: "column",
|
|
133
140
|
overflow: "hidden",
|
|
134
|
-
...
|
|
135
|
-
borderColor:
|
|
141
|
+
...U || X ? { flex: 1 } : { height: fe },
|
|
142
|
+
borderColor: b ? "error.main" : void 0,
|
|
136
143
|
"&:focus-within": {
|
|
137
|
-
borderColor:
|
|
144
|
+
borderColor: b ? "error.main" : "primary.main",
|
|
138
145
|
borderWidth: 2
|
|
139
146
|
}
|
|
140
147
|
},
|
|
141
|
-
children: [
|
|
148
|
+
children: [A && !O && /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d(ee, {
|
|
142
149
|
editor: $,
|
|
143
|
-
toolbarConfig:
|
|
144
|
-
translation:
|
|
145
|
-
disabled:
|
|
146
|
-
isFullscreen:
|
|
147
|
-
onToggleFullscreen: () =>
|
|
148
|
-
pasteAsPlainText:
|
|
149
|
-
onTogglePasteAsPlainText: () =>
|
|
150
|
-
}), /* @__PURE__ */
|
|
150
|
+
toolbarConfig: H,
|
|
151
|
+
translation: V,
|
|
152
|
+
disabled: y,
|
|
153
|
+
isFullscreen: U,
|
|
154
|
+
onToggleFullscreen: () => W((e) => !e),
|
|
155
|
+
pasteAsPlainText: G,
|
|
156
|
+
onTogglePasteAsPlainText: () => ue((e) => !e)
|
|
157
|
+
}), /* @__PURE__ */ d(ne, {})] }), /* @__PURE__ */ d(i, {
|
|
151
158
|
editor: $,
|
|
152
|
-
error:
|
|
153
|
-
disabled:
|
|
154
|
-
readonly:
|
|
159
|
+
error: b,
|
|
160
|
+
disabled: y,
|
|
161
|
+
readonly: O
|
|
155
162
|
})]
|
|
156
163
|
}),
|
|
157
|
-
|
|
158
|
-
helperText:
|
|
159
|
-
error:
|
|
160
|
-
showCharacterCount:
|
|
161
|
-
charCount:
|
|
162
|
-
maxCharacters:
|
|
163
|
-
showWordCount:
|
|
164
|
-
wordCount:
|
|
165
|
-
translation:
|
|
164
|
+
ge && /* @__PURE__ */ d(a, {
|
|
165
|
+
helperText: x,
|
|
166
|
+
error: b,
|
|
167
|
+
showCharacterCount: k || S !== void 0 && S > 0,
|
|
168
|
+
charCount: me,
|
|
169
|
+
maxCharacters: S && S > 0 ? S : void 0,
|
|
170
|
+
showWordCount: j,
|
|
171
|
+
wordCount: he,
|
|
172
|
+
translation: V
|
|
166
173
|
}),
|
|
167
|
-
|
|
174
|
+
T && /* @__PURE__ */ d("input", {
|
|
168
175
|
type: "hidden",
|
|
169
|
-
name:
|
|
176
|
+
name: T,
|
|
170
177
|
value: $ ? $.getHTML() : ""
|
|
171
178
|
})
|
|
172
179
|
]
|
|
173
180
|
});
|
|
174
181
|
}
|
|
175
182
|
//#endregion
|
|
176
|
-
export {
|
|
183
|
+
export { y as RichTextEditor };
|
|
@@ -150,4 +150,10 @@ export type RichTextEditorProps = {
|
|
|
150
150
|
onFocus?: () => void;
|
|
151
151
|
/** Wird bei jeder Änderung zusätzlich zu onChange mit dem Inhalt als Markdown aufgerufen */
|
|
152
152
|
onMarkdownChange?: (markdown: string) => void;
|
|
153
|
+
/**
|
|
154
|
+
* Fires when the user presses Ctrl+S (Windows/Linux) or Cmd+S (macOS) inside the editor.
|
|
155
|
+
* The browser's native "Save Page" dialog is always suppressed within the editor.
|
|
156
|
+
* When provided, implement your own save logic (API call, local storage, etc.).
|
|
157
|
+
*/
|
|
158
|
+
onSave?: () => void;
|
|
153
159
|
};
|