tempest-react-sdk 0.29.1 → 0.31.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.
Files changed (85) hide show
  1. package/dist/components/Chat/Chat.cjs +2 -0
  2. package/dist/components/Chat/Chat.cjs.map +1 -0
  3. package/dist/components/Chat/Chat.js +126 -0
  4. package/dist/components/Chat/Chat.js.map +1 -0
  5. package/dist/components/Chat/Chat.module.cjs +2 -0
  6. package/dist/components/Chat/Chat.module.cjs.map +1 -0
  7. package/dist/components/Chat/Chat.module.js +32 -0
  8. package/dist/components/Chat/Chat.module.js.map +1 -0
  9. package/dist/components/Chat/ChatComposer.cjs +2 -0
  10. package/dist/components/Chat/ChatComposer.cjs.map +1 -0
  11. package/dist/components/Chat/ChatComposer.js +67 -0
  12. package/dist/components/Chat/ChatComposer.js.map +1 -0
  13. package/dist/components/Chat/chat-groups.cjs +2 -0
  14. package/dist/components/Chat/chat-groups.cjs.map +1 -0
  15. package/dist/components/Chat/chat-groups.js +89 -0
  16. package/dist/components/Chat/chat-groups.js.map +1 -0
  17. package/dist/components/FilterBar/FilterBar.cjs +2 -0
  18. package/dist/components/FilterBar/FilterBar.cjs.map +1 -0
  19. package/dist/components/FilterBar/FilterBar.js +238 -0
  20. package/dist/components/FilterBar/FilterBar.js.map +1 -0
  21. package/dist/components/FilterBar/FilterBar.module.cjs +2 -0
  22. package/dist/components/FilterBar/FilterBar.module.cjs.map +1 -0
  23. package/dist/components/FilterBar/FilterBar.module.js +20 -0
  24. package/dist/components/FilterBar/FilterBar.module.js.map +1 -0
  25. package/dist/components/FilterBar/filter-model.cjs +2 -0
  26. package/dist/components/FilterBar/filter-model.cjs.map +1 -0
  27. package/dist/components/FilterBar/filter-model.js +167 -0
  28. package/dist/components/FilterBar/filter-model.js.map +1 -0
  29. package/dist/components/Markdown/Markdown.cjs +2 -0
  30. package/dist/components/Markdown/Markdown.cjs.map +1 -0
  31. package/dist/components/Markdown/Markdown.js +124 -0
  32. package/dist/components/Markdown/Markdown.js.map +1 -0
  33. package/dist/components/Markdown/Markdown.module.cjs +2 -0
  34. package/dist/components/Markdown/Markdown.module.cjs.map +1 -0
  35. package/dist/components/Markdown/Markdown.module.js +23 -0
  36. package/dist/components/Markdown/Markdown.module.js.map +1 -0
  37. package/dist/components/Markdown/markdown-parse.cjs +7 -0
  38. package/dist/components/Markdown/markdown-parse.cjs.map +1 -0
  39. package/dist/components/Markdown/markdown-parse.js +269 -0
  40. package/dist/components/Markdown/markdown-parse.js.map +1 -0
  41. package/dist/components/Markdown/markdown-url.cjs +2 -0
  42. package/dist/components/Markdown/markdown-url.cjs.map +1 -0
  43. package/dist/components/Markdown/markdown-url.js +28 -0
  44. package/dist/components/Markdown/markdown-url.js.map +1 -0
  45. package/dist/components/Masonry/Masonry.cjs +2 -0
  46. package/dist/components/Masonry/Masonry.cjs.map +1 -0
  47. package/dist/components/Masonry/Masonry.js +70 -0
  48. package/dist/components/Masonry/Masonry.js.map +1 -0
  49. package/dist/components/Masonry/Masonry.module.cjs +2 -0
  50. package/dist/components/Masonry/Masonry.module.cjs.map +1 -0
  51. package/dist/components/Masonry/Masonry.module.js +10 -0
  52. package/dist/components/Masonry/Masonry.module.js.map +1 -0
  53. package/dist/components/Masonry/masonry-layout.cjs +2 -0
  54. package/dist/components/Masonry/masonry-layout.cjs.map +1 -0
  55. package/dist/components/Masonry/masonry-layout.js +20 -0
  56. package/dist/components/Masonry/masonry-layout.js.map +1 -0
  57. package/dist/components/Tour/Tour.cjs +2 -0
  58. package/dist/components/Tour/Tour.cjs.map +1 -0
  59. package/dist/components/Tour/Tour.js +186 -0
  60. package/dist/components/Tour/Tour.js.map +1 -0
  61. package/dist/components/Tour/Tour.module.cjs +2 -0
  62. package/dist/components/Tour/Tour.module.cjs.map +1 -0
  63. package/dist/components/Tour/Tour.module.js +21 -0
  64. package/dist/components/Tour/Tour.module.js.map +1 -0
  65. package/dist/components/Tour/tour-position.cjs +2 -0
  66. package/dist/components/Tour/tour-position.cjs.map +1 -0
  67. package/dist/components/Tour/tour-position.js +105 -0
  68. package/dist/components/Tour/tour-position.js.map +1 -0
  69. package/dist/components/Transfer/Transfer.cjs +2 -0
  70. package/dist/components/Transfer/Transfer.cjs.map +1 -0
  71. package/dist/components/Transfer/Transfer.js +163 -0
  72. package/dist/components/Transfer/Transfer.js.map +1 -0
  73. package/dist/components/Transfer/Transfer.module.cjs +2 -0
  74. package/dist/components/Transfer/Transfer.module.cjs.map +1 -0
  75. package/dist/components/Transfer/Transfer.module.js +19 -0
  76. package/dist/components/Transfer/Transfer.module.js.map +1 -0
  77. package/dist/components/Transfer/transfer-state.cjs +2 -0
  78. package/dist/components/Transfer/transfer-state.cjs.map +1 -0
  79. package/dist/components/Transfer/transfer-state.js +59 -0
  80. package/dist/components/Transfer/transfer-state.js.map +1 -0
  81. package/dist/styles.css +1 -1
  82. package/dist/tempest-react-sdk.cjs +1 -1
  83. package/dist/tempest-react-sdk.d.ts +674 -0
  84. package/dist/tempest-react-sdk.js +117 -105
  85. package/package.json +1 -1
