@datum-cloud/datum-ui 3.4.1 → 3.5.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/components/features/rich-text-editor/content.d.ts +2 -0
- package/dist/index.mjs +2 -1
- package/dist/rich-text-content/index.mjs +2 -0
- package/dist/rich-text-content-DNonBD39.mjs +63 -0
- package/dist/rich-text-editor/index.mjs +2 -1
- package/dist/{rich-text-editor-DVga5upM.mjs → rich-text-editor-DP5JnAoO.mjs} +1 -61
- package/package.json +9 -1
package/dist/index.mjs
CHANGED
|
@@ -78,7 +78,8 @@ import { t as Logo } from "./logo-C3FxD7jb.mjs";
|
|
|
78
78
|
import { t as MoreActions } from "./more-actions-C3DYWO0a.mjs";
|
|
79
79
|
import { configureProgress, startProgress, stopProgress } from "./nprogress/index.mjs";
|
|
80
80
|
import { t as PageTitle } from "./page-title-ipRWEOeM.mjs";
|
|
81
|
-
import {
|
|
81
|
+
import { t as RichTextContent } from "./rich-text-content-DNonBD39.mjs";
|
|
82
|
+
import { n as useRichTextEditor, t as RichTextEditor } from "./rich-text-editor-DP5JnAoO.mjs";
|
|
82
83
|
import { t as defineStepper } from "./stepper-dNvkipop.mjs";
|
|
83
84
|
import { t as TagsInput } from "./tag-input-c9OvWTSe.mjs";
|
|
84
85
|
import { _ as RedisTaskStorage, a as TaskPanelItem, b as createProjectMetadata, c as TaskPanelHeader, d as useCurrentScope, f as useTasksWithLabels, g as detectStorage, h as TaskQueue, i as TaskPanel, l as getContextLabel, m as TaskQueueProvider, n as TaskSummaryDialog, o as TaskPanelCounter, p as useTaskQueue, r as TaskQueueTrigger, s as TaskPanelActions, t as TaskQueueDropdown, u as matchesCurrentScope, v as LocalTaskStorage, x as createUserMetadata, y as createOrgMetadata } from "./task-queue-dropdown-CHPP5WIm.mjs";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { t as cn } from "./utils-Bu32wN-x.mjs";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import DOMPurify from "isomorphic-dompurify";
|
|
4
|
+
//#region src/components/features/rich-text-editor/rich-text-content.tsx
|
|
5
|
+
const SANITIZE_CONFIG = {
|
|
6
|
+
ALLOWED_TAGS: [
|
|
7
|
+
"strong",
|
|
8
|
+
"em",
|
|
9
|
+
"u",
|
|
10
|
+
"s",
|
|
11
|
+
"a",
|
|
12
|
+
"p",
|
|
13
|
+
"br"
|
|
14
|
+
],
|
|
15
|
+
ALLOWED_ATTR: [
|
|
16
|
+
"href",
|
|
17
|
+
"target",
|
|
18
|
+
"rel"
|
|
19
|
+
]
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* A bare domain (e.g. `example.com`) has no scheme and isn't a relative or
|
|
23
|
+
* fragment reference, so it needs an https:// prefix to resolve correctly.
|
|
24
|
+
* Anything already scheme-qualified (mailto:, tel:, http(s):, protocol-relative
|
|
25
|
+
* //) or relative (/path, #anchor, ?query, ./, ../) must be left untouched.
|
|
26
|
+
*/
|
|
27
|
+
function needsHttpsPrefix(href) {
|
|
28
|
+
if (!href) return false;
|
|
29
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(href)) return false;
|
|
30
|
+
if (/^[/#?.]/.test(href)) return false;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Post-sanitization: normalizes link hrefs and hardens external links.
|
|
35
|
+
* Applied AFTER DOMPurify so we only touch already-clean HTML.
|
|
36
|
+
*
|
|
37
|
+
* Only bare domains get an https:// prefix, and only http(s) links get
|
|
38
|
+
* target/rel hardening — relative, fragment, tel:, and mailto: links are
|
|
39
|
+
* preserved as-authored so they keep working.
|
|
40
|
+
*/
|
|
41
|
+
function normalizeLinks(html) {
|
|
42
|
+
return html.replace(/<a\s([^>]*)>/gi, (_match, attrs) => {
|
|
43
|
+
const href = attrs.match(/href="([^"]*)"/i)?.[1] ?? "";
|
|
44
|
+
const prefixed = needsHttpsPrefix(href);
|
|
45
|
+
let normalized = attrs;
|
|
46
|
+
if (prefixed) normalized = normalized.replace(/href="[^"]*"/i, `href="https://${href}"`);
|
|
47
|
+
if (prefixed || /^https?:\/\//i.test(href)) {
|
|
48
|
+
if (!/\btarget=/i.test(normalized)) normalized += " target=\"_blank\"";
|
|
49
|
+
if (!/\brel=/i.test(normalized)) normalized += " rel=\"noopener noreferrer\"";
|
|
50
|
+
}
|
|
51
|
+
return `<a ${normalized}>`;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function RichTextContent({ content, className }) {
|
|
55
|
+
if (!content) return null;
|
|
56
|
+
const withSafeLinks = normalizeLinks(DOMPurify.sanitize(content, SANITIZE_CONFIG));
|
|
57
|
+
return /* @__PURE__ */ jsx("div", {
|
|
58
|
+
className: cn("prose prose-sm dark:prose-invert max-w-none", "[&_a]:text-primary text-sm [&_a]:underline [&_p]:my-1 [&_p:empty]:min-h-[1em]", className),
|
|
59
|
+
dangerouslySetInnerHTML: { __html: withSafeLinks }
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { RichTextContent as t };
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as RichTextContent } from "../rich-text-content-DNonBD39.mjs";
|
|
2
|
+
import { n as useRichTextEditor, t as RichTextEditor } from "../rich-text-editor-DP5JnAoO.mjs";
|
|
2
3
|
export { RichTextContent, RichTextEditor, useRichTextEditor };
|
|
@@ -7,72 +7,12 @@ import { t as Tooltip } from "./tooltip-DhbN1BDK.mjs";
|
|
|
7
7
|
import { BoldIcon, ItalicIcon, LinkIcon, StrikethroughIcon, UnderlineIcon, UnlinkIcon } from "lucide-react";
|
|
8
8
|
import { createContext, use, useCallback, useEffect, useState } from "react";
|
|
9
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import DOMPurify from "isomorphic-dompurify";
|
|
11
10
|
import CharacterCount from "@tiptap/extension-character-count";
|
|
12
11
|
import Link from "@tiptap/extension-link";
|
|
13
12
|
import Placeholder from "@tiptap/extension-placeholder";
|
|
14
13
|
import Underline from "@tiptap/extension-underline";
|
|
15
14
|
import { EditorContent, useEditor } from "@tiptap/react";
|
|
16
15
|
import StarterKit from "@tiptap/starter-kit";
|
|
17
|
-
//#region src/components/features/rich-text-editor/rich-text-content.tsx
|
|
18
|
-
const SANITIZE_CONFIG = {
|
|
19
|
-
ALLOWED_TAGS: [
|
|
20
|
-
"strong",
|
|
21
|
-
"em",
|
|
22
|
-
"u",
|
|
23
|
-
"s",
|
|
24
|
-
"a",
|
|
25
|
-
"p",
|
|
26
|
-
"br"
|
|
27
|
-
],
|
|
28
|
-
ALLOWED_ATTR: [
|
|
29
|
-
"href",
|
|
30
|
-
"target",
|
|
31
|
-
"rel"
|
|
32
|
-
]
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* A bare domain (e.g. `example.com`) has no scheme and isn't a relative or
|
|
36
|
-
* fragment reference, so it needs an https:// prefix to resolve correctly.
|
|
37
|
-
* Anything already scheme-qualified (mailto:, tel:, http(s):, protocol-relative
|
|
38
|
-
* //) or relative (/path, #anchor, ?query, ./, ../) must be left untouched.
|
|
39
|
-
*/
|
|
40
|
-
function needsHttpsPrefix(href) {
|
|
41
|
-
if (!href) return false;
|
|
42
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(href)) return false;
|
|
43
|
-
if (/^[/#?.]/.test(href)) return false;
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Post-sanitization: normalizes link hrefs and hardens external links.
|
|
48
|
-
* Applied AFTER DOMPurify so we only touch already-clean HTML.
|
|
49
|
-
*
|
|
50
|
-
* Only bare domains get an https:// prefix, and only http(s) links get
|
|
51
|
-
* target/rel hardening — relative, fragment, tel:, and mailto: links are
|
|
52
|
-
* preserved as-authored so they keep working.
|
|
53
|
-
*/
|
|
54
|
-
function normalizeLinks(html) {
|
|
55
|
-
return html.replace(/<a\s([^>]*)>/gi, (_match, attrs) => {
|
|
56
|
-
const href = attrs.match(/href="([^"]*)"/i)?.[1] ?? "";
|
|
57
|
-
const prefixed = needsHttpsPrefix(href);
|
|
58
|
-
let normalized = attrs;
|
|
59
|
-
if (prefixed) normalized = normalized.replace(/href="[^"]*"/i, `href="https://${href}"`);
|
|
60
|
-
if (prefixed || /^https?:\/\//i.test(href)) {
|
|
61
|
-
if (!/\btarget=/i.test(normalized)) normalized += " target=\"_blank\"";
|
|
62
|
-
if (!/\brel=/i.test(normalized)) normalized += " rel=\"noopener noreferrer\"";
|
|
63
|
-
}
|
|
64
|
-
return `<a ${normalized}>`;
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
function RichTextContent({ content, className }) {
|
|
68
|
-
if (!content) return null;
|
|
69
|
-
const withSafeLinks = normalizeLinks(DOMPurify.sanitize(content, SANITIZE_CONFIG));
|
|
70
|
-
return /* @__PURE__ */ jsx("div", {
|
|
71
|
-
className: cn("prose prose-sm dark:prose-invert max-w-none", "[&_a]:text-primary text-sm [&_a]:underline [&_p]:my-1 [&_p:empty]:min-h-[1em]", className),
|
|
72
|
-
dangerouslySetInnerHTML: { __html: withSafeLinks }
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
//#endregion
|
|
76
16
|
//#region src/components/features/rich-text-editor/toolbar/toolbar-button.tsx
|
|
77
17
|
function ToolbarButton({ ref, active, disabled, onClick, tooltip, children, className }) {
|
|
78
18
|
const button = /* @__PURE__ */ jsx("button", {
|
|
@@ -331,4 +271,4 @@ const RichTextEditor = Object.assign(RichTextEditorRoot, {
|
|
|
331
271
|
Separator: ToolbarSeparator
|
|
332
272
|
});
|
|
333
273
|
//#endregion
|
|
334
|
-
export { useRichTextEditor as n,
|
|
274
|
+
export { useRichTextEditor as n, RichTextEditor as t };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datum-cloud/datum-ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.5.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"url": "https://github.com/datum-cloud/datum-ui"
|
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
"style": "./dist/styles/canela.css",
|
|
24
24
|
"default": "./dist/styles/canela.css"
|
|
25
25
|
},
|
|
26
|
+
"./fonts/*": {
|
|
27
|
+
"default": "./dist/styles/fonts/*"
|
|
28
|
+
},
|
|
26
29
|
"./theme": {
|
|
27
30
|
"source": "./src/components/themes/index.ts",
|
|
28
31
|
"types": "./dist/components/themes/index.d.ts",
|
|
@@ -163,6 +166,11 @@
|
|
|
163
166
|
"types": "./dist/components/features/rich-text-editor/index.d.ts",
|
|
164
167
|
"default": "./dist/rich-text-editor/index.mjs"
|
|
165
168
|
},
|
|
169
|
+
"./rich-text-content": {
|
|
170
|
+
"source": "./src/components/features/rich-text-editor/content.ts",
|
|
171
|
+
"types": "./dist/components/features/rich-text-editor/content.d.ts",
|
|
172
|
+
"default": "./dist/rich-text-content/index.mjs"
|
|
173
|
+
},
|
|
166
174
|
"./select": {
|
|
167
175
|
"source": "./src/components/base/select/index.ts",
|
|
168
176
|
"types": "./dist/components/base/select/index.d.ts",
|