@juspay/svelte-ui-components 4.4.0 → 4.6.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/KeyboardInput/KeyboardInput.svelte +11 -1
- package/dist/KeyboardInput/properties.d.ts +9 -0
- package/dist/MarkdownText/MarkdownText.svelte +10 -3
- package/dist/MarkdownText/markdown.js +133 -19
- package/dist/MarkdownText/properties.d.ts +53 -0
- package/dist-wc/index.js +123 -42
- package/package.json +1 -1
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { KeyboardInputProperties } from './properties';
|
|
3
3
|
|
|
4
|
-
let {
|
|
4
|
+
let {
|
|
5
|
+
keys,
|
|
6
|
+
separator = '+',
|
|
7
|
+
testId,
|
|
8
|
+
onclick,
|
|
9
|
+
classes,
|
|
10
|
+
literal = false
|
|
11
|
+
}: KeyboardInputProperties = $props();
|
|
5
12
|
|
|
6
13
|
const KEY_SYMBOLS: Record<string, string> = {
|
|
7
14
|
cmd: '\u2318',
|
|
@@ -28,6 +35,9 @@
|
|
|
28
35
|
let interactive = $derived(typeof onclick === 'function');
|
|
29
36
|
|
|
30
37
|
function getSymbol(key: string): string {
|
|
38
|
+
if (literal) {
|
|
39
|
+
return key;
|
|
40
|
+
}
|
|
31
41
|
return KEY_SYMBOLS[key.toLowerCase()] ?? key;
|
|
32
42
|
}
|
|
33
43
|
|
|
@@ -6,6 +6,15 @@ export type OptionalKeyboardInputProperties = {
|
|
|
6
6
|
separator?: string;
|
|
7
7
|
testId?: string;
|
|
8
8
|
classes?: string;
|
|
9
|
+
/**
|
|
10
|
+
* When true, every key renders exactly as given — the built-in KEY_SYMBOLS
|
|
11
|
+
* table (`space` → ␣, `tab` → ⇥, `cmd` → ⌘, …) is bypassed entirely.
|
|
12
|
+
* Defaults to false, so existing consumers keep today's glyph substitution
|
|
13
|
+
* unchanged. Use this when the word itself is the label that must appear
|
|
14
|
+
* (e.g. a "Hold SPACE" caption or a physical-key caption reading "Tab"),
|
|
15
|
+
* not the typographic symbol.
|
|
16
|
+
*/
|
|
17
|
+
literal?: boolean;
|
|
9
18
|
};
|
|
10
19
|
export type KeyboardInputEventProperties = {
|
|
11
20
|
onclick?: (event: MouseEvent) => void;
|
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
import { renderMarkdown } from './markdown';
|
|
3
3
|
import type { MarkdownTextProperties } from './properties';
|
|
4
4
|
|
|
5
|
-
let {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
let {
|
|
6
|
+
markdown,
|
|
7
|
+
breaks = false,
|
|
8
|
+
testId,
|
|
9
|
+
classes,
|
|
10
|
+
tableLabel,
|
|
11
|
+
sanitize
|
|
12
|
+
}: MarkdownTextProperties = $props();
|
|
13
|
+
|
|
14
|
+
let html = $derived(renderMarkdown(markdown, { breaks, tableLabel, sanitize }));
|
|
8
15
|
</script>
|
|
9
16
|
|
|
10
17
|
<div
|
|
@@ -55,26 +55,127 @@ function escapeHtml(value) {
|
|
|
55
55
|
.replace(/"/g, '"')
|
|
56
56
|
.replace(/'/g, ''');
|
|
57
57
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (hasSafeProtocol(token.href, SAFE_IMAGE_PROTOCOLS)) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
return escapeHtml(token.text);
|
|
58
|
+
/**
|
|
59
|
+
* `allowedProtocols` can only NARROW a surface's default allow-list, never
|
|
60
|
+
* widen it -- intersecting with the library default (rather than substituting
|
|
61
|
+
* it) is what makes listing an unsafe scheme like `javascript:` a no-op
|
|
62
|
+
* instead of a hole. Casing is normalised so `'HTTPS:'` narrows the same as
|
|
63
|
+
* `'https:'`, matching how `hasSafeProtocol` reads `URL.protocol` (always
|
|
64
|
+
* lower-case).
|
|
65
|
+
*/
|
|
66
|
+
function narrow(defaults, allowedProtocols) {
|
|
67
|
+
if (!allowedProtocols) {
|
|
68
|
+
return defaults;
|
|
73
69
|
}
|
|
74
|
-
|
|
70
|
+
const requested = new Set(allowedProtocols.map((protocol) => protocol.toLowerCase()));
|
|
71
|
+
return new Set([...defaults].filter((protocol) => requested.has(protocol)));
|
|
72
|
+
}
|
|
73
|
+
function resolveProtocolSets(sanitize) {
|
|
74
|
+
return {
|
|
75
|
+
links: narrow(SAFE_LINK_PROTOCOLS, sanitize?.allowedProtocols),
|
|
76
|
+
images: narrow(SAFE_IMAGE_PROTOCOLS, sanitize?.allowedProtocols)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* `null` means "no restriction" (today's default: every tag marked's GFM
|
|
81
|
+
* output can produce renders normally) -- unlike the protocol allow-lists,
|
|
82
|
+
* there is no built-in default set to fall back to once this exists, so its
|
|
83
|
+
* absence is what keeps old behaviour byte-for-byte.
|
|
84
|
+
*/
|
|
85
|
+
function resolveTagAllowList(allowedTags) {
|
|
86
|
+
return allowedTags ? new Set(allowedTags) : null;
|
|
87
|
+
}
|
|
88
|
+
function tagAllowed(allowed, tag) {
|
|
89
|
+
return allowed === null || allowed.has(tag);
|
|
90
|
+
}
|
|
91
|
+
function createSanitizingRenderer(protocols, allowedTags, disableTaskLists) {
|
|
92
|
+
return {
|
|
93
|
+
html(token) {
|
|
94
|
+
return escapeHtml(token.text);
|
|
95
|
+
},
|
|
96
|
+
link(token) {
|
|
97
|
+
if (hasSafeProtocol(token.href, protocols.links) && tagAllowed(allowedTags, 'a')) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return escapeHtml(token.text);
|
|
101
|
+
},
|
|
102
|
+
image(token) {
|
|
103
|
+
if (hasSafeProtocol(token.href, protocols.images) && tagAllowed(allowedTags, 'img')) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return escapeHtml(token.text);
|
|
107
|
+
},
|
|
108
|
+
strong(token) {
|
|
109
|
+
if (tagAllowed(allowedTags, 'strong')) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
return this.parser.parseInline(token.tokens);
|
|
113
|
+
},
|
|
114
|
+
em(token) {
|
|
115
|
+
if (tagAllowed(allowedTags, 'em')) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return this.parser.parseInline(token.tokens);
|
|
119
|
+
},
|
|
120
|
+
del(token) {
|
|
121
|
+
if (tagAllowed(allowedTags, 'del')) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
return this.parser.parseInline(token.tokens);
|
|
125
|
+
},
|
|
126
|
+
codespan(token) {
|
|
127
|
+
if (tagAllowed(allowedTags, 'code')) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
return escapeHtml(token.text);
|
|
131
|
+
},
|
|
132
|
+
code(token) {
|
|
133
|
+
if (tagAllowed(allowedTags, 'pre')) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
return `${escapeHtml(token.text)}\n`;
|
|
137
|
+
},
|
|
138
|
+
blockquote(token) {
|
|
139
|
+
if (tagAllowed(allowedTags, 'blockquote')) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
return this.parser.parse(token.tokens);
|
|
143
|
+
},
|
|
144
|
+
heading(token) {
|
|
145
|
+
if (tagAllowed(allowedTags, `h${token.depth}`)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
return `${this.parser.parseInline(token.tokens)}\n`;
|
|
149
|
+
},
|
|
150
|
+
list(token) {
|
|
151
|
+
if (tagAllowed(allowedTags, token.ordered ? 'ol' : 'ul')) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
return token.items.map((item) => this.parser.parse(item.tokens)).join('');
|
|
155
|
+
},
|
|
156
|
+
table(token) {
|
|
157
|
+
if (tagAllowed(allowedTags, 'table')) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
const rowText = (cells) => cells.map((cell) => this.parser.parseInline(cell.tokens)).join(' | ');
|
|
161
|
+
const lines = [rowText(token.header), ...token.rows.map(rowText)];
|
|
162
|
+
return `<p>${lines.join('<br>')}</p>`;
|
|
163
|
+
},
|
|
164
|
+
hr() {
|
|
165
|
+
return tagAllowed(allowedTags, 'hr') ? false : '';
|
|
166
|
+
},
|
|
167
|
+
checkbox() {
|
|
168
|
+
return disableTaskLists ? '' : false;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
75
172
|
/* Safe to share across SSR requests: each instance's configuration (renderer,
|
|
76
173
|
gfm, breaks) is fixed at construction and parse() takes no per-request state,
|
|
77
|
-
so the cache only ever holds config-immutable parsers keyed by option shape.
|
|
174
|
+
so the cache only ever holds config-immutable parsers keyed by option shape.
|
|
175
|
+
The key folds in the resolved protocol sets, tag allow-list and task-list
|
|
176
|
+
toggle (sorted for a stable string) so differently-configured `sanitize`
|
|
177
|
+
options get their own cached instance and never share a renderer with a
|
|
178
|
+
different allow-list. */
|
|
78
179
|
const instances = new Map();
|
|
79
180
|
/* External links open in a new tab with `rel="noopener noreferrer"` — the same
|
|
80
181
|
default the library's Button/Card apply to `target="_blank"` anchors. The
|
|
@@ -108,10 +209,23 @@ function wrapTables(html, label) {
|
|
|
108
209
|
}
|
|
109
210
|
function instanceFor(options) {
|
|
110
211
|
const breaks = options.breaks === true;
|
|
111
|
-
const
|
|
212
|
+
const protocols = resolveProtocolSets(options.sanitize);
|
|
213
|
+
const allowedTags = resolveTagAllowList(options.sanitize?.allowedTags);
|
|
214
|
+
const disableTaskLists = options.sanitize?.disableTaskLists === true;
|
|
215
|
+
const key = [
|
|
216
|
+
breaks ? 'breaks' : 'default',
|
|
217
|
+
[...protocols.links].sort().join(','),
|
|
218
|
+
[...protocols.images].sort().join(','),
|
|
219
|
+
allowedTags ? [...allowedTags].sort().join(',') : '*',
|
|
220
|
+
disableTaskLists ? 'no-tasks' : 'tasks'
|
|
221
|
+
].join('|');
|
|
112
222
|
let instance = instances.get(key);
|
|
113
223
|
if (!instance) {
|
|
114
|
-
instance = new Marked({
|
|
224
|
+
instance = new Marked({
|
|
225
|
+
gfm: true,
|
|
226
|
+
breaks,
|
|
227
|
+
renderer: createSanitizingRenderer(protocols, allowedTags, disableTaskLists)
|
|
228
|
+
});
|
|
115
229
|
instances.set(key, instance);
|
|
116
230
|
}
|
|
117
231
|
return instance;
|
|
@@ -20,6 +20,57 @@ export type OptionalMarkdownTextProperties = {
|
|
|
20
20
|
* worse than none.
|
|
21
21
|
*/
|
|
22
22
|
tableLabel?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Narrow which URL protocols survive on rendered links/images. See
|
|
25
|
+
* `MarkdownSanitizeOptions`.
|
|
26
|
+
*/
|
|
27
|
+
sanitize?: MarkdownSanitizeOptions;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* A consumer's own link policy can be stricter than the library default
|
|
31
|
+
* (`http:`/`https:`/`mailto:`/`tel:` for links, `http:`/`https:` for images) —
|
|
32
|
+
* for example, no live `mailto:`/`tel:` in a chat surface. `allowedProtocols`
|
|
33
|
+
* lets a caller restrict which of those defaults survive; it is intersected
|
|
34
|
+
* with the library's own allow-list for each surface, so it can only NARROW
|
|
35
|
+
* what already renders, never widen it (listing `javascript:` here can never
|
|
36
|
+
* resurrect it). Omitting `sanitize`, or `allowedProtocols`, keeps today's
|
|
37
|
+
* defaults untouched. This is independent of the "raw HTML is always escaped"
|
|
38
|
+
* guarantee, which has no opt-out.
|
|
39
|
+
*/
|
|
40
|
+
export type MarkdownSanitizeOptions = {
|
|
41
|
+
/**
|
|
42
|
+
* Protocols (e.g. `'https:'`, `'mailto:'`) allowed to survive on rendered
|
|
43
|
+
* links and images, intersected with the library's own default allow-list
|
|
44
|
+
* for each surface. An empty array drops every link and image, keeping
|
|
45
|
+
* their text.
|
|
46
|
+
*/
|
|
47
|
+
allowedProtocols?: string[];
|
|
48
|
+
/**
|
|
49
|
+
* Narrows which markdown-GENERATED tags are allowed to render as
|
|
50
|
+
* themselves. Unlike `allowedProtocols` there is no pre-set default list to
|
|
51
|
+
* intersect with — every tag `marked`'s own GFM output can produce renders
|
|
52
|
+
* normally until this is supplied, so passing it narrows from "everything"
|
|
53
|
+
* rather than from a built-in allow-list. A disallowed tag renders its
|
|
54
|
+
* parsed inner content as plain markup-free text instead of the element —
|
|
55
|
+
* the same "keep the text, drop the element" contract `allowedProtocols`
|
|
56
|
+
* uses for an unsafe link/image. Recognised names: `'a'`, `'img'`,
|
|
57
|
+
* `'strong'`, `'em'`, `'del'`, `'code'` (inline), `'pre'` (code block),
|
|
58
|
+
* `'blockquote'`, `'ul'`, `'ol'`, `'table'`, `'hr'`, and `'h1'`–`'h6'`. An
|
|
59
|
+
* unrecognised name is simply ignored — it narrows nothing, it does not
|
|
60
|
+
* error. Omitting `allowedTags` keeps today's defaults untouched: every tag
|
|
61
|
+
* renders as it does now. This is independent of the "raw HTML is always
|
|
62
|
+
* escaped" guarantee, which has no opt-out and is never affected by this
|
|
63
|
+
* list.
|
|
64
|
+
*/
|
|
65
|
+
allowedTags?: string[];
|
|
66
|
+
/**
|
|
67
|
+
* Render GFM task-list items (`- [ ] done`) as plain list text instead of
|
|
68
|
+
* an `<input type="checkbox">`. The checkbox already renders `disabled` by
|
|
69
|
+
* default (it never submits or toggles), so this is a presentation choice
|
|
70
|
+
* for surfaces that would rather not show checkbox glyphs at all, not a
|
|
71
|
+
* safety one. Defaults to `false`, keeping today's checkbox rendering.
|
|
72
|
+
*/
|
|
73
|
+
disableTaskLists?: boolean;
|
|
23
74
|
};
|
|
24
75
|
export type RenderMarkdownOptions = {
|
|
25
76
|
/** Render single newlines as `<br>` (GFM "breaks" mode). */
|
|
@@ -33,4 +84,6 @@ export type RenderMarkdownOptions = {
|
|
|
33
84
|
inline?: boolean;
|
|
34
85
|
/** Accessible name for the scroll region wrapping each table. See `MarkdownTextProperties.tableLabel`. */
|
|
35
86
|
tableLabel?: string;
|
|
87
|
+
/** Narrow the protocol allow-list. See `MarkdownSanitizeOptions`. */
|
|
88
|
+
sanitize?: MarkdownSanitizeOptions;
|
|
36
89
|
};
|
package/dist-wc/index.js
CHANGED
|
@@ -9834,7 +9834,7 @@ var root$64 = /* @__PURE__ */ from_html("<span class=\"separator svelte-14lwsom\
|
|
|
9834
9834
|
};
|
|
9835
9835
|
function KeyboardInput(e, t) {
|
|
9836
9836
|
push(t, !0), append_styles$1(e, $$css$63);
|
|
9837
|
-
let n = prop(t, "keys", 7), i = prop(t, "separator", 7, "+"), a = prop(t, "testId", 7), o = prop(t, "onclick", 7), s = prop(t, "classes", 7), c = {
|
|
9837
|
+
let n = prop(t, "keys", 7), i = prop(t, "separator", 7, "+"), a = prop(t, "testId", 7), o = prop(t, "onclick", 7), s = prop(t, "classes", 7), c = prop(t, "literal", 7, !1), l = {
|
|
9838
9838
|
cmd: "⌘",
|
|
9839
9839
|
command: "⌘",
|
|
9840
9840
|
ctrl: "⌃",
|
|
@@ -9853,14 +9853,14 @@ function KeyboardInput(e, t) {
|
|
|
9853
9853
|
left: "←",
|
|
9854
9854
|
right: "→",
|
|
9855
9855
|
space: "␣"
|
|
9856
|
-
},
|
|
9857
|
-
function f(e) {
|
|
9858
|
-
return c[e.toLowerCase()] ?? e;
|
|
9859
|
-
}
|
|
9856
|
+
}, u = /* @__PURE__ */ user_derived(() => Array.isArray(n()) ? n() : n().split(i()).map((e) => e.trim())), f = /* @__PURE__ */ user_derived(() => typeof o() == "function");
|
|
9860
9857
|
function p(e) {
|
|
9858
|
+
return c() ? e : l[e.toLowerCase()] ?? e;
|
|
9859
|
+
}
|
|
9860
|
+
function h(e) {
|
|
9861
9861
|
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), o()?.(new MouseEvent("click")));
|
|
9862
9862
|
}
|
|
9863
|
-
var
|
|
9863
|
+
var S = {
|
|
9864
9864
|
get keys() {
|
|
9865
9865
|
return n();
|
|
9866
9866
|
},
|
|
@@ -9890,9 +9890,15 @@ function KeyboardInput(e, t) {
|
|
|
9890
9890
|
},
|
|
9891
9891
|
set classes(e) {
|
|
9892
9892
|
s(e), flushSync();
|
|
9893
|
+
},
|
|
9894
|
+
get literal() {
|
|
9895
|
+
return c();
|
|
9896
|
+
},
|
|
9897
|
+
set literal(e = !1) {
|
|
9898
|
+
c(e), flushSync();
|
|
9893
9899
|
}
|
|
9894
|
-
},
|
|
9895
|
-
return each(
|
|
9900
|
+
}, C = root_2$41();
|
|
9901
|
+
return each(C, 21, () => get(u), index, (e, t, n) => {
|
|
9896
9902
|
var a = root_1$53(), o = first_child(a), s = (e) => {
|
|
9897
9903
|
var t = root$64(), n = child(t, !0);
|
|
9898
9904
|
reset(t), template_effect(() => set_text(n, i())), append(e, t);
|
|
@@ -9901,21 +9907,22 @@ function KeyboardInput(e, t) {
|
|
|
9901
9907
|
n > 0 && e(s);
|
|
9902
9908
|
});
|
|
9903
9909
|
var c = sibling(o, 2), l = child(c, !0);
|
|
9904
|
-
reset(c), template_effect((e) => set_text(l, e), [() =>
|
|
9905
|
-
}), reset(
|
|
9906
|
-
set_class(
|
|
9907
|
-
}), delegated("click",
|
|
9908
|
-
(get(
|
|
9909
|
-
}), delegated("keydown",
|
|
9910
|
-
(get(
|
|
9911
|
-
}), append(e,
|
|
9910
|
+
reset(c), template_effect((e) => set_text(l, e), [() => p(get(t))]), append(e, a);
|
|
9911
|
+
}), reset(C), template_effect(() => {
|
|
9912
|
+
set_class(C, 1, `keyboard-input ${s() ?? "" ?? ""}`, "svelte-14lwsom"), set_attribute(C, "data-pw", typeof a() == "string" ? a() : null), set_attribute(C, "testid", typeof a() == "string" ? a() : null), set_attribute(C, "role", get(f) ? "button" : null), set_attribute(C, "tabindex", get(f) ? 0 : null);
|
|
9913
|
+
}), delegated("click", C, function(...e) {
|
|
9914
|
+
(get(f) ? o() : null)?.apply(this, e);
|
|
9915
|
+
}), delegated("keydown", C, function(...e) {
|
|
9916
|
+
(get(f) ? h : null)?.apply(this, e);
|
|
9917
|
+
}), append(e, C), pop(S);
|
|
9912
9918
|
}
|
|
9913
9919
|
delegate(["click", "keydown"]), create_custom_element(KeyboardInput, {
|
|
9914
9920
|
keys: {},
|
|
9915
9921
|
separator: {},
|
|
9916
9922
|
testId: {},
|
|
9917
9923
|
onclick: {},
|
|
9918
|
-
classes: {}
|
|
9924
|
+
classes: {},
|
|
9925
|
+
literal: {}
|
|
9919
9926
|
}, [], [], { mode: "open" });
|
|
9920
9927
|
//#endregion
|
|
9921
9928
|
//#region src/wc/components/KeyboardInput.wc.svelte
|
|
@@ -9943,6 +9950,10 @@ customElements.define("sui-keyboard-input", create_custom_element(KeyboardInput_
|
|
|
9943
9950
|
type: "String"
|
|
9944
9951
|
},
|
|
9945
9952
|
classes: { type: "String" },
|
|
9953
|
+
literal: {
|
|
9954
|
+
reflect: !0,
|
|
9955
|
+
type: "Boolean"
|
|
9956
|
+
},
|
|
9946
9957
|
onclick: { type: "Object" }
|
|
9947
9958
|
}, [], [], { mode: "open" }));
|
|
9948
9959
|
//#endregion
|
|
@@ -33643,6 +33654,71 @@ function hasSafeProtocol(e, t) {
|
|
|
33643
33654
|
function escapeHtml(e) {
|
|
33644
33655
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
33645
33656
|
}
|
|
33657
|
+
function narrow(e, t) {
|
|
33658
|
+
if (!t) return e;
|
|
33659
|
+
let n = new Set(t.map((e) => e.toLowerCase()));
|
|
33660
|
+
return new Set([...e].filter((e) => n.has(e)));
|
|
33661
|
+
}
|
|
33662
|
+
function resolveProtocolSets(e) {
|
|
33663
|
+
return {
|
|
33664
|
+
links: narrow(SAFE_LINK_PROTOCOLS, e?.allowedProtocols),
|
|
33665
|
+
images: narrow(SAFE_IMAGE_PROTOCOLS, e?.allowedProtocols)
|
|
33666
|
+
};
|
|
33667
|
+
}
|
|
33668
|
+
function resolveTagAllowList(e) {
|
|
33669
|
+
return e ? new Set(e) : null;
|
|
33670
|
+
}
|
|
33671
|
+
function tagAllowed(e, t) {
|
|
33672
|
+
return e === null || e.has(t);
|
|
33673
|
+
}
|
|
33674
|
+
function createSanitizingRenderer(e, t, n) {
|
|
33675
|
+
return {
|
|
33676
|
+
html(e) {
|
|
33677
|
+
return escapeHtml(e.text);
|
|
33678
|
+
},
|
|
33679
|
+
link(n) {
|
|
33680
|
+
return hasSafeProtocol(n.href, e.links) && tagAllowed(t, "a") ? !1 : escapeHtml(n.text);
|
|
33681
|
+
},
|
|
33682
|
+
image(n) {
|
|
33683
|
+
return hasSafeProtocol(n.href, e.images) && tagAllowed(t, "img") ? !1 : escapeHtml(n.text);
|
|
33684
|
+
},
|
|
33685
|
+
strong(e) {
|
|
33686
|
+
return tagAllowed(t, "strong") ? !1 : this.parser.parseInline(e.tokens);
|
|
33687
|
+
},
|
|
33688
|
+
em(e) {
|
|
33689
|
+
return tagAllowed(t, "em") ? !1 : this.parser.parseInline(e.tokens);
|
|
33690
|
+
},
|
|
33691
|
+
del(e) {
|
|
33692
|
+
return tagAllowed(t, "del") ? !1 : this.parser.parseInline(e.tokens);
|
|
33693
|
+
},
|
|
33694
|
+
codespan(e) {
|
|
33695
|
+
return tagAllowed(t, "code") ? !1 : escapeHtml(e.text);
|
|
33696
|
+
},
|
|
33697
|
+
code(e) {
|
|
33698
|
+
return tagAllowed(t, "pre") ? !1 : `${escapeHtml(e.text)}\n`;
|
|
33699
|
+
},
|
|
33700
|
+
blockquote(e) {
|
|
33701
|
+
return tagAllowed(t, "blockquote") ? !1 : this.parser.parse(e.tokens);
|
|
33702
|
+
},
|
|
33703
|
+
heading(e) {
|
|
33704
|
+
return tagAllowed(t, `h${e.depth}`) ? !1 : `${this.parser.parseInline(e.tokens)}\n`;
|
|
33705
|
+
},
|
|
33706
|
+
list(e) {
|
|
33707
|
+
return tagAllowed(t, e.ordered ? "ol" : "ul") ? !1 : e.items.map((e) => this.parser.parse(e.tokens)).join("");
|
|
33708
|
+
},
|
|
33709
|
+
table(e) {
|
|
33710
|
+
if (tagAllowed(t, "table")) return !1;
|
|
33711
|
+
let n = (e) => e.map((e) => this.parser.parseInline(e.tokens)).join(" | ");
|
|
33712
|
+
return `<p>${[n(e.header), ...e.rows.map(n)].join("<br>")}</p>`;
|
|
33713
|
+
},
|
|
33714
|
+
hr() {
|
|
33715
|
+
return tagAllowed(t, "hr") ? !1 : "";
|
|
33716
|
+
},
|
|
33717
|
+
checkbox() {
|
|
33718
|
+
return n ? "" : !1;
|
|
33719
|
+
}
|
|
33720
|
+
};
|
|
33721
|
+
}
|
|
33646
33722
|
function annotateExternalLinks(e) {
|
|
33647
33723
|
return e.replace(EXTERNAL_ANCHOR_PATTERN, "<a href=\"$1\" target=\"_blank\" rel=\"noopener noreferrer\"");
|
|
33648
33724
|
}
|
|
@@ -33651,12 +33727,18 @@ function wrapTables(e, t) {
|
|
|
33651
33727
|
return e.replace(TABLE_OPEN, `${n}<table>`).replace(TABLE_CLOSE, "</table></div>");
|
|
33652
33728
|
}
|
|
33653
33729
|
function instanceFor(e) {
|
|
33654
|
-
let t = e.breaks === !0, n =
|
|
33655
|
-
|
|
33730
|
+
let t = e.breaks === !0, n = resolveProtocolSets(e.sanitize), i = resolveTagAllowList(e.sanitize?.allowedTags), a = e.sanitize?.disableTaskLists === !0, o = [
|
|
33731
|
+
t ? "breaks" : "default",
|
|
33732
|
+
[...n.links].sort().join(","),
|
|
33733
|
+
[...n.images].sort().join(","),
|
|
33734
|
+
i ? [...i].sort().join(",") : "*",
|
|
33735
|
+
a ? "no-tasks" : "tasks"
|
|
33736
|
+
].join("|"), s = instances.get(o);
|
|
33737
|
+
return s || (s = new q({
|
|
33656
33738
|
gfm: !0,
|
|
33657
33739
|
breaks: t,
|
|
33658
|
-
renderer:
|
|
33659
|
-
}), instances.set(
|
|
33740
|
+
renderer: createSanitizingRenderer(n, i, a)
|
|
33741
|
+
}), instances.set(o, s)), s;
|
|
33660
33742
|
}
|
|
33661
33743
|
function renderMarkdown(e, t = {}) {
|
|
33662
33744
|
let n = instanceFor(t), i = t.inline === !0 ? n.parseInline(e) : n.parse(e);
|
|
@@ -33664,23 +33746,13 @@ function renderMarkdown(e, t = {}) {
|
|
|
33664
33746
|
let a = annotateExternalLinks(i);
|
|
33665
33747
|
return t.inline === !0 ? a : wrapTables(a, t.tableLabel);
|
|
33666
33748
|
}
|
|
33667
|
-
var SAFE_LINK_PROTOCOLS, SAFE_IMAGE_PROTOCOLS, NUMERIC_REFERENCE, NAMED_WHITESPACE_REFERENCE, STRIPPED_BY_URL_PARSER,
|
|
33749
|
+
var SAFE_LINK_PROTOCOLS, SAFE_IMAGE_PROTOCOLS, NUMERIC_REFERENCE, NAMED_WHITESPACE_REFERENCE, STRIPPED_BY_URL_PARSER, instances, EXTERNAL_ANCHOR_PATTERN, TABLE_OPEN, TABLE_CLOSE, init_markdown = __esmMin((() => {
|
|
33668
33750
|
init_marked_esm(), SAFE_LINK_PROTOCOLS = new Set([
|
|
33669
33751
|
"http:",
|
|
33670
33752
|
"https:",
|
|
33671
33753
|
"mailto:",
|
|
33672
33754
|
"tel:"
|
|
33673
|
-
]), SAFE_IMAGE_PROTOCOLS = new Set(["http:", "https:"]), NUMERIC_REFERENCE = /&#(x[0-9a-f]+|[0-9]+);?/gi, NAMED_WHITESPACE_REFERENCE = /&(tab|newline);/gi, STRIPPED_BY_URL_PARSER = /[\u0000-\u0020\u007f]/g,
|
|
33674
|
-
html(e) {
|
|
33675
|
-
return escapeHtml(e.text);
|
|
33676
|
-
},
|
|
33677
|
-
link(e) {
|
|
33678
|
-
return hasSafeProtocol(e.href, SAFE_LINK_PROTOCOLS) ? !1 : escapeHtml(e.text);
|
|
33679
|
-
},
|
|
33680
|
-
image(e) {
|
|
33681
|
-
return hasSafeProtocol(e.href, SAFE_IMAGE_PROTOCOLS) ? !1 : escapeHtml(e.text);
|
|
33682
|
-
}
|
|
33683
|
-
}, instances = /* @__PURE__ */ new Map(), EXTERNAL_ANCHOR_PATTERN = /<a href="(https?:\/\/[^"]*)"/g, TABLE_OPEN = /<table>/g, TABLE_CLOSE = /<\/table>/g;
|
|
33755
|
+
]), SAFE_IMAGE_PROTOCOLS = new Set(["http:", "https:"]), NUMERIC_REFERENCE = /&#(x[0-9a-f]+|[0-9]+);?/gi, NAMED_WHITESPACE_REFERENCE = /&(tab|newline);/gi, STRIPPED_BY_URL_PARSER = /[\u0000-\u0020\u007f]/g, instances = /* @__PURE__ */ new Map(), EXTERNAL_ANCHOR_PATTERN = /<a href="(https?:\/\/[^"]*)"/g, TABLE_OPEN = /<table>/g, TABLE_CLOSE = /<\/table>/g;
|
|
33684
33756
|
})), root$11 = /* @__PURE__ */ from_html("<div class=\"avatar svelte-ivh8u\"><!></div>"), root_1$10 = /* @__PURE__ */ from_html("<div class=\"header svelte-ivh8u\"><!></div>"), root_2$7 = /* @__PURE__ */ from_html("<span class=\"marker svelte-ivh8u\" aria-hidden=\"true\"></span>"), root_3$7 = /* @__PURE__ */ from_html("<div class=\"body svelte-ivh8u\"><!></div>"), root_4$6 = /* @__PURE__ */ from_html("<div class=\"body svelte-ivh8u\"></div>"), root_5$6 = /* @__PURE__ */ from_html("<div class=\"body text svelte-ivh8u\"> </div>"), root_6$6 = /* @__PURE__ */ from_html("<div class=\"clamp-toggle svelte-ivh8u\"><!></div>"), root_7$5 = /* @__PURE__ */ from_html("<span class=\"typing svelte-ivh8u\"><!></span>"), root_8$5 = /* @__PURE__ */ from_html("<div class=\"message-attachments svelte-ivh8u\"><!></div>"), root_9$2 = /* @__PURE__ */ from_html("<div class=\"action svelte-ivh8u\"><!></div>"), root_10$1 = /* @__PURE__ */ from_html("<div class=\"action svelte-ivh8u\"><!></div> <div class=\"action svelte-ivh8u\"><!></div>", 1), root_11$1 = /* @__PURE__ */ from_html("<div class=\"actions svelte-ivh8u\"><!> <!> <!> <!></div>"), root_12$1 = /* @__PURE__ */ from_html("<article><div class=\"row svelte-ivh8u\"><!> <div class=\"content svelte-ivh8u\"><!> <div><!> <!> <!> <!></div> <!> <!></div></div></article>"), $$css$12 = {
|
|
33685
33757
|
hash: "svelte-ivh8u",
|
|
33686
33758
|
code: ".chat-message.svelte-ivh8u {box-sizing:border-box;display:flex;flex-direction:column;max-width:var(--chat-message-max-width, 82%);margin:var(--chat-message-margin, 0);}.chat-message.party-sender.svelte-ivh8u {align-self:flex-end;align-items:flex-end;}.chat-message.party-responder.svelte-ivh8u {align-self:flex-start;align-items:flex-start;}.row.svelte-ivh8u {display:flex;gap:var(--chat-message-gap, 10px);align-items:flex-end;width:100%;}.chat-message.party-sender.svelte-ivh8u .row:where(.svelte-ivh8u) {flex-direction:row-reverse;}.avatar.svelte-ivh8u {display:flex;flex-shrink:0;align-items:center;justify-content:center;}.content.svelte-ivh8u {display:flex;flex-direction:column;gap:var(--chat-message-content-gap, 6px);min-width:0;}.header.svelte-ivh8u {font-size:var(--chat-message-header-font-size, 0.75rem);color:var(--chat-message-header-color, #71717a);}.bubble.svelte-ivh8u {box-sizing:border-box;padding:var(--chat-message-bubble-padding, 9px 13px);border-radius:var(--chat-message-bubble-border-radius, 16px);font-size:var(--chat-message-font-size, 0.9375rem);line-height:var(--chat-message-line-height, 1.5);color:var(--chat-message-color, #27272a);background:var(--chat-message-background, #f4f4f5);border:var(--chat-message-border, none);box-shadow:var(--chat-message-box-shadow, none);word-wrap:break-word;overflow-wrap:anywhere;}\n\n /* Only the marker variant becomes a containing block: making every bubble relative\n would silently re-base any absolutely-positioned content a consumer renders in a\n body snippet. */.bubble.has-marker.svelte-ivh8u {position:relative;}.marker.svelte-ivh8u {\n /* Decorative and absolutely positioned, so it sits over the bubble's leading\n padding — where a link at the start of a responder message also sits. Without\n this it silently eats those clicks. */pointer-events:none;position:absolute;inset-block:var(--chat-message-marker-inset-block, 0);\n /* Logical, so the bar follows `role` alignment into RTL instead of pinning left. */inset-inline-start:var(--chat-message-marker-offset, 0px);width:var(--chat-message-marker-width, 2px);border-radius:var(--chat-message-marker-border-radius, 0);background:var(--chat-message-marker-color, #6d28d9);}.chat-message.party-sender.svelte-ivh8u .bubble:where(.svelte-ivh8u) {color:var(--chat-message-sender-color, #ffffff);background:var(--chat-message-sender-background, #18181b);border:var(--chat-message-sender-border, none);border-radius:var(\n --chat-message-sender-border-radius,\n var(--chat-message-bubble-border-radius, 16px)\n );}.chat-message.party-responder.svelte-ivh8u .bubble:where(.svelte-ivh8u) {color:var(--chat-message-responder-color, var(--chat-message-color, #27272a));background:var(--chat-message-responder-background, transparent);border:var(--chat-message-responder-border, none);padding:var(--chat-message-responder-padding, 2px 0);}.chat-message.error.svelte-ivh8u .bubble:where(.svelte-ivh8u) {color:var(--chat-message-error-color, #e0334b);}.text.svelte-ivh8u {white-space:pre-wrap;}.typing.svelte-ivh8u {display:inline-flex;align-items:center;}.message-attachments.svelte-ivh8u {display:flex;flex-direction:column;gap:var(--chat-message-attachments-gap, 8px);margin:var(--chat-message-attachments-margin, 4px 0 0 0);}.message-attachments.svelte-ivh8u:empty {display:none;}.actions.svelte-ivh8u {display:flex;align-items:center;gap:var(--chat-message-actions-gap, 2px);opacity:var(--chat-message-actions-opacity, 0);transition:var(--chat-message-actions-transition, opacity 0.15s ease);--button-width: var(--chat-message-action-size, 28px);--button-height: var(--chat-message-action-size, 28px);--button-padding: var(--chat-message-action-padding, 6px);--button-border-radius: var(--chat-message-action-border-radius, 6px);--button-color: var(--chat-message-action-background-color, transparent);--button-text-color: var(--chat-message-action-color, #71717a);--button-content-gap: 0px;--button-hover-color: var(--chat-message-action-hover-background-color, #f4f4f5);}.chat-message.svelte-ivh8u:hover .actions:where(.svelte-ivh8u),\n .chat-message.svelte-ivh8u:focus-within .actions:where(.svelte-ivh8u) {opacity:1;}.action.svelte-ivh8u {display:flex;}.action.svelte-ivh8u svg {height:100%;width:100%;}\n\n @media (hover: none) {.actions.svelte-ivh8u {opacity:1;}\n }.clamp-toggle.svelte-ivh8u {display:flex;margin-top:var(--chat-message-clamp-toggle-margin-top, 4px);}\n\n /* Clamp the rendered body, not the source: the message keeps its markup and its\n copy text, and expanding is a state change rather than a re-render. */.bubble[data-clamped='true'].svelte-ivh8u .body:where(.svelte-ivh8u) {display:-webkit-box;line-clamp:var(--chat-message-clamp-lines, var(--chat-message-clamp-lines-prop, 2));-webkit-line-clamp:var(--chat-message-clamp-lines, var(--chat-message-clamp-lines-prop, 2));-webkit-box-orient:vertical;overflow:hidden;}.body.svelte-ivh8u p {margin:var(--chat-message-paragraph-margin, 0 0 0.5em 0);}.body.svelte-ivh8u p:last-child {margin-bottom:0;}.body.svelte-ivh8u a {color:var(--chat-message-link-color, #6d28d9);text-decoration:underline;text-underline-offset:2px;}.body.svelte-ivh8u code {font-family:var(--chat-message-code-font-family, ui-monospace, monospace);font-size:0.88em;background:var(--chat-message-code-background, rgba(0, 0, 0, 0.05));padding:1px 5px;border-radius:4px;}.body.svelte-ivh8u pre {background:var(--chat-message-pre-background, rgba(0, 0, 0, 0.05));padding:10px 12px;border-radius:8px;overflow-x:auto;margin:0.5em 0;}.body.svelte-ivh8u pre code {background:transparent;padding:0;}.body.svelte-ivh8u ul,\n .body.svelte-ivh8u ol {margin:var(--chat-message-list-margin, 0.4em 0);padding-left:var(--chat-message-list-padding, 1.4em);}.body.svelte-ivh8u li {margin:0.2em 0;}.body.svelte-ivh8u h1,\n .body.svelte-ivh8u h2,\n .body.svelte-ivh8u h3,\n .body.svelte-ivh8u h4,\n .body.svelte-ivh8u h5,\n .body.svelte-ivh8u h6 {margin:var(--chat-message-heading-margin, 0.8em 0 0.4em 0);line-height:1.3;}.body.svelte-ivh8u h1 {font-size:1.35em;}.body.svelte-ivh8u h2 {font-size:1.2em;}.body.svelte-ivh8u h3 {font-size:1.1em;}.body.svelte-ivh8u h4,\n .body.svelte-ivh8u h5,\n .body.svelte-ivh8u h6 {font-size:1em;}.body.svelte-ivh8u blockquote {margin:0.5em 0;padding:2px 0 2px 12px;border-left:3px solid var(--chat-message-blockquote-border-color, rgba(0, 0, 0, 0.15));opacity:var(--chat-message-blockquote-opacity, 0.85);}.body.svelte-ivh8u table {display:block;max-width:100%;overflow-x:auto;border-collapse:collapse;margin:0.5em 0;}.body.svelte-ivh8u th,\n .body.svelte-ivh8u td {padding:5px 10px;border:1px solid var(--chat-message-table-border-color, rgba(0, 0, 0, 0.12));text-align:left;}.body.svelte-ivh8u th {background:var(--chat-message-table-header-background, rgba(0, 0, 0, 0.04));}.body.svelte-ivh8u img {max-width:100%;border-radius:var(--chat-message-image-border-radius, 8px);}.body.svelte-ivh8u hr {border:none;border-top:1px solid var(--chat-message-hr-color, rgba(0, 0, 0, 0.12));margin:0.8em 0;}"
|
|
@@ -37000,11 +37072,12 @@ var root$4 = /* @__PURE__ */ from_html("<div></div>"), $$css$5 = {
|
|
|
37000
37072
|
};
|
|
37001
37073
|
function MarkdownText(e, t) {
|
|
37002
37074
|
push(t, !0), append_styles$1(e, $$css$5);
|
|
37003
|
-
let n = prop(t, "markdown", 7), i = prop(t, "breaks", 7, !1), a = prop(t, "testId", 7), o = prop(t, "classes", 7), s = prop(t, "tableLabel", 7), c = /* @__PURE__ */ user_derived(() => renderMarkdown(n(), {
|
|
37075
|
+
let n = prop(t, "markdown", 7), i = prop(t, "breaks", 7, !1), a = prop(t, "testId", 7), o = prop(t, "classes", 7), s = prop(t, "tableLabel", 7), c = prop(t, "sanitize", 7), l = /* @__PURE__ */ user_derived(() => renderMarkdown(n(), {
|
|
37004
37076
|
breaks: i(),
|
|
37005
|
-
tableLabel: s()
|
|
37077
|
+
tableLabel: s(),
|
|
37078
|
+
sanitize: c()
|
|
37006
37079
|
}));
|
|
37007
|
-
var
|
|
37080
|
+
var u = {
|
|
37008
37081
|
get markdown() {
|
|
37009
37082
|
return n();
|
|
37010
37083
|
},
|
|
@@ -37034,18 +37107,25 @@ function MarkdownText(e, t) {
|
|
|
37034
37107
|
},
|
|
37035
37108
|
set tableLabel(e) {
|
|
37036
37109
|
s(e), flushSync();
|
|
37110
|
+
},
|
|
37111
|
+
get sanitize() {
|
|
37112
|
+
return c();
|
|
37113
|
+
},
|
|
37114
|
+
set sanitize(e) {
|
|
37115
|
+
c(e), flushSync();
|
|
37037
37116
|
}
|
|
37038
|
-
},
|
|
37039
|
-
return html(
|
|
37040
|
-
set_class(
|
|
37041
|
-
}), append(e,
|
|
37117
|
+
}, f = root$4();
|
|
37118
|
+
return html(f, () => get(l), !0), reset(f), template_effect(() => {
|
|
37119
|
+
set_class(f, 1, `markdown-text ${o() ?? "" ?? ""}`, "svelte-1d6q5h0"), set_attribute(f, "data-pw", typeof a() == "string" ? a() : null), set_attribute(f, "testid", typeof a() == "string" ? a() : null);
|
|
37120
|
+
}), append(e, f), pop(u);
|
|
37042
37121
|
}
|
|
37043
37122
|
create_custom_element(MarkdownText, {
|
|
37044
37123
|
markdown: {},
|
|
37045
37124
|
breaks: {},
|
|
37046
37125
|
testId: {},
|
|
37047
37126
|
classes: {},
|
|
37048
|
-
tableLabel: {}
|
|
37127
|
+
tableLabel: {},
|
|
37128
|
+
sanitize: {}
|
|
37049
37129
|
}, [], [], { mode: "open" });
|
|
37050
37130
|
//#endregion
|
|
37051
37131
|
//#region src/wc/components/MarkdownText.wc.svelte
|
|
@@ -37070,7 +37150,8 @@ customElements.define("sui-markdown-text", create_custom_element(MarkdownText_wc
|
|
|
37070
37150
|
tableLabel: {
|
|
37071
37151
|
attribute: "table-label",
|
|
37072
37152
|
type: "String"
|
|
37073
|
-
}
|
|
37153
|
+
},
|
|
37154
|
+
sanitize: { type: "Object" }
|
|
37074
37155
|
}, [], [], { mode: "open" }));
|
|
37075
37156
|
//#endregion
|
|
37076
37157
|
//#region src/wc/components/ChatComposer.wc.svelte
|