@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.
@@ -0,0 +1,2 @@
1
+ export { RichTextContent } from './rich-text-content';
2
+ export type { RichTextContentProps } from './types';
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 { n as useRichTextEditor, r as RichTextContent, t as RichTextEditor } from "./rich-text-editor-DVga5upM.mjs";
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,2 @@
1
+ import { t as RichTextContent } from "../rich-text-content-DNonBD39.mjs";
2
+ export { RichTextContent };
@@ -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 { n as useRichTextEditor, r as RichTextContent, t as RichTextEditor } from "../rich-text-editor-DVga5upM.mjs";
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, RichTextContent as r, RichTextEditor as t };
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.1",
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",