@@ -0,0 +1,124 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ import { useScrollOverflow as t } from "../../hooks/use-scroll-overflow.js";
3
+ import { CodeBlock as n } from "../CodeBlock/CodeBlock.js";
4
+ import { parseMarkdown as r } from "./markdown-parse.js";
5
+ import i from "./Markdown.module.js";
6
+ import { Fragment as a, useMemo as o, useRef as s } from "react";
7
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
8
+ //#region src/components/Markdown/Markdown.tsx
9
+ function u(e) {
10
+ return e.map((e, t) => {
11
+ let n = t;
12
+ switch (e.type) {
13
+ case "text": return /* @__PURE__ */ c(a, { children: e.value }, n);
14
+ case "strong": return /* @__PURE__ */ c("strong", { children: u(e.children) }, n);
15
+ case "em": return /* @__PURE__ */ c("em", { children: u(e.children) }, n);
16
+ case "del": return /* @__PURE__ */ c("del", { children: u(e.children) }, n);
17
+ case "code": return /* @__PURE__ */ c("code", {
18
+ className: i.inlineCode,
19
+ children: e.value
20
+ }, n);
21
+ case "image": return /* @__PURE__ */ c("img", {
22
+ className: i.image,
23
+ src: e.src,
24
+ alt: e.alt
25
+ }, n);
26
+ case "break": return /* @__PURE__ */ c("br", {}, n);
27
+ default: return null;
28
+ }
29
+ });
30
+ }
31
+ function d(e) {
32
+ return e ? { textAlign: e } : void 0;
33
+ }
34
+ function f({ source: t, headingOffset: n = 2, highlightCode: a = !0, showLineNumbers: s = !1, linkProps: l, className: u, ...d }) {
35
+ let f = o(() => r(t), [t]);
36
+ return /* @__PURE__ */ c("div", {
37
+ className: e(i.root, u),
38
+ ...d,
39
+ children: f.map((e, t) => /* @__PURE__ */ c(p, {
40
+ block: e,
41
+ headingOffset: n,
42
+ highlightCode: a,
43
+ showLineNumbers: s,
44
+ linkProps: l
45
+ }, t))
46
+ });
47
+ }
48
+ function p({ block: e, headingOffset: t, highlightCode: r, showLineNumbers: o, linkProps: s }) {
49
+ let l = (e) => e.map((e, n) => /* @__PURE__ */ c(p, {
50
+ block: e,
51
+ headingOffset: t,
52
+ highlightCode: r,
53
+ showLineNumbers: o,
54
+ linkProps: s
55
+ }, n)), d = (e) => e.map((e, t) => e.type === "link" ? /* @__PURE__ */ c("a", {
56
+ className: i.link,
57
+ href: e.href,
58
+ ...s,
59
+ children: u(e.children)
60
+ }, t) : /* @__PURE__ */ c(a, { children: u([e]) }, t));
61
+ switch (e.type) {
62
+ case "heading": {
63
+ let n = Math.min(6, Math.max(1, e.level + t - 1));
64
+ return /* @__PURE__ */ c(`h${n}`, {
65
+ className: i[`h${n}`],
66
+ children: d(e.children)
67
+ });
68
+ }
69
+ case "paragraph": return /* @__PURE__ */ c("p", { children: d(e.children) });
70
+ case "code": return r ? /* @__PURE__ */ c(n, {
71
+ code: e.value,
72
+ language: e.language ?? void 0,
73
+ showLineNumbers: o
74
+ }) : /* @__PURE__ */ c("pre", { children: /* @__PURE__ */ c("code", { children: e.value }) });
75
+ case "quote": return /* @__PURE__ */ c("blockquote", {
76
+ className: i.quote,
77
+ children: l(e.children)
78
+ });
79
+ case "rule": return /* @__PURE__ */ c("hr", { className: i.rule });
80
+ case "list": return e.ordered ? /* @__PURE__ */ c("ol", {
81
+ className: i.list,
82
+ start: e.start === 1 ? void 0 : e.start,
83
+ children: e.items.map((e, t) => /* @__PURE__ */ c("li", {
84
+ className: i.item,
85
+ children: l(e)
86
+ }, t))
87
+ }) : /* @__PURE__ */ c("ul", {
88
+ className: i.list,
89
+ children: e.items.map((e, t) => /* @__PURE__ */ c("li", {
90
+ className: i.item,
91
+ children: l(e)
92
+ }, t))
93
+ });
94
+ case "table": return /* @__PURE__ */ c(m, {
95
+ block: e,
96
+ inline: d
97
+ });
98
+ default: return null;
99
+ }
100
+ }
101
+ function m({ block: e, inline: n }) {
102
+ let r = s(null), a = t(r, "horizontal");
103
+ return /* @__PURE__ */ c("div", {
104
+ ref: r,
105
+ className: i.tableScroll,
106
+ tabIndex: a ? 0 : void 0,
107
+ role: a ? "region" : void 0,
108
+ "aria-label": a ? "Tabela rolável" : void 0,
109
+ children: /* @__PURE__ */ l("table", {
110
+ className: i.table,
111
+ children: [/* @__PURE__ */ c("thead", { children: /* @__PURE__ */ c("tr", { children: e.head.map((t, r) => /* @__PURE__ */ c("th", {
112
+ style: d(e.align[r] ?? null),
113
+ children: n(t)
114
+ }, r)) }) }), /* @__PURE__ */ c("tbody", { children: e.rows.map((t, r) => /* @__PURE__ */ c("tr", { children: t.map((t, r) => /* @__PURE__ */ c("td", {
115
+ style: d(e.align[r] ?? null),
116
+ children: n(t)
117
+ }, r)) }, r)) })]
118
+ })
119
+ });
120
+ }
121
+ //#endregion
122
+ export { f as Markdown };
123
+
124
+ //# sourceMappingURL=Markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Markdown.js","names":[],"sources":["../../../src/components/Markdown/Markdown.tsx"],"sourcesContent":["import { Fragment, useMemo, useRef, type HTMLAttributes, type ReactNode } from \"react\";\n\nimport { useScrollOverflow } from \"@/hooks/use-scroll-overflow\";\nimport { cn } from \"@/utils/cn\";\n\nimport { CodeBlock } from \"../CodeBlock\";\nimport {\n parseMarkdown,\n type MarkdownAlign,\n type MarkdownBlock,\n type MarkdownInline,\n} from \"./markdown-parse\";\nimport styles from \"./Markdown.module.css\";\n\n/** DOM attributes this component redefines. */\ntype OverriddenDomProps = \"children\";\n\nexport interface MarkdownProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps> {\n /** The Markdown source. */\n source: string;\n /**\n * Heading level the document's `#` maps to. Default 2.\n *\n * A comment body rendered inside a page whose `<h1>` is the page title must not\n * emit a second `<h1>`; shifting the whole scale keeps the outline valid.\n */\n headingOffset?: number;\n /** Render fenced code with `CodeBlock` (copy button, line numbers). Default `true`. */\n highlightCode?: boolean;\n /** Show line numbers in fenced code. Default `false`. */\n showLineNumbers?: boolean;\n /** Extra props for every link — `target=\"_blank\"`, an analytics handler. */\n linkProps?: HTMLAttributes<HTMLAnchorElement> & { target?: string; rel?: string };\n}\n\n/** Render inline nodes. */\nfunction renderInline(nodes: readonly MarkdownInline[]): ReactNode {\n return nodes.map((node, index) => {\n const key = index;\n switch (node.type) {\n case \"text\":\n return <Fragment key={key}>{node.value}</Fragment>;\n case \"strong\":\n return <strong key={key}>{renderInline(node.children)}</strong>;\n case \"em\":\n return <em key={key}>{renderInline(node.children)}</em>;\n case \"del\":\n return <del key={key}>{renderInline(node.children)}</del>;\n case \"code\":\n return (\n <code key={key} className={styles.inlineCode}>\n {node.value}\n </code>\n );\n case \"image\":\n return <img key={key} className={styles.image} src={node.src} alt={node.alt} />;\n case \"break\":\n return <br key={key} />;\n default:\n return null;\n }\n });\n}\n\n/** CSS `text-align` for a table column. */\nfunction alignOf(align: MarkdownAlign): { textAlign: \"left\" | \"center\" | \"right\" } | undefined {\n return align ? { textAlign: align } : undefined;\n}\n\n/**\n * Rendered Markdown, from a node tree — never from an HTML string.\n *\n * `dangerouslySetInnerHTML` appears nowhere in this component. That is what makes\n * rendering somebody else's Markdown safe by construction rather than by a promise\n * about escaping: a `<script>` in a comment is four characters of text, because text\n * is all a React child can be.\n *\n * Link and image URLs go through a scheme **allowlist** (`http`, `https`, `mailto`,\n * `tel`, `sms`, plus relative), so `[click](javascript:alert(1))` renders as plain\n * text. A blocklist would have to enumerate every spelling of `javascript:` and\n * would miss one.\n *\n * @example\n * <Markdown source={comentario.corpo} linkProps={{ target: \"_blank\", rel: \"noreferrer\" }} />\n */\nexport function Markdown({\n source,\n headingOffset = 2,\n highlightCode = true,\n showLineNumbers = false,\n linkProps,\n className,\n ...rest\n}: MarkdownProps) {\n const blocks = useMemo(() => parseMarkdown(source), [source]);\n\n return (\n <div className={cn(styles.root, className)} {...rest}>\n {blocks.map((block, index) => (\n <Block\n key={index}\n block={block}\n headingOffset={headingOffset}\n highlightCode={highlightCode}\n showLineNumbers={showLineNumbers}\n linkProps={linkProps}\n />\n ))}\n </div>\n );\n}\n\ninterface BlockProps {\n block: MarkdownBlock;\n headingOffset: number;\n highlightCode: boolean;\n showLineNumbers: boolean;\n linkProps?: MarkdownProps[\"linkProps\"];\n}\n\n/** One block, and its children. */\nfunction Block({ block, headingOffset, highlightCode, showLineNumbers, linkProps }: BlockProps) {\n const children = (nodes: readonly MarkdownBlock[]): ReactNode =>\n nodes.map((child, index) => (\n <Block\n key={index}\n block={child}\n headingOffset={headingOffset}\n highlightCode={highlightCode}\n showLineNumbers={showLineNumbers}\n linkProps={linkProps}\n />\n ));\n\n const inline = (nodes: readonly MarkdownInline[]): ReactNode =>\n nodes.map((node, index) =>\n node.type === \"link\" ? (\n <a key={index} className={styles.link} href={node.href} {...linkProps}>\n {renderInline(node.children)}\n </a>\n ) : (\n <Fragment key={index}>{renderInline([node])}</Fragment>\n ),\n );\n\n switch (block.type) {\n case \"heading\": {\n const level = Math.min(6, Math.max(1, block.level + headingOffset - 1));\n const Tag = `h${level}` as \"h1\";\n return (\n <Tag className={styles[`h${level}` as keyof typeof styles]}>\n {inline(block.children)}\n </Tag>\n );\n }\n case \"paragraph\":\n return <p>{inline(block.children)}</p>;\n case \"code\":\n return highlightCode ? (\n <CodeBlock\n code={block.value}\n language={block.language ?? undefined}\n showLineNumbers={showLineNumbers}\n />\n ) : (\n <pre>\n <code>{block.value}</code>\n </pre>\n );\n case \"quote\":\n return <blockquote className={styles.quote}>{children(block.children)}</blockquote>;\n case \"rule\":\n return <hr className={styles.rule} />;\n case \"list\":\n return block.ordered ? (\n <ol className={styles.list} start={block.start === 1 ? undefined : block.start}>\n {block.items.map((item, index) => (\n <li key={index} className={styles.item}>\n {children(item)}\n </li>\n ))}\n </ol>\n ) : (\n <ul className={styles.list}>\n {block.items.map((item, index) => (\n <li key={index} className={styles.item}>\n {children(item)}\n </li>\n ))}\n </ul>\n );\n case \"table\":\n return <Table block={block} inline={inline} />;\n default:\n return null;\n }\n}\n\n/**\n * A table, in its own scroll box.\n *\n * The box only becomes a tab stop while it actually overflows: a scroll container\n * with nothing focusable inside cannot be reached by keyboard, and adding the stop\n * unconditionally would pollute the tab order with one entry per table on the page.\n */\nfunction Table({\n block,\n inline,\n}: {\n block: Extract<MarkdownBlock, { type: \"table\" }>;\n inline: (nodes: readonly MarkdownInline[]) => ReactNode;\n}) {\n const scroll = useRef<HTMLDivElement | null>(null);\n const overflowing = useScrollOverflow(scroll, \"horizontal\");\n\n return (\n <div\n ref={scroll}\n className={styles.tableScroll}\n tabIndex={overflowing ? 0 : undefined}\n role={overflowing ? \"region\" : undefined}\n aria-label={overflowing ? \"Tabela rolável\" : undefined}\n >\n <table className={styles.table}>\n <thead>\n <tr>\n {block.head.map((cell, index) => (\n <th key={index} style={alignOf(block.align[index] ?? null)}>\n {inline(cell)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {block.rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <td key={cellIndex} style={alignOf(block.align[cellIndex] ?? null)}>\n {inline(cell)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ var e=`tempest_root_L7b3z`,t=`tempest_h1_wpviN`,n=`tempest_h2_H0B9X`,r=`tempest_h3_zI9g3`,i=`tempest_h4_w1Khg`,a=`tempest_h5_MN-QR`,o=`tempest_h6_SFcgF`,s=`tempest_list_QopC7`,c=`tempest_item_0veAk`,l=`tempest_quote_QK3OF`,u=`tempest_rule_M019c`,d=`tempest_inlineCode_XsQik`,f=`tempest_link_prTnN`,p=`tempest_image_HjzdE`,m=`tempest_tableScroll_2u5gY`,h=`tempest_table_-CmP5`,g={root:e,h1:t,h2:n,h3:r,h4:i,h5:a,h6:o,list:s,item:c,quote:l,rule:u,inlineCode:d,link:f,image:p,tableScroll:m,table:h};exports.default=g,exports.h1=t,exports.h2=n,exports.h3=r,exports.h4=i,exports.h5=a,exports.h6=o,exports.image=p,exports.inlineCode=d,exports.item=c,exports.link=f,exports.list=s,exports.quote=l,exports.root=e,exports.rule=u,exports.table=h,exports.tableScroll=m;
2
+ //# sourceMappingURL=Markdown.module.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Markdown.module.cjs","names":[],"sources":["../../../src/components/Markdown/Markdown.module.css"],"sourcesContent":[".root {\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-relaxed);\n overflow-wrap: anywhere;\n}\n\n/*\n * Every block spaces itself with `margin-block-end` and the last child clears it,\n * so a Markdown body dropped into a card does not add a phantom gap at the bottom.\n */\n.root > * {\n margin-block: 0 var(--tempest-space-3);\n}\n\n.root > *:last-child {\n margin-block-end: 0;\n}\n\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n margin-block-start: var(--tempest-space-5);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-tight);\n}\n\n.root > .h1:first-child,\n.root > .h2:first-child,\n.root > .h3:first-child,\n.root > .h4:first-child,\n.root > .h5:first-child,\n.root > .h6:first-child {\n margin-block-start: 0;\n}\n\n.h1 {\n font-size: var(--tempest-text-2xl);\n}\n\n.h2 {\n font-size: var(--tempest-text-xl);\n}\n\n.h3 {\n font-size: var(--tempest-text-lg);\n}\n\n.h4,\n.h5,\n.h6 {\n font-size: var(--tempest-text-base);\n}\n\n.list {\n padding-inline-start: var(--tempest-space-6);\n}\n\n.list .list {\n margin-block: var(--tempest-space-1) 0;\n}\n\n.item {\n margin-block-end: var(--tempest-space-1);\n}\n\n.item > p {\n margin: 0;\n}\n\n.quote {\n padding-inline-start: var(--tempest-space-4);\n border-inline-start: 3px solid var(--tempest-border-strong);\n color: var(--tempest-text-muted);\n}\n\n.rule {\n height: 1px;\n border: 0;\n background-color: var(--tempest-border);\n}\n\n.inlineCode {\n padding: 0.1em 0.35em;\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-code-text, var(--tempest-text));\n font-family: var(--tempest-font-mono);\n font-size: 0.9em;\n}\n\n.link {\n color: var(--tempest-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.image {\n max-width: 100%;\n height: auto;\n border-radius: var(--tempest-radius-md);\n}\n\n/*\n * A wide table scrolls inside its own box, and that box is focusable — a scroll\n * container with nothing focusable inside cannot be reached by keyboard, which is\n * the same defect the Table fix addressed.\n */\n.tableScroll {\n overflow-x: auto;\n}\n\n.tableScroll:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tempest-text-sm);\n}\n\n.table th,\n.table td {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left;\n}\n\n.table th {\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n}\n"],"mappings":""}
@@ -0,0 +1,23 @@
1
+ //#region src/components/Markdown/Markdown.module.css
2
+ var e = "tempest_root_L7b3z", t = "tempest_h1_wpviN", n = "tempest_h2_H0B9X", r = "tempest_h3_zI9g3", i = "tempest_h4_w1Khg", a = "tempest_h5_MN-QR", o = "tempest_h6_SFcgF", s = "tempest_list_QopC7", c = "tempest_item_0veAk", l = "tempest_quote_QK3OF", u = "tempest_rule_M019c", d = "tempest_inlineCode_XsQik", f = "tempest_link_prTnN", p = "tempest_image_HjzdE", m = "tempest_tableScroll_2u5gY", h = "tempest_table_-CmP5", g = {
3
+ root: e,
4
+ h1: t,
5
+ h2: n,
6
+ h3: r,
7
+ h4: i,
8
+ h5: a,
9
+ h6: o,
10
+ list: s,
11
+ item: c,
12
+ quote: l,
13
+ rule: u,
14
+ inlineCode: d,
15
+ link: f,
16
+ image: p,
17
+ tableScroll: m,
18
+ table: h
19
+ };
20
+ //#endregion
21
+ export { g as default, t as h1, n as h2, r as h3, i as h4, a as h5, o as h6, p as image, d as inlineCode, c as item, f as link, s as list, l as quote, e as root, u as rule, h as table, m as tableScroll };
22
+
23
+ //# sourceMappingURL=Markdown.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Markdown.module.js","names":[],"sources":["../../../src/components/Markdown/Markdown.module.css"],"sourcesContent":[".root {\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-relaxed);\n overflow-wrap: anywhere;\n}\n\n/*\n * Every block spaces itself with `margin-block-end` and the last child clears it,\n * so a Markdown body dropped into a card does not add a phantom gap at the bottom.\n */\n.root > * {\n margin-block: 0 var(--tempest-space-3);\n}\n\n.root > *:last-child {\n margin-block-end: 0;\n}\n\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n margin-block-start: var(--tempest-space-5);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-tight);\n}\n\n.root > .h1:first-child,\n.root > .h2:first-child,\n.root > .h3:first-child,\n.root > .h4:first-child,\n.root > .h5:first-child,\n.root > .h6:first-child {\n margin-block-start: 0;\n}\n\n.h1 {\n font-size: var(--tempest-text-2xl);\n}\n\n.h2 {\n font-size: var(--tempest-text-xl);\n}\n\n.h3 {\n font-size: var(--tempest-text-lg);\n}\n\n.h4,\n.h5,\n.h6 {\n font-size: var(--tempest-text-base);\n}\n\n.list {\n padding-inline-start: var(--tempest-space-6);\n}\n\n.list .list {\n margin-block: var(--tempest-space-1) 0;\n}\n\n.item {\n margin-block-end: var(--tempest-space-1);\n}\n\n.item > p {\n margin: 0;\n}\n\n.quote {\n padding-inline-start: var(--tempest-space-4);\n border-inline-start: 3px solid var(--tempest-border-strong);\n color: var(--tempest-text-muted);\n}\n\n.rule {\n height: 1px;\n border: 0;\n background-color: var(--tempest-border);\n}\n\n.inlineCode {\n padding: 0.1em 0.35em;\n border-radius: var(--tempest-radius-sm);\n background-color: var(--tempest-surface-2);\n color: var(--tempest-code-text, var(--tempest-text));\n font-family: var(--tempest-font-mono);\n font-size: 0.9em;\n}\n\n.link {\n color: var(--tempest-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.image {\n max-width: 100%;\n height: auto;\n border-radius: var(--tempest-radius-md);\n}\n\n/*\n * A wide table scrolls inside its own box, and that box is focusable — a scroll\n * container with nothing focusable inside cannot be reached by keyboard, which is\n * the same defect the Table fix addressed.\n */\n.tableScroll {\n overflow-x: auto;\n}\n\n.tableScroll:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--tempest-text-sm);\n}\n\n.table th,\n.table td {\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-bottom: 1px solid var(--tempest-border);\n text-align: left;\n}\n\n.table th {\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n}\n"],"mappings":""}
@@ -0,0 +1,7 @@
1
+ const e=require("./markdown-url.cjs");var t=/^\s{0,3}(`{3,}|~{3,})\s*([\w+-]*)\s*$/,n=/^\s{0,3}(#{1,6})\s+(.*?)\s*#*\s*$/,r=/^\s{0,3}([-*_])\s*(?:\1\s*){2,}$/,i=/^\s{0,3}>\s?(.*)$/,a=/^(\s*)([-*+])\s+(.*)$/,o=/^(\s*)(\d{1,9})[.)]\s+(.*)$/,s=/^\s{0,3}\|[\s|:-]*$|^\s{0,3}:?-+:?(\s*\|\s*:?-+:?)+\s*\|?\s*$/;function c(e){return l(e.replace(/\r\n?/g,`
2
+ `).split(`
3
+ `))}function l(e){let c=[],d=0;for(;d<e.length;){let p=e[d];if(p.trim()===``){d+=1;continue}let h=t.exec(p);if(h){let t=h[1][0],n=[];for(d+=1;d<e.length&&!RegExp(`^\\s{0,3}${t}{3,}\\s*$`).test(e[d]);)n.push(e[d]),d+=1;d+=1,c.push({type:`code`,language:h[2]||null,value:n.join(`
4
+ `)});continue}let g=n.exec(p);if(g){c.push({type:`heading`,level:g[1].length,children:m(g[2])}),d+=1;continue}if(r.test(p)){c.push({type:`rule`}),d+=1;continue}if(i.test(p)){let t=[];for(;d<e.length;){let n=i.exec(e[d]);if(n){t.push(n[1]),d+=1;continue}if(e[d].trim()===``)break;t.push(e[d]),d+=1}c.push({type:`quote`,children:l(t)});continue}if(a.test(p)||o.test(p)){let[t,n]=u(e,d);c.push(t),d=n;continue}if(d+1<e.length&&p.includes(`|`)&&s.test(e[d+1])){let[t,n]=f(e,d);c.push(t),d=n;continue}let _=[];for(;d<e.length&&e[d].trim()!==``;){let s=e[d];if(n.test(s)||r.test(s)||t.test(s)||i.test(s)||a.test(s)||o.test(s))break;_.push(s.trim()),d+=1}_.length>0&&c.push({type:`paragraph`,children:m(_.join(`
5
+ `))})}return c}function u(e,t){let n=a.exec(e[t]),r=o.exec(e[t]),i=r!==null,s=((r??n)?.[1]??``).length,c=i?Number(r?.[2]??1):1,u=[],d=[],f=t,p=()=>{d.length!==0&&(u.push(l(d)),d=[])};for(;f<e.length;){let t=e[f];if(t.trim()===``){if(f+1<e.length&&e[f+1].trim()!==``){d.push(``),f+=1;continue}break}let n=a.exec(t),r=o.exec(t),c=n??r;if(c&&c[1].length<=s){if(!(i?r:n))break;p(),d.push(c[3]),f+=1;continue}if(c){d.push(t.slice(s)),f+=1;continue}if(t.search(/\S/)>s){d.push(t.trim()),f+=1;continue}break}return p(),[{type:`list`,ordered:i,start:c,items:u},f]}function d(e){let t=e.trim().replace(/^\|/,``).replace(/\|$/,``),n=[],r=``;for(let e=0;e<t.length;e+=1){if(t[e]===`\\`&&t[e+1]===`|`){r+=`|`,e+=1;continue}if(t[e]===`|`){n.push(r),r=``;continue}r+=t[e]}return n.push(r),n.map(e=>e.trim())}function f(e,t){let n=d(e[t]),r=d(e[t+1]).map(e=>{let t=e.startsWith(`:`),n=e.endsWith(`:`);return t&&n?`center`:n?`right`:t?`left`:null}),i=[],a=t+2;for(;a<e.length&&e[a].trim()!==``&&e[a].includes(`|`);)i.push(d(e[a]).map(m)),a+=1;return[{type:`table`,align:r,head:n.map(m),rows:i},a]}var p=[{pattern:/^!\[([^\]]*)\]\(((?:[^()\s]|\([^()\s]*\))+)(?:\s+"[^"]*")?\)/,build:t=>{let n=e.safeImageUrl(t[2]);return n?{type:`image`,src:n,alt:t[1]}:{type:`text`,value:t[1]}}},{pattern:/^\[([^\]]*)\]\(((?:[^()\s]|\([^()\s]*\))+)(?:\s+"[^"]*")?\)/,build:t=>{let n=e.safeLinkUrl(t[2]),r=m(t[1]);return n?{type:`link`,href:n,children:r}:{type:`text`,value:t[1]}}},{pattern:/^`([^`]+)`/,build:e=>({type:`code`,value:e[1]})},{pattern:/^\*\*([\s\S]+?)\*\*/,build:e=>({type:`strong`,children:m(e[1])})},{pattern:/^__([\s\S]+?)__/,build:e=>({type:`strong`,children:m(e[1])})},{pattern:/^~~([\s\S]+?)~~/,build:e=>({type:`del`,children:m(e[1])})},{pattern:/^\*([^*\n]+)\*/,build:e=>({type:`em`,children:m(e[1])})},{pattern:/^_([^_\n]+)_/,build:e=>({type:`em`,children:m(e[1])})},{pattern:/^<((?:https?:\/\/|mailto:)[^>\s]+)>/,build:t=>{let n=e.safeLinkUrl(t[1]);return n?{type:`link`,href:n,children:[{type:`text`,value:t[1]}]}:{type:`text`,value:t[1]}}},{pattern:/^ {2,}\n/,build:()=>({type:`break`})},{pattern:/^\\\n/,build:()=>({type:`break`})}];function m(e){let t=[],n=``,r=0,i=()=>{n&&t.push({type:`text`,value:n}),n=``};for(;r<e.length;){if(e[r]===`\\`&&r+1<e.length&&e[r+1]!==`
6
+ `){n+=e[r+1],r+=2;continue}let a=e.slice(r),o=!1;for(let e of p){let n=e.pattern.exec(a);if(!n)continue;let s=e.build(n);if(s){i(),t.push(s),r+=n[0].length,o=!0;break}}o||(n+=e[r],r+=1)}return i(),t}exports.parseInline=m,exports.parseMarkdown=c;
7
+ //# sourceMappingURL=markdown-parse.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-parse.cjs","names":[],"sources":["../../../src/components/Markdown/markdown-parse.ts"],"sourcesContent":["// A small Markdown parser for the subset an app actually renders from untrusted\n// text: comments, ticket bodies, release notes, a product description.\n//\n// It produces a node tree, never an HTML string, and the renderer turns that into\n// React elements. No `dangerouslySetInnerHTML` exists anywhere in this component —\n// which is the property that makes rendering somebody else's Markdown safe, and it\n// is structural rather than a promise about escaping.\n//\n// Raw HTML in the input is therefore not \"sanitized\", it is **text**: `<script>` in\n// a comment renders as the four characters somebody typed. That is the whole point,\n// and it is also the documented limit — this is not a CommonMark implementation and\n// does not try to be.\n\nimport { safeImageUrl, safeLinkUrl } from \"./markdown-url\";\n\n/** Inline content. */\nexport type MarkdownInline =\n | { type: \"text\"; value: string }\n | { type: \"strong\"; children: MarkdownInline[] }\n | { type: \"em\"; children: MarkdownInline[] }\n | { type: \"del\"; children: MarkdownInline[] }\n | { type: \"code\"; value: string }\n | { type: \"link\"; href: string; children: MarkdownInline[] }\n | { type: \"image\"; src: string; alt: string }\n | { type: \"break\" };\n\n/** Column alignment of a table, from the delimiter row. */\nexport type MarkdownAlign = \"left\" | \"center\" | \"right\" | null;\n\n/** Block content. */\nexport type MarkdownBlock =\n | { type: \"heading\"; level: number; children: MarkdownInline[] }\n | { type: \"paragraph\"; children: MarkdownInline[] }\n | { type: \"code\"; language: string | null; value: string }\n | { type: \"quote\"; children: MarkdownBlock[] }\n | { type: \"list\"; ordered: boolean; start: number; items: MarkdownBlock[][] }\n | {\n type: \"table\";\n align: MarkdownAlign[];\n head: MarkdownInline[][];\n rows: MarkdownInline[][][];\n }\n | { type: \"rule\" };\n\nconst FENCE = /^\\s{0,3}(`{3,}|~{3,})\\s*([\\w+-]*)\\s*$/;\nconst HEADING = /^\\s{0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/;\nconst RULE = /^\\s{0,3}([-*_])\\s*(?:\\1\\s*){2,}$/;\nconst QUOTE = /^\\s{0,3}>\\s?(.*)$/;\nconst BULLET = /^(\\s*)([-*+])\\s+(.*)$/;\nconst ORDERED = /^(\\s*)(\\d{1,9})[.)]\\s+(.*)$/;\n/**\n * A table's delimiter row.\n *\n * The `|` is required somewhere in the line, and that is what tells a one-column\n * table (`| --- |`) apart from a thematic break (`---`) — a single column is a\n * legitimate table, and the first version of this regex demanded two.\n */\nconst TABLE_DELIMITER = /^\\s{0,3}\\|[\\s|:-]*$|^\\s{0,3}:?-+:?(\\s*\\|\\s*:?-+:?)+\\s*\\|?\\s*$/;\n\n/**\n * Parse a Markdown document into blocks.\n *\n * @param source - Raw Markdown.\n * @returns Block nodes in document order.\n */\nexport function parseMarkdown(source: string): MarkdownBlock[] {\n const lines = source.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n return parseBlocks(lines);\n}\n\n/** Parse a run of lines into blocks. */\nfunction parseBlocks(lines: string[]): MarkdownBlock[] {\n const blocks: MarkdownBlock[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (line.trim() === \"\") {\n i += 1;\n continue;\n }\n\n const fence = FENCE.exec(line);\n if (fence) {\n const marker = fence[1][0];\n const body: string[] = [];\n i += 1;\n while (i < lines.length && !new RegExp(`^\\\\s{0,3}${marker}{3,}\\\\s*$`).test(lines[i])) {\n body.push(lines[i]);\n i += 1;\n }\n // An unterminated fence still yields a code block: the alternative is to\n // render the rest of the document as prose full of backticks.\n i += 1;\n blocks.push({ type: \"code\", language: fence[2] || null, value: body.join(\"\\n\") });\n continue;\n }\n\n const heading = HEADING.exec(line);\n if (heading) {\n blocks.push({\n type: \"heading\",\n level: heading[1].length,\n children: parseInline(heading[2]),\n });\n i += 1;\n continue;\n }\n\n if (RULE.test(line)) {\n blocks.push({ type: \"rule\" });\n i += 1;\n continue;\n }\n\n if (QUOTE.test(line)) {\n const inner: string[] = [];\n while (i < lines.length) {\n const match = QUOTE.exec(lines[i]);\n if (match) {\n inner.push(match[1]);\n i += 1;\n continue;\n }\n // A blank line ends the quote; a plain line continues it (lazy\n // continuation), which is how people actually write quotes.\n if (lines[i].trim() === \"\") break;\n inner.push(lines[i]);\n i += 1;\n }\n blocks.push({ type: \"quote\", children: parseBlocks(inner) });\n continue;\n }\n\n if (BULLET.test(line) || ORDERED.test(line)) {\n const [list, next] = parseList(lines, i);\n blocks.push(list);\n i = next;\n continue;\n }\n\n if (i + 1 < lines.length && line.includes(\"|\") && TABLE_DELIMITER.test(lines[i + 1])) {\n const [table, next] = parseTable(lines, i);\n blocks.push(table);\n i = next;\n continue;\n }\n\n const paragraph: string[] = [];\n while (i < lines.length && lines[i].trim() !== \"\") {\n const current = lines[i];\n if (\n HEADING.test(current) ||\n RULE.test(current) ||\n FENCE.test(current) ||\n QUOTE.test(current) ||\n BULLET.test(current) ||\n ORDERED.test(current)\n ) {\n break;\n }\n paragraph.push(current.trim());\n i += 1;\n }\n if (paragraph.length > 0) {\n blocks.push({ type: \"paragraph\", children: parseInline(paragraph.join(\"\\n\")) });\n }\n }\n\n return blocks;\n}\n\n/**\n * Parse a list, including nested lists and multi-line items.\n *\n * Nesting is decided by indentation relative to the **first** item's marker, so a\n * list indented inside a quote or another list still reads correctly.\n *\n * @returns The list node and the index of the first line after it.\n */\nfunction parseList(lines: string[], start: number): [MarkdownBlock, number] {\n const bulletStart = BULLET.exec(lines[start]);\n const orderedStart = ORDERED.exec(lines[start]);\n // The two markers are mutually exclusive — `-*+` versus digits — so whichever\n // matched decides the list kind.\n const ordered = orderedStart !== null;\n const first = orderedStart ?? bulletStart;\n const baseIndent = (first?.[1] ?? \"\").length;\n const startNumber = ordered ? Number(orderedStart?.[2] ?? 1) : 1;\n\n const items: MarkdownBlock[][] = [];\n let buffer: string[] = [];\n let i = start;\n\n const flush = (): void => {\n if (buffer.length === 0) return;\n items.push(parseBlocks(buffer));\n buffer = [];\n };\n\n while (i < lines.length) {\n const line = lines[i];\n if (line.trim() === \"\") {\n // A single blank line inside a list is a loose item, not the end. Two in\n // a row end it, which is what a blank-then-paragraph document means.\n if (i + 1 < lines.length && lines[i + 1].trim() !== \"\") {\n buffer.push(\"\");\n i += 1;\n continue;\n }\n break;\n }\n const bullet = BULLET.exec(line);\n const numbered = ORDERED.exec(line);\n const match = bullet ?? numbered;\n\n if (match && match[1].length <= baseIndent) {\n const sameKind = ordered ? Boolean(numbered) : Boolean(bullet);\n if (!sameKind) break;\n flush();\n buffer.push(match[3]);\n i += 1;\n continue;\n }\n if (match) {\n // Deeper marker: keep the indentation so the recursive call sees a list.\n buffer.push(line.slice(baseIndent));\n i += 1;\n continue;\n }\n if (line.search(/\\S/) > baseIndent) {\n buffer.push(line.trim());\n i += 1;\n continue;\n }\n break;\n }\n flush();\n\n return [{ type: \"list\", ordered, start: startNumber, items }, i];\n}\n\n/** Split a table row on unescaped pipes. */\nfunction splitRow(line: string): string[] {\n const trimmed = line.trim().replace(/^\\|/, \"\").replace(/\\|$/, \"\");\n const cells: string[] = [];\n let current = \"\";\n for (let i = 0; i < trimmed.length; i += 1) {\n if (trimmed[i] === \"\\\\\" && trimmed[i + 1] === \"|\") {\n current += \"|\";\n i += 1;\n continue;\n }\n if (trimmed[i] === \"|\") {\n cells.push(current);\n current = \"\";\n continue;\n }\n current += trimmed[i];\n }\n cells.push(current);\n return cells.map((cell) => cell.trim());\n}\n\n/**\n * Parse a GFM pipe table.\n *\n * @returns The table node and the index of the first line after it.\n */\nfunction parseTable(lines: string[], start: number): [MarkdownBlock, number] {\n const head = splitRow(lines[start]);\n const align: MarkdownAlign[] = splitRow(lines[start + 1]).map((cell) => {\n const left = cell.startsWith(\":\");\n const right = cell.endsWith(\":\");\n if (left && right) return \"center\";\n if (right) return \"right\";\n if (left) return \"left\";\n return null;\n });\n\n const rows: MarkdownInline[][][] = [];\n let i = start + 2;\n while (i < lines.length && lines[i].trim() !== \"\" && lines[i].includes(\"|\")) {\n rows.push(splitRow(lines[i]).map(parseInline));\n i += 1;\n }\n\n return [{ type: \"table\", align, head: head.map(parseInline), rows }, i];\n}\n\n/** Inline delimiters, longest marker first so `**` wins over `*`. */\nconst INLINE_RULES: Array<{\n pattern: RegExp;\n build: (match: RegExpExecArray) => MarkdownInline | null;\n}> = [\n {\n pattern: /^!\\[([^\\]]*)\\]\\(((?:[^()\\s]|\\([^()\\s]*\\))+)(?:\\s+\"[^\"]*\")?\\)/,\n build: (match) => {\n const src = safeImageUrl(match[2]);\n return src ? { type: \"image\", src, alt: match[1] } : { type: \"text\", value: match[1] };\n },\n },\n {\n pattern: /^\\[([^\\]]*)\\]\\(((?:[^()\\s]|\\([^()\\s]*\\))+)(?:\\s+\"[^\"]*\")?\\)/,\n build: (match) => {\n const href = safeLinkUrl(match[2]);\n const children = parseInline(match[1]);\n // A rejected URL keeps the label as plain text: dropping the text too\n // would silently delete words somebody wrote.\n return href ? { type: \"link\", href, children } : { type: \"text\", value: match[1] };\n },\n },\n { pattern: /^`([^`]+)`/, build: (match) => ({ type: \"code\", value: match[1] }) },\n {\n pattern: /^\\*\\*([\\s\\S]+?)\\*\\*/,\n build: (match) => ({ type: \"strong\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^__([\\s\\S]+?)__/,\n build: (match) => ({ type: \"strong\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^~~([\\s\\S]+?)~~/,\n build: (match) => ({ type: \"del\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^\\*([^*\\n]+)\\*/,\n build: (match) => ({ type: \"em\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^_([^_\\n]+)_/,\n build: (match) => ({ type: \"em\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^<((?:https?:\\/\\/|mailto:)[^>\\s]+)>/,\n build: (match) => {\n const href = safeLinkUrl(match[1]);\n return href\n ? { type: \"link\", href, children: [{ type: \"text\", value: match[1] }] }\n : { type: \"text\", value: match[1] };\n },\n },\n { pattern: /^ {2,}\\n/, build: () => ({ type: \"break\" }) },\n { pattern: /^\\\\\\n/, build: () => ({ type: \"break\" }) },\n];\n\n/**\n * Parse inline Markdown.\n *\n * A backslash escapes the next character, so `\\*not italic\\*` renders with the\n * asterisks. Anything that matches no rule is text — an unclosed `**` is two\n * asterisks, not a bold run to the end of the paragraph.\n *\n * @param source - One block's text.\n * @returns Inline nodes.\n */\nexport function parseInline(source: string): MarkdownInline[] {\n const nodes: MarkdownInline[] = [];\n let text = \"\";\n let i = 0;\n\n const flush = (): void => {\n if (text) nodes.push({ type: \"text\", value: text });\n text = \"\";\n };\n\n while (i < source.length) {\n if (source[i] === \"\\\\\" && i + 1 < source.length && source[i + 1] !== \"\\n\") {\n text += source[i + 1];\n i += 2;\n continue;\n }\n\n const rest = source.slice(i);\n let matched = false;\n for (const rule of INLINE_RULES) {\n const match = rule.pattern.exec(rest);\n if (!match) continue;\n const node = rule.build(match);\n if (!node) continue;\n flush();\n nodes.push(node);\n i += match[0].length;\n matched = true;\n break;\n }\n if (matched) continue;\n\n text += source[i];\n i += 1;\n }\n\n flush();\n return nodes;\n}\n"],"mappings":"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"}
@@ -0,0 +1,269 @@
1
+ import { safeImageUrl as e, safeLinkUrl as t } from "./markdown-url.js";
2
+ //#region src/components/Markdown/markdown-parse.ts
3
+ var n = /^\s{0,3}(`{3,}|~{3,})\s*([\w+-]*)\s*$/, r = /^\s{0,3}(#{1,6})\s+(.*?)\s*#*\s*$/, i = /^\s{0,3}([-*_])\s*(?:\1\s*){2,}$/, a = /^\s{0,3}>\s?(.*)$/, o = /^(\s*)([-*+])\s+(.*)$/, s = /^(\s*)(\d{1,9})[.)]\s+(.*)$/, c = /^\s{0,3}\|[\s|:-]*$|^\s{0,3}:?-+:?(\s*\|\s*:?-+:?)+\s*\|?\s*$/;
4
+ function l(e) {
5
+ return u(e.replace(/\r\n?/g, "\n").split("\n"));
6
+ }
7
+ function u(e) {
8
+ let t = [], l = 0;
9
+ for (; l < e.length;) {
10
+ let f = e[l];
11
+ if (f.trim() === "") {
12
+ l += 1;
13
+ continue;
14
+ }
15
+ let m = n.exec(f);
16
+ if (m) {
17
+ let n = m[1][0], r = [];
18
+ for (l += 1; l < e.length && !RegExp(`^\\s{0,3}${n}{3,}\\s*$`).test(e[l]);) r.push(e[l]), l += 1;
19
+ l += 1, t.push({
20
+ type: "code",
21
+ language: m[2] || null,
22
+ value: r.join("\n")
23
+ });
24
+ continue;
25
+ }
26
+ let g = r.exec(f);
27
+ if (g) {
28
+ t.push({
29
+ type: "heading",
30
+ level: g[1].length,
31
+ children: h(g[2])
32
+ }), l += 1;
33
+ continue;
34
+ }
35
+ if (i.test(f)) {
36
+ t.push({ type: "rule" }), l += 1;
37
+ continue;
38
+ }
39
+ if (a.test(f)) {
40
+ let n = [];
41
+ for (; l < e.length;) {
42
+ let t = a.exec(e[l]);
43
+ if (t) {
44
+ n.push(t[1]), l += 1;
45
+ continue;
46
+ }
47
+ if (e[l].trim() === "") break;
48
+ n.push(e[l]), l += 1;
49
+ }
50
+ t.push({
51
+ type: "quote",
52
+ children: u(n)
53
+ });
54
+ continue;
55
+ }
56
+ if (o.test(f) || s.test(f)) {
57
+ let [n, r] = d(e, l);
58
+ t.push(n), l = r;
59
+ continue;
60
+ }
61
+ if (l + 1 < e.length && f.includes("|") && c.test(e[l + 1])) {
62
+ let [n, r] = p(e, l);
63
+ t.push(n), l = r;
64
+ continue;
65
+ }
66
+ let _ = [];
67
+ for (; l < e.length && e[l].trim() !== "";) {
68
+ let t = e[l];
69
+ if (r.test(t) || i.test(t) || n.test(t) || a.test(t) || o.test(t) || s.test(t)) break;
70
+ _.push(t.trim()), l += 1;
71
+ }
72
+ _.length > 0 && t.push({
73
+ type: "paragraph",
74
+ children: h(_.join("\n"))
75
+ });
76
+ }
77
+ return t;
78
+ }
79
+ function d(e, t) {
80
+ let n = o.exec(e[t]), r = s.exec(e[t]), i = r !== null, a = ((r ?? n)?.[1] ?? "").length, c = i ? Number(r?.[2] ?? 1) : 1, l = [], d = [], f = t, p = () => {
81
+ d.length !== 0 && (l.push(u(d)), d = []);
82
+ };
83
+ for (; f < e.length;) {
84
+ let t = e[f];
85
+ if (t.trim() === "") {
86
+ if (f + 1 < e.length && e[f + 1].trim() !== "") {
87
+ d.push(""), f += 1;
88
+ continue;
89
+ }
90
+ break;
91
+ }
92
+ let n = o.exec(t), r = s.exec(t), c = n ?? r;
93
+ if (c && c[1].length <= a) {
94
+ if (!(i ? r : n)) break;
95
+ p(), d.push(c[3]), f += 1;
96
+ continue;
97
+ }
98
+ if (c) {
99
+ d.push(t.slice(a)), f += 1;
100
+ continue;
101
+ }
102
+ if (t.search(/\S/) > a) {
103
+ d.push(t.trim()), f += 1;
104
+ continue;
105
+ }
106
+ break;
107
+ }
108
+ return p(), [{
109
+ type: "list",
110
+ ordered: i,
111
+ start: c,
112
+ items: l
113
+ }, f];
114
+ }
115
+ function f(e) {
116
+ let t = e.trim().replace(/^\|/, "").replace(/\|$/, ""), n = [], r = "";
117
+ for (let e = 0; e < t.length; e += 1) {
118
+ if (t[e] === "\\" && t[e + 1] === "|") {
119
+ r += "|", e += 1;
120
+ continue;
121
+ }
122
+ if (t[e] === "|") {
123
+ n.push(r), r = "";
124
+ continue;
125
+ }
126
+ r += t[e];
127
+ }
128
+ return n.push(r), n.map((e) => e.trim());
129
+ }
130
+ function p(e, t) {
131
+ let n = f(e[t]), r = f(e[t + 1]).map((e) => {
132
+ let t = e.startsWith(":"), n = e.endsWith(":");
133
+ return t && n ? "center" : n ? "right" : t ? "left" : null;
134
+ }), i = [], a = t + 2;
135
+ for (; a < e.length && e[a].trim() !== "" && e[a].includes("|");) i.push(f(e[a]).map(h)), a += 1;
136
+ return [{
137
+ type: "table",
138
+ align: r,
139
+ head: n.map(h),
140
+ rows: i
141
+ }, a];
142
+ }
143
+ var m = [
144
+ {
145
+ pattern: /^!\[([^\]]*)\]\(((?:[^()\s]|\([^()\s]*\))+)(?:\s+"[^"]*")?\)/,
146
+ build: (t) => {
147
+ let n = e(t[2]);
148
+ return n ? {
149
+ type: "image",
150
+ src: n,
151
+ alt: t[1]
152
+ } : {
153
+ type: "text",
154
+ value: t[1]
155
+ };
156
+ }
157
+ },
158
+ {
159
+ pattern: /^\[([^\]]*)\]\(((?:[^()\s]|\([^()\s]*\))+)(?:\s+"[^"]*")?\)/,
160
+ build: (e) => {
161
+ let n = t(e[2]), r = h(e[1]);
162
+ return n ? {
163
+ type: "link",
164
+ href: n,
165
+ children: r
166
+ } : {
167
+ type: "text",
168
+ value: e[1]
169
+ };
170
+ }
171
+ },
172
+ {
173
+ pattern: /^`([^`]+)`/,
174
+ build: (e) => ({
175
+ type: "code",
176
+ value: e[1]
177
+ })
178
+ },
179
+ {
180
+ pattern: /^\*\*([\s\S]+?)\*\*/,
181
+ build: (e) => ({
182
+ type: "strong",
183
+ children: h(e[1])
184
+ })
185
+ },
186
+ {
187
+ pattern: /^__([\s\S]+?)__/,
188
+ build: (e) => ({
189
+ type: "strong",
190
+ children: h(e[1])
191
+ })
192
+ },
193
+ {
194
+ pattern: /^~~([\s\S]+?)~~/,
195
+ build: (e) => ({
196
+ type: "del",
197
+ children: h(e[1])
198
+ })
199
+ },
200
+ {
201
+ pattern: /^\*([^*\n]+)\*/,
202
+ build: (e) => ({
203
+ type: "em",
204
+ children: h(e[1])
205
+ })
206
+ },
207
+ {
208
+ pattern: /^_([^_\n]+)_/,
209
+ build: (e) => ({
210
+ type: "em",
211
+ children: h(e[1])
212
+ })
213
+ },
214
+ {
215
+ pattern: /^<((?:https?:\/\/|mailto:)[^>\s]+)>/,
216
+ build: (e) => {
217
+ let n = t(e[1]);
218
+ return n ? {
219
+ type: "link",
220
+ href: n,
221
+ children: [{
222
+ type: "text",
223
+ value: e[1]
224
+ }]
225
+ } : {
226
+ type: "text",
227
+ value: e[1]
228
+ };
229
+ }
230
+ },
231
+ {
232
+ pattern: /^ {2,}\n/,
233
+ build: () => ({ type: "break" })
234
+ },
235
+ {
236
+ pattern: /^\\\n/,
237
+ build: () => ({ type: "break" })
238
+ }
239
+ ];
240
+ function h(e) {
241
+ let t = [], n = "", r = 0, i = () => {
242
+ n && t.push({
243
+ type: "text",
244
+ value: n
245
+ }), n = "";
246
+ };
247
+ for (; r < e.length;) {
248
+ if (e[r] === "\\" && r + 1 < e.length && e[r + 1] !== "\n") {
249
+ n += e[r + 1], r += 2;
250
+ continue;
251
+ }
252
+ let a = e.slice(r), o = !1;
253
+ for (let e of m) {
254
+ let n = e.pattern.exec(a);
255
+ if (!n) continue;
256
+ let s = e.build(n);
257
+ if (s) {
258
+ i(), t.push(s), r += n[0].length, o = !0;
259
+ break;
260
+ }
261
+ }
262
+ o || (n += e[r], r += 1);
263
+ }
264
+ return i(), t;
265
+ }
266
+ //#endregion
267
+ export { h as parseInline, l as parseMarkdown };
268
+
269
+ //# sourceMappingURL=markdown-parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-parse.js","names":[],"sources":["../../../src/components/Markdown/markdown-parse.ts"],"sourcesContent":["// A small Markdown parser for the subset an app actually renders from untrusted\n// text: comments, ticket bodies, release notes, a product description.\n//\n// It produces a node tree, never an HTML string, and the renderer turns that into\n// React elements. No `dangerouslySetInnerHTML` exists anywhere in this component —\n// which is the property that makes rendering somebody else's Markdown safe, and it\n// is structural rather than a promise about escaping.\n//\n// Raw HTML in the input is therefore not \"sanitized\", it is **text**: `<script>` in\n// a comment renders as the four characters somebody typed. That is the whole point,\n// and it is also the documented limit — this is not a CommonMark implementation and\n// does not try to be.\n\nimport { safeImageUrl, safeLinkUrl } from \"./markdown-url\";\n\n/** Inline content. */\nexport type MarkdownInline =\n | { type: \"text\"; value: string }\n | { type: \"strong\"; children: MarkdownInline[] }\n | { type: \"em\"; children: MarkdownInline[] }\n | { type: \"del\"; children: MarkdownInline[] }\n | { type: \"code\"; value: string }\n | { type: \"link\"; href: string; children: MarkdownInline[] }\n | { type: \"image\"; src: string; alt: string }\n | { type: \"break\" };\n\n/** Column alignment of a table, from the delimiter row. */\nexport type MarkdownAlign = \"left\" | \"center\" | \"right\" | null;\n\n/** Block content. */\nexport type MarkdownBlock =\n | { type: \"heading\"; level: number; children: MarkdownInline[] }\n | { type: \"paragraph\"; children: MarkdownInline[] }\n | { type: \"code\"; language: string | null; value: string }\n | { type: \"quote\"; children: MarkdownBlock[] }\n | { type: \"list\"; ordered: boolean; start: number; items: MarkdownBlock[][] }\n | {\n type: \"table\";\n align: MarkdownAlign[];\n head: MarkdownInline[][];\n rows: MarkdownInline[][][];\n }\n | { type: \"rule\" };\n\nconst FENCE = /^\\s{0,3}(`{3,}|~{3,})\\s*([\\w+-]*)\\s*$/;\nconst HEADING = /^\\s{0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/;\nconst RULE = /^\\s{0,3}([-*_])\\s*(?:\\1\\s*){2,}$/;\nconst QUOTE = /^\\s{0,3}>\\s?(.*)$/;\nconst BULLET = /^(\\s*)([-*+])\\s+(.*)$/;\nconst ORDERED = /^(\\s*)(\\d{1,9})[.)]\\s+(.*)$/;\n/**\n * A table's delimiter row.\n *\n * The `|` is required somewhere in the line, and that is what tells a one-column\n * table (`| --- |`) apart from a thematic break (`---`) — a single column is a\n * legitimate table, and the first version of this regex demanded two.\n */\nconst TABLE_DELIMITER = /^\\s{0,3}\\|[\\s|:-]*$|^\\s{0,3}:?-+:?(\\s*\\|\\s*:?-+:?)+\\s*\\|?\\s*$/;\n\n/**\n * Parse a Markdown document into blocks.\n *\n * @param source - Raw Markdown.\n * @returns Block nodes in document order.\n */\nexport function parseMarkdown(source: string): MarkdownBlock[] {\n const lines = source.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n return parseBlocks(lines);\n}\n\n/** Parse a run of lines into blocks. */\nfunction parseBlocks(lines: string[]): MarkdownBlock[] {\n const blocks: MarkdownBlock[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (line.trim() === \"\") {\n i += 1;\n continue;\n }\n\n const fence = FENCE.exec(line);\n if (fence) {\n const marker = fence[1][0];\n const body: string[] = [];\n i += 1;\n while (i < lines.length && !new RegExp(`^\\\\s{0,3}${marker}{3,}\\\\s*$`).test(lines[i])) {\n body.push(lines[i]);\n i += 1;\n }\n // An unterminated fence still yields a code block: the alternative is to\n // render the rest of the document as prose full of backticks.\n i += 1;\n blocks.push({ type: \"code\", language: fence[2] || null, value: body.join(\"\\n\") });\n continue;\n }\n\n const heading = HEADING.exec(line);\n if (heading) {\n blocks.push({\n type: \"heading\",\n level: heading[1].length,\n children: parseInline(heading[2]),\n });\n i += 1;\n continue;\n }\n\n if (RULE.test(line)) {\n blocks.push({ type: \"rule\" });\n i += 1;\n continue;\n }\n\n if (QUOTE.test(line)) {\n const inner: string[] = [];\n while (i < lines.length) {\n const match = QUOTE.exec(lines[i]);\n if (match) {\n inner.push(match[1]);\n i += 1;\n continue;\n }\n // A blank line ends the quote; a plain line continues it (lazy\n // continuation), which is how people actually write quotes.\n if (lines[i].trim() === \"\") break;\n inner.push(lines[i]);\n i += 1;\n }\n blocks.push({ type: \"quote\", children: parseBlocks(inner) });\n continue;\n }\n\n if (BULLET.test(line) || ORDERED.test(line)) {\n const [list, next] = parseList(lines, i);\n blocks.push(list);\n i = next;\n continue;\n }\n\n if (i + 1 < lines.length && line.includes(\"|\") && TABLE_DELIMITER.test(lines[i + 1])) {\n const [table, next] = parseTable(lines, i);\n blocks.push(table);\n i = next;\n continue;\n }\n\n const paragraph: string[] = [];\n while (i < lines.length && lines[i].trim() !== \"\") {\n const current = lines[i];\n if (\n HEADING.test(current) ||\n RULE.test(current) ||\n FENCE.test(current) ||\n QUOTE.test(current) ||\n BULLET.test(current) ||\n ORDERED.test(current)\n ) {\n break;\n }\n paragraph.push(current.trim());\n i += 1;\n }\n if (paragraph.length > 0) {\n blocks.push({ type: \"paragraph\", children: parseInline(paragraph.join(\"\\n\")) });\n }\n }\n\n return blocks;\n}\n\n/**\n * Parse a list, including nested lists and multi-line items.\n *\n * Nesting is decided by indentation relative to the **first** item's marker, so a\n * list indented inside a quote or another list still reads correctly.\n *\n * @returns The list node and the index of the first line after it.\n */\nfunction parseList(lines: string[], start: number): [MarkdownBlock, number] {\n const bulletStart = BULLET.exec(lines[start]);\n const orderedStart = ORDERED.exec(lines[start]);\n // The two markers are mutually exclusive — `-*+` versus digits — so whichever\n // matched decides the list kind.\n const ordered = orderedStart !== null;\n const first = orderedStart ?? bulletStart;\n const baseIndent = (first?.[1] ?? \"\").length;\n const startNumber = ordered ? Number(orderedStart?.[2] ?? 1) : 1;\n\n const items: MarkdownBlock[][] = [];\n let buffer: string[] = [];\n let i = start;\n\n const flush = (): void => {\n if (buffer.length === 0) return;\n items.push(parseBlocks(buffer));\n buffer = [];\n };\n\n while (i < lines.length) {\n const line = lines[i];\n if (line.trim() === \"\") {\n // A single blank line inside a list is a loose item, not the end. Two in\n // a row end it, which is what a blank-then-paragraph document means.\n if (i + 1 < lines.length && lines[i + 1].trim() !== \"\") {\n buffer.push(\"\");\n i += 1;\n continue;\n }\n break;\n }\n const bullet = BULLET.exec(line);\n const numbered = ORDERED.exec(line);\n const match = bullet ?? numbered;\n\n if (match && match[1].length <= baseIndent) {\n const sameKind = ordered ? Boolean(numbered) : Boolean(bullet);\n if (!sameKind) break;\n flush();\n buffer.push(match[3]);\n i += 1;\n continue;\n }\n if (match) {\n // Deeper marker: keep the indentation so the recursive call sees a list.\n buffer.push(line.slice(baseIndent));\n i += 1;\n continue;\n }\n if (line.search(/\\S/) > baseIndent) {\n buffer.push(line.trim());\n i += 1;\n continue;\n }\n break;\n }\n flush();\n\n return [{ type: \"list\", ordered, start: startNumber, items }, i];\n}\n\n/** Split a table row on unescaped pipes. */\nfunction splitRow(line: string): string[] {\n const trimmed = line.trim().replace(/^\\|/, \"\").replace(/\\|$/, \"\");\n const cells: string[] = [];\n let current = \"\";\n for (let i = 0; i < trimmed.length; i += 1) {\n if (trimmed[i] === \"\\\\\" && trimmed[i + 1] === \"|\") {\n current += \"|\";\n i += 1;\n continue;\n }\n if (trimmed[i] === \"|\") {\n cells.push(current);\n current = \"\";\n continue;\n }\n current += trimmed[i];\n }\n cells.push(current);\n return cells.map((cell) => cell.trim());\n}\n\n/**\n * Parse a GFM pipe table.\n *\n * @returns The table node and the index of the first line after it.\n */\nfunction parseTable(lines: string[], start: number): [MarkdownBlock, number] {\n const head = splitRow(lines[start]);\n const align: MarkdownAlign[] = splitRow(lines[start + 1]).map((cell) => {\n const left = cell.startsWith(\":\");\n const right = cell.endsWith(\":\");\n if (left && right) return \"center\";\n if (right) return \"right\";\n if (left) return \"left\";\n return null;\n });\n\n const rows: MarkdownInline[][][] = [];\n let i = start + 2;\n while (i < lines.length && lines[i].trim() !== \"\" && lines[i].includes(\"|\")) {\n rows.push(splitRow(lines[i]).map(parseInline));\n i += 1;\n }\n\n return [{ type: \"table\", align, head: head.map(parseInline), rows }, i];\n}\n\n/** Inline delimiters, longest marker first so `**` wins over `*`. */\nconst INLINE_RULES: Array<{\n pattern: RegExp;\n build: (match: RegExpExecArray) => MarkdownInline | null;\n}> = [\n {\n pattern: /^!\\[([^\\]]*)\\]\\(((?:[^()\\s]|\\([^()\\s]*\\))+)(?:\\s+\"[^\"]*\")?\\)/,\n build: (match) => {\n const src = safeImageUrl(match[2]);\n return src ? { type: \"image\", src, alt: match[1] } : { type: \"text\", value: match[1] };\n },\n },\n {\n pattern: /^\\[([^\\]]*)\\]\\(((?:[^()\\s]|\\([^()\\s]*\\))+)(?:\\s+\"[^\"]*\")?\\)/,\n build: (match) => {\n const href = safeLinkUrl(match[2]);\n const children = parseInline(match[1]);\n // A rejected URL keeps the label as plain text: dropping the text too\n // would silently delete words somebody wrote.\n return href ? { type: \"link\", href, children } : { type: \"text\", value: match[1] };\n },\n },\n { pattern: /^`([^`]+)`/, build: (match) => ({ type: \"code\", value: match[1] }) },\n {\n pattern: /^\\*\\*([\\s\\S]+?)\\*\\*/,\n build: (match) => ({ type: \"strong\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^__([\\s\\S]+?)__/,\n build: (match) => ({ type: \"strong\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^~~([\\s\\S]+?)~~/,\n build: (match) => ({ type: \"del\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^\\*([^*\\n]+)\\*/,\n build: (match) => ({ type: \"em\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^_([^_\\n]+)_/,\n build: (match) => ({ type: \"em\", children: parseInline(match[1]) }),\n },\n {\n pattern: /^<((?:https?:\\/\\/|mailto:)[^>\\s]+)>/,\n build: (match) => {\n const href = safeLinkUrl(match[1]);\n return href\n ? { type: \"link\", href, children: [{ type: \"text\", value: match[1] }] }\n : { type: \"text\", value: match[1] };\n },\n },\n { pattern: /^ {2,}\\n/, build: () => ({ type: \"break\" }) },\n { pattern: /^\\\\\\n/, build: () => ({ type: \"break\" }) },\n];\n\n/**\n * Parse inline Markdown.\n *\n * A backslash escapes the next character, so `\\*not italic\\*` renders with the\n * asterisks. Anything that matches no rule is text — an unclosed `**` is two\n * asterisks, not a bold run to the end of the paragraph.\n *\n * @param source - One block's text.\n * @returns Inline nodes.\n */\nexport function parseInline(source: string): MarkdownInline[] {\n const nodes: MarkdownInline[] = [];\n let text = \"\";\n let i = 0;\n\n const flush = (): void => {\n if (text) nodes.push({ type: \"text\", value: text });\n text = \"\";\n };\n\n while (i < source.length) {\n if (source[i] === \"\\\\\" && i + 1 < source.length && source[i + 1] !== \"\\n\") {\n text += source[i + 1];\n i += 2;\n continue;\n }\n\n const rest = source.slice(i);\n let matched = false;\n for (const rule of INLINE_RULES) {\n const match = rule.pattern.exec(rest);\n if (!match) continue;\n const node = rule.build(match);\n if (!node) continue;\n flush();\n nodes.push(node);\n i += match[0].length;\n matched = true;\n break;\n }\n if (matched) continue;\n\n text += source[i];\n i += 1;\n }\n\n flush();\n return nodes;\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ var e=new Set([`http:`,`https:`,`mailto:`,`tel:`,`sms:`]),t=/^data:image\/(png|jpe?g|gif|webp|avif|bmp);base64,[a-z0-9+/=\s]+$/i;function n(e){return e.replace(/[\u0000-\u0020\u007F]/g,``).trim()}function r(t){let r=n(t);if(!r)return null;if(/^[a-z][a-z0-9+.-]*:/i.test(r)){let t=r.slice(0,r.indexOf(`:`)+1).toLowerCase();return e.has(t)?r:null}return r}function i(e){let i=n(e);return i?t.test(i)?i:/^data:/i.test(i)?null:r(i):null}exports.safeImageUrl=i,exports.safeLinkUrl=r;
2
+ //# sourceMappingURL=markdown-url.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-url.cjs","names":[],"sources":["../../../src/components/Markdown/markdown-url.ts"],"sourcesContent":["/**\n * URL vetting for links and images in rendered Markdown.\n *\n * This is the security boundary of the whole component. Markdown that arrives from\n * a user — a comment, a ticket description, a review — reaches the DOM as a real\n * `href`, and `javascript:alert(1)` in a link is script execution on click. So the\n * scheme is checked against an allowlist rather than a blocklist: a blocklist has\n * to enumerate `javascript:`, `JaVaScRiPt:`, `java\\tscript:`, `&#106;avascript:`\n * and whatever comes next, and misses the one nobody thought of.\n */\n\n/** Schemes a link may use. Anything else is dropped. */\nconst LINK_SCHEMES = new Set([\"http:\", \"https:\", \"mailto:\", \"tel:\", \"sms:\"]);\n\n/**\n * Image `data:` types that are safe to inline.\n *\n * `svg+xml` is deliberately absent: an SVG is a document, it can carry `<script>`\n * and event handlers, and browsers execute them when it loads from a `data:` URL in\n * some contexts. The raster formats cannot carry code.\n */\nconst IMAGE_DATA_TYPES = /^data:image\\/(png|jpe?g|gif|webp|avif|bmp);base64,[a-z0-9+/=\\s]+$/i;\n\n/**\n * Strip the characters a scheme can be smuggled through.\n *\n * `java\\tscript:` and `java\\nscript:` are both parsed as `javascript:` by browsers,\n * and a leading control character defeats a naive `startsWith` check.\n */\nfunction normalize(raw: string): string {\n // eslint-disable-next-line no-control-regex -- stripping control characters is the point\n return raw.replace(/[\\u0000-\\u0020\\u007F]/g, \"\").trim();\n}\n\n/**\n * The href to render, or `null` when the URL must not be linked.\n *\n * Relative URLs (`/docs`, `./x`, `#anchor`, `foo/bar`) are kept: they cannot carry\n * a scheme, so they cannot execute anything, and dropping them would break every\n * in-app link.\n *\n * @param raw - URL as written in the Markdown.\n * @returns A safe href, or `null`.\n */\nexport function safeLinkUrl(raw: string): string | null {\n const url = normalize(raw);\n if (!url) return null;\n if (/^[a-z][a-z0-9+.-]*:/i.test(url)) {\n const scheme = url.slice(0, url.indexOf(\":\") + 1).toLowerCase();\n return LINK_SCHEMES.has(scheme) ? url : null;\n }\n // Protocol-relative (`//host/path`) inherits the page scheme — safe, and real.\n return url;\n}\n\n/**\n * The `src` to render for an image, or `null`.\n *\n * @param raw - URL as written in the Markdown.\n * @returns A safe src, or `null`.\n */\nexport function safeImageUrl(raw: string): string | null {\n const url = normalize(raw);\n if (!url) return null;\n if (IMAGE_DATA_TYPES.test(url)) return url;\n if (/^data:/i.test(url)) return null;\n return safeLinkUrl(url);\n}\n"],"mappings":"AAYA,IAAM,EAAe,IAAI,IAAI,CAAC,QAAS,SAAU,UAAW,OAAQ,MAAM,CAAC,EASrE,EAAmB,qEAQzB,SAAS,EAAU,EAAqB,CAEpC,OAAO,EAAI,QAAQ,yBAA0B,EAAE,CAAC,CAAC,KAAK,CAC1D,CAYA,SAAgB,EAAY,EAA4B,CACpD,IAAM,EAAM,EAAU,CAAG,EACzB,GAAI,CAAC,EAAK,OAAO,KACjB,GAAI,uBAAuB,KAAK,CAAG,EAAG,CAClC,IAAM,EAAS,EAAI,MAAM,EAAG,EAAI,QAAQ,GAAG,EAAI,CAAC,CAAC,CAAC,YAAY,EAC9D,OAAO,EAAa,IAAI,CAAM,EAAI,EAAM,IAC5C,CAEA,OAAO,CACX,CAQA,SAAgB,EAAa,EAA4B,CACrD,IAAM,EAAM,EAAU,CAAG,EAIzB,OAHK,EACD,EAAiB,KAAK,CAAG,EAAU,EACnC,UAAU,KAAK,CAAG,EAAU,KACzB,EAAY,CAAG,EAHL,IAIrB"}
@@ -0,0 +1,28 @@
1
+ //#region src/components/Markdown/markdown-url.ts
2
+ var e = /* @__PURE__ */ new Set([
3
+ "http:",
4
+ "https:",
5
+ "mailto:",
6
+ "tel:",
7
+ "sms:"
8
+ ]), t = /^data:image\/(png|jpe?g|gif|webp|avif|bmp);base64,[a-z0-9+/=\s]+$/i;
9
+ function n(e) {
10
+ return e.replace(/[\u0000-\u0020\u007F]/g, "").trim();
11
+ }
12
+ function r(t) {
13
+ let r = n(t);
14
+ if (!r) return null;
15
+ if (/^[a-z][a-z0-9+.-]*:/i.test(r)) {
16
+ let t = r.slice(0, r.indexOf(":") + 1).toLowerCase();
17
+ return e.has(t) ? r : null;
18
+ }
19
+ return r;
20
+ }
21
+ function i(e) {
22
+ let i = n(e);
23
+ return i ? t.test(i) ? i : /^data:/i.test(i) ? null : r(i) : null;
24
+ }
25
+ //#endregion
26
+ export { i as safeImageUrl, r as safeLinkUrl };
27
+
28
+ //# sourceMappingURL=markdown-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-url.js","names":[],"sources":["../../../src/components/Markdown/markdown-url.ts"],"sourcesContent":["/**\n * URL vetting for links and images in rendered Markdown.\n *\n * This is the security boundary of the whole component. Markdown that arrives from\n * a user — a comment, a ticket description, a review — reaches the DOM as a real\n * `href`, and `javascript:alert(1)` in a link is script execution on click. So the\n * scheme is checked against an allowlist rather than a blocklist: a blocklist has\n * to enumerate `javascript:`, `JaVaScRiPt:`, `java\\tscript:`, `&#106;avascript:`\n * and whatever comes next, and misses the one nobody thought of.\n */\n\n/** Schemes a link may use. Anything else is dropped. */\nconst LINK_SCHEMES = new Set([\"http:\", \"https:\", \"mailto:\", \"tel:\", \"sms:\"]);\n\n/**\n * Image `data:` types that are safe to inline.\n *\n * `svg+xml` is deliberately absent: an SVG is a document, it can carry `<script>`\n * and event handlers, and browsers execute them when it loads from a `data:` URL in\n * some contexts. The raster formats cannot carry code.\n */\nconst IMAGE_DATA_TYPES = /^data:image\\/(png|jpe?g|gif|webp|avif|bmp);base64,[a-z0-9+/=\\s]+$/i;\n\n/**\n * Strip the characters a scheme can be smuggled through.\n *\n * `java\\tscript:` and `java\\nscript:` are both parsed as `javascript:` by browsers,\n * and a leading control character defeats a naive `startsWith` check.\n */\nfunction normalize(raw: string): string {\n // eslint-disable-next-line no-control-regex -- stripping control characters is the point\n return raw.replace(/[\\u0000-\\u0020\\u007F]/g, \"\").trim();\n}\n\n/**\n * The href to render, or `null` when the URL must not be linked.\n *\n * Relative URLs (`/docs`, `./x`, `#anchor`, `foo/bar`) are kept: they cannot carry\n * a scheme, so they cannot execute anything, and dropping them would break every\n * in-app link.\n *\n * @param raw - URL as written in the Markdown.\n * @returns A safe href, or `null`.\n */\nexport function safeLinkUrl(raw: string): string | null {\n const url = normalize(raw);\n if (!url) return null;\n if (/^[a-z][a-z0-9+.-]*:/i.test(url)) {\n const scheme = url.slice(0, url.indexOf(\":\") + 1).toLowerCase();\n return LINK_SCHEMES.has(scheme) ? url : null;\n }\n // Protocol-relative (`//host/path`) inherits the page scheme — safe, and real.\n return url;\n}\n\n/**\n * The `src` to render for an image, or `null`.\n *\n * @param raw - URL as written in the Markdown.\n * @returns A safe src, or `null`.\n */\nexport function safeImageUrl(raw: string): string | null {\n const url = normalize(raw);\n if (!url) return null;\n if (IMAGE_DATA_TYPES.test(url)) return url;\n if (/^data:/i.test(url)) return null;\n return safeLinkUrl(url);\n}\n"],"mappings":";AAYA,IAAM,oBAAe,IAAI,IAAI;CAAC;CAAS;CAAU;CAAW;CAAQ;AAAM,CAAC,GASrE,IAAmB;AAQzB,SAAS,EAAU,GAAqB;CAEpC,OAAO,EAAI,QAAQ,0BAA0B,EAAE,CAAC,CAAC,KAAK;AAC1D;AAYA,SAAgB,EAAY,GAA4B;CACpD,IAAM,IAAM,EAAU,CAAG;CACzB,IAAI,CAAC,GAAK,OAAO;CACjB,IAAI,uBAAuB,KAAK,CAAG,GAAG;EAClC,IAAM,IAAS,EAAI,MAAM,GAAG,EAAI,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,YAAY;EAC9D,OAAO,EAAa,IAAI,CAAM,IAAI,IAAM;CAC5C;CAEA,OAAO;AACX;AAQA,SAAgB,EAAa,GAA4B;CACrD,IAAM,IAAM,EAAU,CAAG;CAIzB,OAHK,IACD,EAAiB,KAAK,CAAG,IAAU,IACnC,UAAU,KAAK,CAAG,IAAU,OACzB,EAAY,CAAG,IAHL;AAIrB"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../utils/cn.cjs"),t=require("./masonry-layout.cjs"),n=require("./Masonry.module.cjs");let r=require("react"),i=require("react/jsx-runtime");var a={0:1,640:2,1024:3};function o({items:o,children:s,itemKey:c,columns:l=a,gap:u,className:d,style:f,...p}){let m=(0,r.useRef)(null),h=(0,r.useRef)(new Map),[g,_]=(0,r.useState)(0),[v,y]=(0,r.useState)([]),b=t.columnsFor(g,l);(0,r.useEffect)(()=>{let e=m.current;if(!e||typeof ResizeObserver>`u`)return;let t=new ResizeObserver(([e])=>{_(e.contentRect.width)});return t.observe(e),_(e.getBoundingClientRect().width),()=>t.disconnect()},[]);let x=(0,r.useCallback)(()=>{let e=o.map((e,t)=>{let n=h.current.get(t);return n?n.getBoundingClientRect().height:1});y(t=>t.length===e.length&&t.every((t,n)=>t===e[n])?t:e)},[o]);(0,r.useLayoutEffect)(x,[x,b,g]),(0,r.useEffect)(()=>{if(typeof ResizeObserver>`u`)return;let e=new ResizeObserver(x);for(let t of h.current.values())e.observe(t);return()=>e.disconnect()},[x,b]);let S=(0,r.useMemo)(()=>t.distribute(o.map((e,t)=>v[t]??1),b),[o,v,b]);return(0,i.jsx)(`div`,{ref:m,className:e.cn(n.default.wrapper,d),style:{...f,...u?{"--tempest-masonry-gap":u}:{}},...p,children:S.map((e,t)=>(0,i.jsx)(`div`,{className:n.default.column,children:e.map(e=>{let t=o[e];return(0,i.jsx)(`div`,{className:n.default.item,ref:t=>{t?h.current.set(e,t):h.current.delete(e)},children:s(t,e)},c?c(t,e):e)})},t))})}exports.Masonry=o;
2
+ //# sourceMappingURL=Masonry.cjs.map