@juspay/svelte-ui-components 2.136.1 → 2.136.7
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/BrandLoader/BrandLoader.svelte +9 -2
- package/dist/Button/Button.svelte +3 -1
- package/dist/Carousel/Carousel.svelte +50 -6
- package/dist/Chat/types.d.ts +5 -0
- package/dist/ChatMessage/ChatMessage.svelte +114 -3
- package/dist/ChatMessage/properties.d.ts +12 -0
- package/dist/ChatMessageList/ChatMessageList.svelte +1 -0
- package/dist/Choicebox/Choicebox.svelte +55 -0
- package/dist/Choicebox/properties.d.ts +1 -0
- package/dist/Input/Input.svelte +18 -7
- package/dist/InputButton/InputButton.svelte +7 -3
- package/dist/MarkdownText/MarkdownText.svelte +138 -0
- package/dist/MarkdownText/MarkdownText.svelte.d.ts +4 -0
- package/dist/MarkdownText/markdown.d.ts +6 -0
- package/dist/MarkdownText/markdown.js +105 -0
- package/dist/MarkdownText/properties.d.ts +27 -0
- package/dist/SoundKit/properties.js +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- package/dist-wc/index.js +15264 -11926
- package/package.json +5 -1
- /package/dist/{soundKit → MarkdownText}/properties.js +0 -0
- /package/dist/{soundKit/soundKit.d.ts → SoundKit/SoundKit.d.ts} +0 -0
- /package/dist/{soundKit/soundKit.js → SoundKit/SoundKit.js} +0 -0
- /package/dist/{soundKit → SoundKit}/properties.d.ts +0 -0
|
@@ -32,8 +32,15 @@
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
.loader {
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
/* --loader-height/--loader-width are also independently read by the
|
|
36
|
+
unrelated Loader component (with a 20px default there, vs 100vh/100vw
|
|
37
|
+
here), so a consumer setting either name in a scope containing both
|
|
38
|
+
components would size them identically. --brand-loader-* is the
|
|
39
|
+
namespaced, collision-free override point; the legacy --loader-*
|
|
40
|
+
names are kept as a fallback so existing consumer overrides keep
|
|
41
|
+
working unchanged. */
|
|
42
|
+
height: var(--brand-loader-height, var(--loader-height, 100vh));
|
|
43
|
+
width: var(--brand-loader-width, var(--loader-width, 100vw));
|
|
37
44
|
border-radius: var(--loader-background-border-radius, 0px);
|
|
38
45
|
display: flex;
|
|
39
46
|
justify-content: var(--loader-justify-content, center);
|
|
@@ -232,7 +232,8 @@
|
|
|
232
232
|
opacity: var(--opacity, 1);
|
|
233
233
|
border: var(--button-border, var(--_btn-border, none));
|
|
234
234
|
box-sizing: border-box;
|
|
235
|
-
text-decoration: none;
|
|
235
|
+
text-decoration: var(--button-text-decoration, none);
|
|
236
|
+
line-height: var(--button-line-height, normal);
|
|
236
237
|
display: flex;
|
|
237
238
|
justify-content: var(--button-justify-content, center);
|
|
238
239
|
align-items: center;
|
|
@@ -255,6 +256,7 @@
|
|
|
255
256
|
color: var(--disabled-text-color, var(--button-text-color, var(--_btn-text-color, white)));
|
|
256
257
|
font-size: var(--disabled-font-size);
|
|
257
258
|
font-weight: var(--disabled-font-weight);
|
|
259
|
+
text-decoration: var(--button-disabled-text-decoration, var(--button-text-decoration, none));
|
|
258
260
|
/* Preserve the variant border when disabled so secondary (bordered) stays distinct from ghost. */
|
|
259
261
|
border: var(--disabled-border, var(--button-border, var(--_btn-border, none)));
|
|
260
262
|
background: var(
|
|
@@ -135,6 +135,12 @@
|
|
|
135
135
|
});
|
|
136
136
|
|
|
137
137
|
onDestroy(() => {
|
|
138
|
+
if (carouselDiv) {
|
|
139
|
+
carouselDiv.removeEventListener('touchstart', handleTouchStart);
|
|
140
|
+
carouselDiv.removeEventListener('touchend', handleTouchEnd);
|
|
141
|
+
carouselDiv.removeEventListener('mousedown', handleMouseDown);
|
|
142
|
+
carouselDiv.removeEventListener('mouseup', handeMouseUp);
|
|
143
|
+
}
|
|
138
144
|
if (autoplay) {
|
|
139
145
|
clearInterval(intervalId);
|
|
140
146
|
}
|
|
@@ -151,11 +157,15 @@
|
|
|
151
157
|
<div class="slidesDiv" bind:this={slidesDiv}>
|
|
152
158
|
{#each views as view, index (index)}
|
|
153
159
|
<div class="current-slide">
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
<!-- Spread is the real fix: every component in this library takes named
|
|
161
|
+
props, so passing the bag under a single `properties` key meant a
|
|
162
|
+
normal slide rendered empty. `properties` is ALSO still passed so
|
|
163
|
+
that a consumer who built a purpose-made wrapper around the old
|
|
164
|
+
behaviour keeps working -- that wrapper was the only shape this
|
|
165
|
+
component was usable with before, and breaking it would force a
|
|
166
|
+
major bump for a fix that is otherwise additive. Deprecated: read
|
|
167
|
+
the named props, not `properties`. -->
|
|
168
|
+
<view.component {...view.properties} properties={view.properties} />
|
|
159
169
|
</div>
|
|
160
170
|
{/each}
|
|
161
171
|
</div>
|
|
@@ -172,7 +182,13 @@
|
|
|
172
182
|
<div
|
|
173
183
|
class={activeSlideIndex == index ? 'active-dot' : 'dot'}
|
|
174
184
|
onclick={() => moveSlideToIndex(index)}
|
|
175
|
-
{
|
|
185
|
+
onkeydown={(event) => {
|
|
186
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
187
|
+
event.preventDefault();
|
|
188
|
+
moveSlideToIndex(index);
|
|
189
|
+
}
|
|
190
|
+
onkeydown?.(event);
|
|
191
|
+
}}
|
|
176
192
|
role="button"
|
|
177
193
|
tabindex="0"
|
|
178
194
|
aria-label={`Go to slide ${index + 1}`}
|
|
@@ -182,6 +198,13 @@
|
|
|
182
198
|
{/each}
|
|
183
199
|
</div>
|
|
184
200
|
{/if}
|
|
201
|
+
<!-- Slide changes are silent to assistive tech otherwise: the dots announce
|
|
202
|
+
where they GO, but nothing announces where the carousel ARRIVED, whether
|
|
203
|
+
the move came from autoplay, a swipe or a dot. polite so it never
|
|
204
|
+
interrupts, and atomic so the whole position is read as one phrase. -->
|
|
205
|
+
<div class="carousel-live-region" aria-live="polite" aria-atomic="true">
|
|
206
|
+
{#if views.length > 0}Slide {activeSlideIndex + 1} of {views.length}{/if}
|
|
207
|
+
</div>
|
|
185
208
|
</div>
|
|
186
209
|
|
|
187
210
|
<style>
|
|
@@ -231,6 +254,12 @@
|
|
|
231
254
|
background: var(--carousel-dot-active-color, #000000);
|
|
232
255
|
transition: 0.3s ease;
|
|
233
256
|
}
|
|
257
|
+
|
|
258
|
+
.dot:focus-visible,
|
|
259
|
+
.active-dot:focus-visible {
|
|
260
|
+
outline: var(--dot-focus-outline, 2px solid #000000);
|
|
261
|
+
outline-offset: var(--dot-focus-outline-offset, 2px);
|
|
262
|
+
}
|
|
234
263
|
/*
|
|
235
264
|
@media only screen and (max-width: 324px) {
|
|
236
265
|
|
|
@@ -258,4 +287,19 @@
|
|
|
258
287
|
}
|
|
259
288
|
|
|
260
289
|
} */
|
|
290
|
+
|
|
291
|
+
/* Visually hidden but readable by assistive tech -- the standard clip pattern
|
|
292
|
+
rather than display:none, which would remove it from the a11y tree. */
|
|
293
|
+
.carousel-live-region {
|
|
294
|
+
position: absolute;
|
|
295
|
+
width: 1px;
|
|
296
|
+
height: 1px;
|
|
297
|
+
margin: -1px;
|
|
298
|
+
padding: 0;
|
|
299
|
+
overflow: hidden;
|
|
300
|
+
clip: rect(0 0 0 0);
|
|
301
|
+
clip-path: inset(50%);
|
|
302
|
+
white-space: nowrap;
|
|
303
|
+
border: 0;
|
|
304
|
+
}
|
|
261
305
|
</style>
|
package/dist/Chat/types.d.ts
CHANGED
|
@@ -6,6 +6,11 @@ export type ChatMessageData = {
|
|
|
6
6
|
role: ChatRole;
|
|
7
7
|
content: string;
|
|
8
8
|
html?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Markdown source rendered through the library's sanitized pipeline (see
|
|
11
|
+
* MarkdownText). Wins over `html` and `content` in the bubble.
|
|
12
|
+
*/
|
|
13
|
+
markdown?: string;
|
|
9
14
|
streaming?: boolean;
|
|
10
15
|
status?: ChatMessageStatus;
|
|
11
16
|
timestamp?: number;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import retrySvg from '../assets/retry.svg?raw';
|
|
7
7
|
import thumbUpSvg from '../assets/thumb-up.svg?raw';
|
|
8
8
|
import thumbDownSvg from '../assets/thumb-down.svg?raw';
|
|
9
|
+
import { onDestroy, onMount } from 'svelte';
|
|
9
10
|
import { partyOf } from '../Chat/roles';
|
|
10
11
|
import type { ChatMessageProperties } from './properties';
|
|
11
12
|
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
role,
|
|
14
15
|
content = '',
|
|
15
16
|
html,
|
|
17
|
+
markdown,
|
|
16
18
|
body,
|
|
17
19
|
streaming = false,
|
|
18
20
|
status,
|
|
@@ -37,7 +39,34 @@
|
|
|
37
39
|
let copied = $state(false);
|
|
38
40
|
let copyResetTimer: ReturnType<typeof setTimeout> | null = null;
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
onDestroy(() => {
|
|
43
|
+
if (copyResetTimer !== null) {
|
|
44
|
+
clearTimeout(copyResetTimer);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
let hasMarkdown = $derived(typeof markdown === 'string' && markdown.length > 0);
|
|
49
|
+
|
|
50
|
+
/* The pipeline loads dynamically at mount (the LottiePlayer pattern) so
|
|
51
|
+
`marked` — a peer dependency — is only pulled in at runtime, never during
|
|
52
|
+
SSR, and rendering `markdown` degrades to the `html`/`content` fallback
|
|
53
|
+
until the module resolves or when the peer is absent. */
|
|
54
|
+
let renderMarkdownFn = $state<((source: string) => string) | null>(null);
|
|
55
|
+
|
|
56
|
+
onMount(() => {
|
|
57
|
+
void import('../MarkdownText/markdown')
|
|
58
|
+
.then((module) => {
|
|
59
|
+
renderMarkdownFn = module.renderMarkdown;
|
|
60
|
+
})
|
|
61
|
+
.catch(() => {
|
|
62
|
+
renderMarkdownFn = null;
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
let effectiveHtml = $derived(
|
|
67
|
+
hasMarkdown && renderMarkdownFn !== null ? renderMarkdownFn(markdown ?? '') : html
|
|
68
|
+
);
|
|
69
|
+
let hasHtml = $derived(typeof effectiveHtml === 'string' && effectiveHtml.length > 0);
|
|
41
70
|
let hasBody = $derived(typeof body === 'function');
|
|
42
71
|
let hasContent = $derived(hasBody || hasHtml || content.length > 0);
|
|
43
72
|
let showTyping = $derived(streaming && !hasContent);
|
|
@@ -55,7 +84,14 @@
|
|
|
55
84
|
}
|
|
56
85
|
|
|
57
86
|
async function copy(): Promise<void> {
|
|
58
|
-
const text =
|
|
87
|
+
const text =
|
|
88
|
+
content.length > 0
|
|
89
|
+
? content
|
|
90
|
+
: hasMarkdown
|
|
91
|
+
? (markdown ?? '')
|
|
92
|
+
: typeof html === 'string'
|
|
93
|
+
? htmlToText(html)
|
|
94
|
+
: '';
|
|
59
95
|
if (typeof navigator !== 'undefined' && typeof navigator.clipboard?.writeText === 'function') {
|
|
60
96
|
try {
|
|
61
97
|
await navigator.clipboard.writeText(text);
|
|
@@ -97,7 +133,7 @@
|
|
|
97
133
|
<div class="body">{@render body?.()}</div>
|
|
98
134
|
{:else if hasHtml}
|
|
99
135
|
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
100
|
-
<div class="body">{@html
|
|
136
|
+
<div class="body">{@html effectiveHtml}</div>
|
|
101
137
|
{:else if content.length > 0}
|
|
102
138
|
<div class="body text">{content}</div>
|
|
103
139
|
{/if}
|
|
@@ -331,4 +367,79 @@
|
|
|
331
367
|
background: transparent;
|
|
332
368
|
padding: 0;
|
|
333
369
|
}
|
|
370
|
+
|
|
371
|
+
.body :global(ul),
|
|
372
|
+
.body :global(ol) {
|
|
373
|
+
margin: var(--chat-message-list-margin, 0.4em 0);
|
|
374
|
+
padding-left: var(--chat-message-list-padding, 1.4em);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.body :global(li) {
|
|
378
|
+
margin: 0.2em 0;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.body :global(h1),
|
|
382
|
+
.body :global(h2),
|
|
383
|
+
.body :global(h3),
|
|
384
|
+
.body :global(h4),
|
|
385
|
+
.body :global(h5),
|
|
386
|
+
.body :global(h6) {
|
|
387
|
+
margin: var(--chat-message-heading-margin, 0.8em 0 0.4em 0);
|
|
388
|
+
line-height: 1.3;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.body :global(h1) {
|
|
392
|
+
font-size: 1.35em;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.body :global(h2) {
|
|
396
|
+
font-size: 1.2em;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.body :global(h3) {
|
|
400
|
+
font-size: 1.1em;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.body :global(h4),
|
|
404
|
+
.body :global(h5),
|
|
405
|
+
.body :global(h6) {
|
|
406
|
+
font-size: 1em;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.body :global(blockquote) {
|
|
410
|
+
margin: 0.5em 0;
|
|
411
|
+
padding: 2px 0 2px 12px;
|
|
412
|
+
border-left: 3px solid var(--chat-message-blockquote-border-color, rgba(0, 0, 0, 0.15));
|
|
413
|
+
opacity: var(--chat-message-blockquote-opacity, 0.85);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.body :global(table) {
|
|
417
|
+
display: block;
|
|
418
|
+
max-width: 100%;
|
|
419
|
+
overflow-x: auto;
|
|
420
|
+
border-collapse: collapse;
|
|
421
|
+
margin: 0.5em 0;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.body :global(th),
|
|
425
|
+
.body :global(td) {
|
|
426
|
+
padding: 5px 10px;
|
|
427
|
+
border: 1px solid var(--chat-message-table-border-color, rgba(0, 0, 0, 0.12));
|
|
428
|
+
text-align: left;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.body :global(th) {
|
|
432
|
+
background: var(--chat-message-table-header-background, rgba(0, 0, 0, 0.04));
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.body :global(img) {
|
|
436
|
+
max-width: 100%;
|
|
437
|
+
border-radius: var(--chat-message-image-border-radius, 8px);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.body :global(hr) {
|
|
441
|
+
border: none;
|
|
442
|
+
border-top: 1px solid var(--chat-message-hr-color, rgba(0, 0, 0, 0.12));
|
|
443
|
+
margin: 0.8em 0;
|
|
444
|
+
}
|
|
334
445
|
</style>
|
|
@@ -8,6 +8,18 @@ export type MandatoryChatMessageProperties = {
|
|
|
8
8
|
export type OptionalChatMessageProperties = {
|
|
9
9
|
content?: string;
|
|
10
10
|
html?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Markdown source rendered through the library's sanitized-by-construction
|
|
13
|
+
* pipeline (raw HTML is escaped; unsafe link/image protocols are stripped) —
|
|
14
|
+
* unlike `html`, which must arrive pre-sanitized. Non-empty `markdown` takes
|
|
15
|
+
* precedence over `html` and `content`; a `body` snippet still wins. An
|
|
16
|
+
* empty string is treated as absent and falls through, exactly like `html`.
|
|
17
|
+
* Also serves as the copy text when `content` is empty. The pipeline loads
|
|
18
|
+
* on demand, so the `marked` peer is only needed when this prop is used;
|
|
19
|
+
* during SSR and while loading, `html`/`content` render as the fallback
|
|
20
|
+
* (for server-rendered markdown use `MarkdownText` or `renderMarkdown`).
|
|
21
|
+
*/
|
|
22
|
+
markdown?: string;
|
|
11
23
|
/**
|
|
12
24
|
* Replaces the rendered bubble body with arbitrary markup while keeping the
|
|
13
25
|
* message chrome (role styling, avatar, header, attachments, copy/retry/
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { ChoiceboxProperties } from './properties';
|
|
3
|
+
import checkmarkSvg from '../assets/checkmark.svg?raw';
|
|
3
4
|
|
|
4
5
|
let {
|
|
5
6
|
children,
|
|
6
7
|
selected = $bindable(false),
|
|
7
8
|
mode = 'radio',
|
|
8
9
|
disabled = false,
|
|
10
|
+
showIndicator = true,
|
|
9
11
|
testId,
|
|
10
12
|
onclick,
|
|
11
13
|
classes
|
|
@@ -47,6 +49,14 @@
|
|
|
47
49
|
{#if typeof children === 'function'}
|
|
48
50
|
{@render children()}
|
|
49
51
|
{/if}
|
|
52
|
+
{#if showIndicator}
|
|
53
|
+
<span class="indicator {mode}" class:selected aria-hidden="true">
|
|
54
|
+
{#if mode === 'checkbox' && selected}
|
|
55
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
56
|
+
<span class="indicator-icon">{@html checkmarkSvg}</span>
|
|
57
|
+
{/if}
|
|
58
|
+
</span>
|
|
59
|
+
{/if}
|
|
50
60
|
</div>
|
|
51
61
|
|
|
52
62
|
<style>
|
|
@@ -87,4 +97,49 @@
|
|
|
87
97
|
opacity: var(--choicebox-disabled-opacity, 0.4);
|
|
88
98
|
cursor: var(--choicebox-disabled-cursor, not-allowed);
|
|
89
99
|
}
|
|
100
|
+
|
|
101
|
+
.indicator {
|
|
102
|
+
flex: 0 0 auto;
|
|
103
|
+
order: var(--choicebox-indicator-order, 1);
|
|
104
|
+
margin-inline-start: var(--choicebox-indicator-margin-inline-start, auto);
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
box-sizing: border-box;
|
|
109
|
+
width: var(--choicebox-indicator-size, 20px);
|
|
110
|
+
height: var(--choicebox-indicator-size, 20px);
|
|
111
|
+
border: var(--choicebox-indicator-border, 2px solid #757575);
|
|
112
|
+
background: var(--choicebox-indicator-background, transparent);
|
|
113
|
+
transition: var(--choicebox-indicator-transition, background 0.2s, border-color 0.2s);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.indicator.radio {
|
|
117
|
+
border-radius: 50%;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.indicator.checkbox {
|
|
121
|
+
border-radius: var(--choicebox-indicator-border-radius, var(--radius, 4px));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.indicator.selected {
|
|
125
|
+
border: var(--choicebox-indicator-selected-border, 2px solid #2196f3);
|
|
126
|
+
background: var(--choicebox-indicator-selected-background, #2196f3);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.indicator.radio.selected {
|
|
130
|
+
box-shadow: inset 0 0 0 var(--choicebox-indicator-dot-inset, 4px)
|
|
131
|
+
var(--choicebox-background, #ffffff);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.indicator-icon {
|
|
135
|
+
display: flex;
|
|
136
|
+
width: var(--choicebox-indicator-icon-size, 14px);
|
|
137
|
+
height: var(--choicebox-indicator-icon-size, 14px);
|
|
138
|
+
color: var(--choicebox-indicator-icon-color, #ffffff);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.indicator-icon :global(svg) {
|
|
142
|
+
width: 100%;
|
|
143
|
+
height: 100%;
|
|
144
|
+
}
|
|
90
145
|
</style>
|
package/dist/Input/Input.svelte
CHANGED
|
@@ -435,7 +435,12 @@
|
|
|
435
435
|
</div>
|
|
436
436
|
{/if}
|
|
437
437
|
{#if isShowingInfo}
|
|
438
|
-
<div
|
|
438
|
+
<div
|
|
439
|
+
id={infoMessageId}
|
|
440
|
+
class="info-message"
|
|
441
|
+
data-pw={typeof testId === 'string' && testId.length > 0 ? `${testId}-info-message` : null}
|
|
442
|
+
testID={typeof testId === 'string' && testId.length > 0 ? `${testId}-info-message` : null}
|
|
443
|
+
>
|
|
439
444
|
{infoMessage}
|
|
440
445
|
</div>
|
|
441
446
|
{/if}
|
|
@@ -492,11 +497,11 @@
|
|
|
492
497
|
.input-error {
|
|
493
498
|
--input-focus-border: var(
|
|
494
499
|
--input-error-border,
|
|
495
|
-
1px solid var(--input-error-msg-text-color, #
|
|
500
|
+
1px solid var(--input-error-msg-text-color, #c5120a)
|
|
496
501
|
) !important;
|
|
497
502
|
--input-border: var(
|
|
498
503
|
--input-error-border,
|
|
499
|
-
1px solid var(--input-error-msg-text-color, #
|
|
504
|
+
1px solid var(--input-error-msg-text-color, #c5120a)
|
|
500
505
|
) !important;
|
|
501
506
|
}
|
|
502
507
|
|
|
@@ -523,7 +528,7 @@
|
|
|
523
528
|
}
|
|
524
529
|
|
|
525
530
|
.input-mandatory-asterisk {
|
|
526
|
-
color: var(--input-mandatory-color, var(--input-error-msg-text-color, #
|
|
531
|
+
color: var(--input-mandatory-color, var(--input-error-msg-text-color, #c5120a));
|
|
527
532
|
margin-left: var(--input-mandatory-gap, 2px);
|
|
528
533
|
}
|
|
529
534
|
|
|
@@ -591,7 +596,9 @@
|
|
|
591
596
|
.error-message {
|
|
592
597
|
font-weight: var(--input-error-msg-text-weight, 400);
|
|
593
598
|
font-size: var(--input-error-msg-text-size, 12px);
|
|
594
|
-
|
|
599
|
+
/* #c5120a clears WCAG AA (6.06:1 on white) at this 12px size; the prior #fa1405
|
|
600
|
+
default was only 4.06:1, so the error message itself failed to be legible. */
|
|
601
|
+
color: var(--input-error-msg-text-color, #c5120a);
|
|
595
602
|
margin: var(--input-error-msg-margin);
|
|
596
603
|
padding: var(--input-error-msg-padding);
|
|
597
604
|
}
|
|
@@ -599,7 +606,11 @@
|
|
|
599
606
|
.info-message {
|
|
600
607
|
font-weight: var(--input-info-msg-text-weight, 400);
|
|
601
608
|
font-size: var(--input-info-msg-text-size, 12px);
|
|
602
|
-
|
|
609
|
+
/* Neutral on purpose -- this used to default to the same red as .error-message,
|
|
610
|
+
so helper text with no error visually read as a failed field (color-alone
|
|
611
|
+
signalling, WCAG 1.4.1). #52525b is the muted-text tone already used for
|
|
612
|
+
ChatToolStatus/ThinkingIndicator elsewhere in this library, at 7.73:1. */
|
|
613
|
+
color: var(--input-info-msg-text-color, #52525b);
|
|
603
614
|
margin: var(--input-info-msg-margin);
|
|
604
615
|
padding: var(--input-info-msg-padding);
|
|
605
616
|
}
|
|
@@ -613,7 +624,7 @@
|
|
|
613
624
|
}
|
|
614
625
|
|
|
615
626
|
.input-char-count.at-limit {
|
|
616
|
-
color: var(--input-char-count-limit-color, var(--input-error-msg-text-color, #
|
|
627
|
+
color: var(--input-char-count-limit-color, var(--input-error-msg-text-color, #c5120a));
|
|
617
628
|
}
|
|
618
629
|
|
|
619
630
|
::placeholder {
|
|
@@ -193,14 +193,18 @@
|
|
|
193
193
|
.error-message {
|
|
194
194
|
font-weight: var(--input-error-msg-text-weight, 400);
|
|
195
195
|
font-size: var(--input-error-msg-text-size, 12px);
|
|
196
|
-
|
|
196
|
+
/* Shares --input-error-msg-text-color with Input.svelte -- kept in sync with its
|
|
197
|
+
#c5120a default (6.06:1 AA) so the same token means the same color everywhere. */
|
|
198
|
+
color: var(--input-error-msg-text-color, #c5120a);
|
|
197
199
|
margin: var(--input-btn-error-msg-margin, 12px 0px 0px 0px);
|
|
198
200
|
}
|
|
199
201
|
|
|
200
202
|
.info-message {
|
|
201
203
|
font-weight: var(--input-info-msg-text-weight, 400);
|
|
202
204
|
font-size: var(--input-info-msg-text-size, 12px);
|
|
203
|
-
|
|
205
|
+
/* Shares --input-info-msg-text-color with Input.svelte -- see its .info-message
|
|
206
|
+
for why this is a neutral #52525b rather than the error red. */
|
|
207
|
+
color: var(--input-info-msg-text-color, #52525b);
|
|
204
208
|
margin: var(--input-btn-info-msg-margin, 12px 0px 0px 0px);
|
|
205
209
|
}
|
|
206
210
|
|
|
@@ -224,7 +228,7 @@
|
|
|
224
228
|
}
|
|
225
229
|
|
|
226
230
|
.external-error-message {
|
|
227
|
-
color: var(--inputbutton-external-error-color, #
|
|
231
|
+
color: var(--inputbutton-external-error-color, #c5120a);
|
|
228
232
|
margin: var(--inputbutton-external-error-margin, 6px 0px 0px 0px);
|
|
229
233
|
}
|
|
230
234
|
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { renderMarkdown } from './markdown';
|
|
3
|
+
import type { MarkdownTextProperties } from './properties';
|
|
4
|
+
|
|
5
|
+
let { markdown, breaks = false, testId, classes }: MarkdownTextProperties = $props();
|
|
6
|
+
|
|
7
|
+
let html = $derived(renderMarkdown(markdown, { breaks }));
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<div
|
|
11
|
+
class="markdown-text {classes ?? ''}"
|
|
12
|
+
data-pw={typeof testId === 'string' ? testId : null}
|
|
13
|
+
testID={typeof testId === 'string' ? testId : null}
|
|
14
|
+
>
|
|
15
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
16
|
+
{@html html}
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<style>
|
|
20
|
+
.markdown-text {
|
|
21
|
+
font-size: var(--markdown-text-font-size, inherit);
|
|
22
|
+
line-height: var(--markdown-text-line-height, 1.5);
|
|
23
|
+
color: var(--markdown-text-color, inherit);
|
|
24
|
+
word-wrap: break-word;
|
|
25
|
+
overflow-wrap: anywhere;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.markdown-text :global(p) {
|
|
29
|
+
margin: var(--markdown-text-paragraph-margin, 0 0 0.5em 0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.markdown-text :global(p:last-child) {
|
|
33
|
+
margin-bottom: 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.markdown-text :global(h1),
|
|
37
|
+
.markdown-text :global(h2),
|
|
38
|
+
.markdown-text :global(h3),
|
|
39
|
+
.markdown-text :global(h4),
|
|
40
|
+
.markdown-text :global(h5),
|
|
41
|
+
.markdown-text :global(h6) {
|
|
42
|
+
margin: var(--markdown-text-heading-margin, 0.8em 0 0.4em 0);
|
|
43
|
+
line-height: 1.3;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.markdown-text :global(h1) {
|
|
47
|
+
font-size: 1.35em;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.markdown-text :global(h2) {
|
|
51
|
+
font-size: 1.2em;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.markdown-text :global(h3) {
|
|
55
|
+
font-size: 1.1em;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.markdown-text :global(h4),
|
|
59
|
+
.markdown-text :global(h5),
|
|
60
|
+
.markdown-text :global(h6) {
|
|
61
|
+
font-size: 1em;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.markdown-text :global(a) {
|
|
65
|
+
color: var(--markdown-text-link-color, #6d28d9);
|
|
66
|
+
text-decoration: underline;
|
|
67
|
+
text-underline-offset: 2px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.markdown-text :global(code) {
|
|
71
|
+
font-family: var(--markdown-text-code-font-family, ui-monospace, monospace);
|
|
72
|
+
font-size: 0.88em;
|
|
73
|
+
background: var(--markdown-text-code-background, rgba(0, 0, 0, 0.05));
|
|
74
|
+
padding: 1px 5px;
|
|
75
|
+
border-radius: 4px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.markdown-text :global(pre) {
|
|
79
|
+
background: var(--markdown-text-pre-background, rgba(0, 0, 0, 0.05));
|
|
80
|
+
padding: 10px 12px;
|
|
81
|
+
border-radius: 8px;
|
|
82
|
+
overflow-x: auto;
|
|
83
|
+
margin: 0.5em 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.markdown-text :global(pre code) {
|
|
87
|
+
background: transparent;
|
|
88
|
+
padding: 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.markdown-text :global(ul),
|
|
92
|
+
.markdown-text :global(ol) {
|
|
93
|
+
margin: var(--markdown-text-list-margin, 0.4em 0);
|
|
94
|
+
padding-left: var(--markdown-text-list-padding, 1.4em);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.markdown-text :global(li) {
|
|
98
|
+
margin: 0.2em 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.markdown-text :global(blockquote) {
|
|
102
|
+
margin: 0.5em 0;
|
|
103
|
+
padding: 2px 0 2px 12px;
|
|
104
|
+
border-left: 3px solid var(--markdown-text-blockquote-border-color, rgba(0, 0, 0, 0.15));
|
|
105
|
+
color: var(--markdown-text-blockquote-color, inherit);
|
|
106
|
+
opacity: var(--markdown-text-blockquote-opacity, 0.85);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.markdown-text :global(table) {
|
|
110
|
+
display: block;
|
|
111
|
+
max-width: 100%;
|
|
112
|
+
overflow-x: auto;
|
|
113
|
+
border-collapse: collapse;
|
|
114
|
+
margin: 0.5em 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.markdown-text :global(th),
|
|
118
|
+
.markdown-text :global(td) {
|
|
119
|
+
padding: 5px 10px;
|
|
120
|
+
border: 1px solid var(--markdown-text-table-border-color, rgba(0, 0, 0, 0.12));
|
|
121
|
+
text-align: left;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.markdown-text :global(th) {
|
|
125
|
+
background: var(--markdown-text-table-header-background, rgba(0, 0, 0, 0.04));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.markdown-text :global(img) {
|
|
129
|
+
max-width: 100%;
|
|
130
|
+
border-radius: var(--markdown-text-image-border-radius, 8px);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.markdown-text :global(hr) {
|
|
134
|
+
border: none;
|
|
135
|
+
border-top: 1px solid var(--markdown-text-hr-color, rgba(0, 0, 0, 0.12));
|
|
136
|
+
margin: 0.8em 0;
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RenderMarkdownOptions } from './properties';
|
|
2
|
+
/**
|
|
3
|
+
* Markdown → HTML with the sanitizing pipeline above. Pure string transform —
|
|
4
|
+
* no DOM involved — so it renders identically on server and client.
|
|
5
|
+
*/
|
|
6
|
+
export declare function renderMarkdown(markdown: string, options?: RenderMarkdownOptions): string;
|