@heyramzi/ui 6.1.0 → 7.0.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/COMPONENTS.md +6 -25
- package/README.md +6 -4
- package/package.json +7 -15
- package/scripts/sync-shadcn.mjs +12 -3
- package/src/ai/index.ts +0 -18
- package/src/animations/README.md +3 -3
- package/src/lib/sliding-pill.ts +68 -0
- package/src/lib/theme-transition.ts +4 -2
- package/src/shadcn/code-block/code-block-actions.svelte +23 -0
- package/src/shadcn/code-block/code-block-content.svelte +55 -0
- package/src/shadcn/code-block/code-block-copy-button.svelte +59 -0
- package/src/shadcn/code-block/code-block-footer.svelte +20 -0
- package/src/shadcn/code-block/code-block-header.svelte +23 -0
- package/src/shadcn/code-block/code-block-line.svelte +71 -0
- package/src/shadcn/code-block/code-block-title.svelte +23 -0
- package/src/shadcn/code-block/code-block.svelte +47 -0
- package/src/shadcn/code-block/index.ts +42 -0
- package/src/shadcn/hooks/highlighter.ts +132 -0
- package/src/shadcn/hooks/use-highlighted-code.svelte.ts +98 -0
- package/src/shadcn/kbd/index.ts +10 -0
- package/src/shadcn/kbd/kbd-group.svelte +20 -0
- package/src/shadcn/kbd/kbd.svelte +23 -0
- package/src/shadcn/message-scroller/index.ts +28 -0
- package/src/shadcn/message-scroller/message-scroller-button.svelte +52 -0
- package/src/shadcn/message-scroller/message-scroller-content.svelte +17 -0
- package/src/shadcn/message-scroller/message-scroller-item.svelte +22 -0
- package/src/shadcn/message-scroller/message-scroller-provider.svelte +7 -0
- package/src/shadcn/message-scroller/message-scroller-viewport.svelte +20 -0
- package/src/shadcn/message-scroller/message-scroller.svelte +20 -0
- package/src/shadcn/tabs/tabs-list.svelte +13 -2
- package/src/shadcn/tabs/tabs-trigger.svelte +1 -1
- package/src/shadcn/trace/index.ts +29 -0
- package/src/shadcn/trace/trace-collapsible-content.svelte +29 -0
- package/src/shadcn/trace/trace-collapsible-trigger.svelte +29 -0
- package/src/shadcn/trace/trace-collapsible.svelte +20 -0
- package/src/shadcn/trace/trace-description.svelte +20 -0
- package/src/shadcn/trace/trace-icon.svelte +24 -0
- package/src/shadcn/trace/trace-line.svelte +31 -0
- package/src/shadcn/trace/trace-title.svelte +20 -0
- package/src/shadcn/trace/trace.svelte +23 -0
- package/src/showcase/AiSection.svelte +0 -7
- package/src/showcase/demos/shadcn/code-block.svelte +80 -0
- package/src/showcase/demos/shadcn/index.ts +24 -0
- package/src/showcase/demos/shadcn/message-scroller.svelte +44 -0
- package/src/showcase/demos/shadcn/trace.svelte +51 -0
- package/src/showcase/kit.ts +1 -2
- package/src/ai/conversation/Conversation.svelte +0 -28
- package/src/ai/conversation/ConversationContent.svelte +0 -35
- package/src/ai/conversation/ConversationEmptyState.svelte +0 -46
- package/src/ai/conversation/ConversationScrollButton.svelte +0 -51
- package/src/ai/conversation/index.ts +0 -33
- package/src/ai/conversation/stick-to-bottom-context.svelte.ts +0 -131
- package/src/charts/animated-value.css +0 -7
- package/src/charts/animated-value.svelte +0 -110
- package/src/charts/area-chart.css +0 -29
- package/src/charts/area-chart.svelte +0 -195
- package/src/charts/bar-chart.css +0 -119
- package/src/charts/bar-chart.svelte +0 -269
- package/src/charts/charts.css +0 -201
- package/src/charts/crosshair.svelte +0 -35
- package/src/charts/donut-chart.css +0 -56
- package/src/charts/donut-chart.svelte +0 -158
- package/src/charts/edge-fade.svelte +0 -43
- package/src/charts/edge-fade.ts +0 -16
- package/src/charts/figure.css +0 -100
- package/src/charts/figure.svelte +0 -122
- package/src/charts/gauge-chart.css +0 -94
- package/src/charts/gauge-chart.svelte +0 -303
- package/src/charts/hover-band.test.ts +0 -30
- package/src/charts/hover-band.ts +0 -21
- package/src/charts/hover-focus.svelte +0 -85
- package/src/charts/index.ts +0 -30
- package/src/charts/legend.css +0 -131
- package/src/charts/legend.svelte +0 -112
- package/src/charts/line-chart.css +0 -26
- package/src/charts/line-chart.svelte +0 -256
- package/src/charts/motion.ts +0 -19
- package/src/charts/number-chart.css +0 -168
- package/src/charts/number-chart.svelte +0 -177
- package/src/charts/primitives/chart-container.svelte +0 -57
- package/src/charts/primitives/chart-style.svelte +0 -36
- package/src/charts/primitives/chart-tooltip.svelte +0 -161
- package/src/charts/primitives/chart-utils.ts +0 -54
- package/src/charts/primitives/index.ts +0 -11
- package/src/charts/reveal.svelte +0 -61
- package/src/charts/ring-chart.css +0 -96
- package/src/charts/ring-chart.svelte +0 -158
- package/src/charts/sparkline.css +0 -45
- package/src/charts/sparkline.svelte +0 -140
- package/src/charts/stat-card.css +0 -103
- package/src/charts/stat-card.svelte +0 -267
- package/src/charts/time-series-chart.css +0 -28
- package/src/charts/time-series-chart.svelte +0 -179
- package/src/charts/trend-pill.css +0 -38
- package/src/charts/trend-pill.svelte +0 -48
- package/src/lib/hooks/is-mobile.svelte.ts +0 -11
- package/src/showcase/ChartsSection.svelte +0 -458
- package/src/showcase/demos/ai/conversation.svelte +0 -59
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Actions from "./code-block-actions.svelte";
|
|
2
|
+
import Content from "./code-block-content.svelte";
|
|
3
|
+
import CopyButton from "./code-block-copy-button.svelte";
|
|
4
|
+
import Footer from "./code-block-footer.svelte";
|
|
5
|
+
import Header from "./code-block-header.svelte";
|
|
6
|
+
import Title from "./code-block-title.svelte";
|
|
7
|
+
import Line, {
|
|
8
|
+
codeBlockLineVariants,
|
|
9
|
+
type CodeBlockLineToken,
|
|
10
|
+
type CodeBlockLineVariant,
|
|
11
|
+
} from "./code-block-line.svelte";
|
|
12
|
+
import Root, {
|
|
13
|
+
codeBlockVariants,
|
|
14
|
+
type CodeBlockSize,
|
|
15
|
+
type CodeBlockVariant,
|
|
16
|
+
} from "./code-block.svelte";
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
Root,
|
|
20
|
+
Header,
|
|
21
|
+
Title,
|
|
22
|
+
Actions,
|
|
23
|
+
CopyButton,
|
|
24
|
+
Content,
|
|
25
|
+
Line,
|
|
26
|
+
Footer,
|
|
27
|
+
codeBlockVariants,
|
|
28
|
+
codeBlockLineVariants,
|
|
29
|
+
type CodeBlockVariant,
|
|
30
|
+
type CodeBlockSize,
|
|
31
|
+
type CodeBlockLineVariant,
|
|
32
|
+
type CodeBlockLineToken,
|
|
33
|
+
//
|
|
34
|
+
Root as CodeBlock,
|
|
35
|
+
Header as CodeBlockHeader,
|
|
36
|
+
Title as CodeBlockTitle,
|
|
37
|
+
Actions as CodeBlockActions,
|
|
38
|
+
CopyButton as CodeBlockCopyButton,
|
|
39
|
+
Content as CodeBlockContent,
|
|
40
|
+
Line as CodeBlockLine,
|
|
41
|
+
Footer as CodeBlockFooter,
|
|
42
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createHighlighterCore,
|
|
3
|
+
type GrammarState,
|
|
4
|
+
type HighlighterCore,
|
|
5
|
+
type ThemedToken,
|
|
6
|
+
} from "shiki/core";
|
|
7
|
+
import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
|
|
8
|
+
|
|
9
|
+
// Add the languages you need. Each one loads the first time it is used.
|
|
10
|
+
const languages = {
|
|
11
|
+
bash: () => import("shiki/langs/shellscript.mjs"),
|
|
12
|
+
css: () => import("shiki/langs/css.mjs"),
|
|
13
|
+
diff: () => import("shiki/langs/diff.mjs"),
|
|
14
|
+
html: () => import("shiki/langs/html.mjs"),
|
|
15
|
+
javascript: () => import("shiki/langs/javascript.mjs"),
|
|
16
|
+
json: () => import("shiki/langs/json.mjs"),
|
|
17
|
+
jsx: () => import("shiki/langs/jsx.mjs"),
|
|
18
|
+
markdown: () => import("shiki/langs/markdown.mjs"),
|
|
19
|
+
python: () => import("shiki/langs/python.mjs"),
|
|
20
|
+
sql: () => import("shiki/langs/sql.mjs"),
|
|
21
|
+
svelte: () => import("shiki/langs/svelte.mjs"),
|
|
22
|
+
tsx: () => import("shiki/langs/tsx.mjs"),
|
|
23
|
+
typescript: () => import("shiki/langs/typescript.mjs"),
|
|
24
|
+
yaml: () => import("shiki/langs/yaml.mjs"),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const aliases: Record<string, keyof typeof languages> = {
|
|
28
|
+
js: "javascript",
|
|
29
|
+
md: "markdown",
|
|
30
|
+
py: "python",
|
|
31
|
+
sh: "bash",
|
|
32
|
+
shell: "bash",
|
|
33
|
+
shellscript: "bash",
|
|
34
|
+
ts: "typescript",
|
|
35
|
+
yml: "yaml",
|
|
36
|
+
zsh: "bash",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
let highlighter: Promise<HighlighterCore> | undefined;
|
|
40
|
+
|
|
41
|
+
function getHighlighter() {
|
|
42
|
+
highlighter ??= createHighlighterCore({
|
|
43
|
+
themes: [import("shiki/themes/github-light.mjs"), import("shiki/themes/github-dark.mjs")],
|
|
44
|
+
langs: [],
|
|
45
|
+
engine: createJavaScriptRegexEngine({ forgiving: true }),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return highlighter;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getLanguage(language: string) {
|
|
52
|
+
const name = language.toLowerCase();
|
|
53
|
+
|
|
54
|
+
if (name === "ansi") {
|
|
55
|
+
return name;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (name in languages) {
|
|
59
|
+
return name as keyof typeof languages;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return aliases[name] ?? null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// One highlighted token. Render it as a `<span>` with this style and class.
|
|
66
|
+
export type HighlightedToken = {
|
|
67
|
+
content: string;
|
|
68
|
+
style?: string;
|
|
69
|
+
class?: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// A line of plain text, or the highlighted tokens of a line.
|
|
73
|
+
export type HighlightedLine = string | HighlightedToken[];
|
|
74
|
+
|
|
75
|
+
function toHighlightedLine(tokens: ThemedToken[]): HighlightedToken[] {
|
|
76
|
+
return tokens.map((token) => ({
|
|
77
|
+
content: token.content,
|
|
78
|
+
style: Object.entries(token.htmlStyle ?? {})
|
|
79
|
+
.map(([property, value]) => `${property}:${value}`)
|
|
80
|
+
.join(";"),
|
|
81
|
+
class: "text-(--shiki-light) dark:text-(--shiki-dark)",
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type Highlighter = NonNullable<Awaited<ReturnType<typeof loadHighlighter>>>;
|
|
86
|
+
|
|
87
|
+
// Loads a language and returns a highlighter for it, or null for a language
|
|
88
|
+
// that is not listed.
|
|
89
|
+
export async function loadHighlighter(language: string) {
|
|
90
|
+
const lang = getLanguage(language);
|
|
91
|
+
|
|
92
|
+
if (!lang) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const shiki = await getHighlighter();
|
|
97
|
+
|
|
98
|
+
if (lang !== "ansi" && !shiki.getLoadedLanguages().includes(lang)) {
|
|
99
|
+
await shiki.loadLanguage(languages[lang]);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
// Returns the tokens of each line, and the grammar state after the last
|
|
104
|
+
// line. Pass that state back to continue where the code left off.
|
|
105
|
+
highlight(code: string, state?: GrammarState) {
|
|
106
|
+
const tokenize = (text: string) =>
|
|
107
|
+
shiki.codeToTokens(text, {
|
|
108
|
+
lang,
|
|
109
|
+
themes: { light: "github-light", dark: "github-dark" },
|
|
110
|
+
defaultColor: false,
|
|
111
|
+
grammarState: state,
|
|
112
|
+
}).tokens;
|
|
113
|
+
|
|
114
|
+
// ANSI has no grammar state, so each line is tokenized on its own and
|
|
115
|
+
// gets the same colors whether it arrives in one piece or streams.
|
|
116
|
+
const tokens =
|
|
117
|
+
lang === "ansi" ? code.split("\n").flatMap((line) => tokenize(line)) : tokenize(code);
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
lines: tokens.map((line) => toHighlightedLine(line)),
|
|
121
|
+
state: shiki.getLastGrammarState(tokens),
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Returns the tokens of each line, or null for a language that is not listed.
|
|
128
|
+
export async function highlightCode(code: string, language: string) {
|
|
129
|
+
const highlighter = await loadHighlighter(language);
|
|
130
|
+
|
|
131
|
+
return highlighter ? highlighter.highlight(code).lines : null;
|
|
132
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadHighlighter,
|
|
3
|
+
type Highlighter,
|
|
4
|
+
type HighlightedLine,
|
|
5
|
+
} from "./highlighter.js";
|
|
6
|
+
import type { GrammarState } from "shiki/core";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Highlights `code` in `language`. `current` holds one entry per line: a plain
|
|
10
|
+
* string until the highlighter loads, then the line's tokens. Pass each one to
|
|
11
|
+
* the `code` prop of a `CodeBlock.Line`.
|
|
12
|
+
*
|
|
13
|
+
* ```svelte
|
|
14
|
+
* <script lang="ts">
|
|
15
|
+
* const lines = useHighlightedCode(() => code, () => "json");
|
|
16
|
+
* </script>
|
|
17
|
+
*
|
|
18
|
+
* {#each lines.current as line, index (index)}
|
|
19
|
+
* <CodeBlock.Line code={line} />
|
|
20
|
+
* {/each}
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function useHighlightedCode(value: () => string, language: () => string) {
|
|
24
|
+
let loaded = $state.raw<{
|
|
25
|
+
language: string;
|
|
26
|
+
highlighter: Highlighter | null;
|
|
27
|
+
} | null>(null);
|
|
28
|
+
|
|
29
|
+
$effect(() => {
|
|
30
|
+
const lang = language();
|
|
31
|
+
let cancelled = false;
|
|
32
|
+
|
|
33
|
+
loadHighlighter(lang)
|
|
34
|
+
.then((next) => {
|
|
35
|
+
if (!cancelled) {
|
|
36
|
+
loaded = { language: lang, highlighter: next };
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
.catch(() => {});
|
|
40
|
+
|
|
41
|
+
return () => {
|
|
42
|
+
cancelled = true;
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// The complete lines, highlighted. While the code streams, only the new
|
|
47
|
+
// lines are tokenized, starting from the grammar state of the last one.
|
|
48
|
+
let done: {
|
|
49
|
+
highlighter: Highlighter | null;
|
|
50
|
+
text: string;
|
|
51
|
+
lines: HighlightedLine[];
|
|
52
|
+
state?: GrammarState;
|
|
53
|
+
} = { highlighter: null, text: "", lines: [] };
|
|
54
|
+
|
|
55
|
+
const lines = $derived.by((): HighlightedLine[] => {
|
|
56
|
+
const raw = value();
|
|
57
|
+
// A trailing newline would render as an extra empty line.
|
|
58
|
+
const code = raw.endsWith("\n") ? raw.slice(0, -1) : raw;
|
|
59
|
+
const lang = language();
|
|
60
|
+
const highlighter = loaded?.language === lang ? loaded.highlighter : null;
|
|
61
|
+
|
|
62
|
+
if (!highlighter) {
|
|
63
|
+
return code.split("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let next = done;
|
|
67
|
+
|
|
68
|
+
if (next.highlighter !== highlighter || !code.startsWith(next.text)) {
|
|
69
|
+
next = { highlighter, text: "", lines: [] };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const end = code.lastIndexOf("\n") + 1;
|
|
73
|
+
|
|
74
|
+
if (end > next.text.length) {
|
|
75
|
+
const result = highlighter.highlight(code.slice(next.text.length, end - 1), next.state);
|
|
76
|
+
|
|
77
|
+
next = {
|
|
78
|
+
highlighter,
|
|
79
|
+
text: code.slice(0, end),
|
|
80
|
+
lines: [...next.lines, ...result.lines],
|
|
81
|
+
state: result.state,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
done = next;
|
|
86
|
+
|
|
87
|
+
// The last line is still being written, so it is tokenized every time.
|
|
88
|
+
const tail = code.slice(end);
|
|
89
|
+
|
|
90
|
+
return [...next.lines, highlighter.highlight(tail, next.state).lines[0]];
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
get current() {
|
|
95
|
+
return lines;
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn, type WithElementRef } from "@heyramzi/utils";
|
|
3
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
ref = $bindable(null),
|
|
7
|
+
class: className,
|
|
8
|
+
children,
|
|
9
|
+
...restProps
|
|
10
|
+
}: WithElementRef<HTMLAttributes<HTMLElement>> = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<kbd
|
|
14
|
+
bind:this={ref}
|
|
15
|
+
data-slot="kbd-group"
|
|
16
|
+
class={cn("inline-flex items-center gap-1", className)}
|
|
17
|
+
{...restProps}
|
|
18
|
+
>
|
|
19
|
+
{@render children?.()}
|
|
20
|
+
</kbd>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn, type WithElementRef } from "@heyramzi/utils";
|
|
3
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
ref = $bindable(null),
|
|
7
|
+
class: className,
|
|
8
|
+
children,
|
|
9
|
+
...restProps
|
|
10
|
+
}: WithElementRef<HTMLAttributes<HTMLElement>> = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<kbd
|
|
14
|
+
bind:this={ref}
|
|
15
|
+
data-slot="kbd"
|
|
16
|
+
class={cn(
|
|
17
|
+
"bg-muted text-muted-foreground pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm px-1 font-sans text-xs font-medium tabular-nums select-none [&_svg:not([class*='size-'])]:size-3",
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
{...restProps}
|
|
21
|
+
>
|
|
22
|
+
{@render children?.()}
|
|
23
|
+
</kbd>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Button from "./message-scroller-button.svelte";
|
|
2
|
+
import Content from "./message-scroller-content.svelte";
|
|
3
|
+
import Item from "./message-scroller-item.svelte";
|
|
4
|
+
import Provider from "./message-scroller-provider.svelte";
|
|
5
|
+
import Viewport from "./message-scroller-viewport.svelte";
|
|
6
|
+
import Root from "./message-scroller.svelte";
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
useMessageScroller,
|
|
10
|
+
useMessageScrollerScrollable,
|
|
11
|
+
useMessageScrollerVisibility,
|
|
12
|
+
} from "@shadcn-svelte/primitives/message-scroller";
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
Provider,
|
|
16
|
+
Root,
|
|
17
|
+
Viewport,
|
|
18
|
+
Content,
|
|
19
|
+
Item,
|
|
20
|
+
Button,
|
|
21
|
+
//
|
|
22
|
+
Provider as MessageScrollerProvider,
|
|
23
|
+
Root as MessageScroller,
|
|
24
|
+
Viewport as MessageScrollerViewport,
|
|
25
|
+
Content as MessageScrollerContent,
|
|
26
|
+
Item as MessageScrollerItem,
|
|
27
|
+
Button as MessageScrollerButton,
|
|
28
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MessageScroller as MessageScrollerPrimitive } from "@shadcn-svelte/primitives/message-scroller";
|
|
3
|
+
import ArrowDownIcon from "@lucide/svelte/icons/arrow-down";
|
|
4
|
+
import { Button } from "../button/index.js";
|
|
5
|
+
import type { ButtonSize, ButtonVariant } from "../button/index.js";
|
|
6
|
+
import { cn } from "@heyramzi/utils";
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
ref = $bindable(null),
|
|
10
|
+
direction = "end",
|
|
11
|
+
class: className,
|
|
12
|
+
children,
|
|
13
|
+
child: childProp,
|
|
14
|
+
variant = "outline",
|
|
15
|
+
size = "sm",
|
|
16
|
+
...restProps
|
|
17
|
+
}: MessageScrollerPrimitive.ButtonProps & {
|
|
18
|
+
variant?: ButtonVariant;
|
|
19
|
+
size?: ButtonSize;
|
|
20
|
+
} = $props();
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<MessageScrollerPrimitive.Button
|
|
24
|
+
bind:ref
|
|
25
|
+
data-slot="message-scroller-button"
|
|
26
|
+
data-direction={direction}
|
|
27
|
+
data-variant={variant}
|
|
28
|
+
data-size={size}
|
|
29
|
+
{direction}
|
|
30
|
+
class={cn(
|
|
31
|
+
"absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180",
|
|
32
|
+
className
|
|
33
|
+
)}
|
|
34
|
+
{...restProps}
|
|
35
|
+
>
|
|
36
|
+
{#snippet child(state)}
|
|
37
|
+
{#if childProp}
|
|
38
|
+
{@render childProp(state)}
|
|
39
|
+
{:else}
|
|
40
|
+
<Button {variant} {size} icon={!children} {...state.props}>
|
|
41
|
+
{#if children}
|
|
42
|
+
{@render children()}
|
|
43
|
+
{:else}
|
|
44
|
+
<ArrowDownIcon />
|
|
45
|
+
<span class="sr-only">
|
|
46
|
+
{direction === "end" ? "Scroll to end" : "Scroll to start"}
|
|
47
|
+
</span>
|
|
48
|
+
{/if}
|
|
49
|
+
</Button>
|
|
50
|
+
{/if}
|
|
51
|
+
{/snippet}
|
|
52
|
+
</MessageScrollerPrimitive.Button>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MessageScroller as MessageScrollerPrimitive } from "@shadcn-svelte/primitives/message-scroller";
|
|
3
|
+
import { cn } from "@heyramzi/utils";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
ref = $bindable(null),
|
|
7
|
+
class: className,
|
|
8
|
+
...restProps
|
|
9
|
+
}: MessageScrollerPrimitive.ContentProps = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<MessageScrollerPrimitive.Content
|
|
13
|
+
bind:ref
|
|
14
|
+
data-slot="message-scroller-content"
|
|
15
|
+
class={cn("gap-8 flex h-max min-h-full flex-col", className)}
|
|
16
|
+
{...restProps}
|
|
17
|
+
/>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MessageScroller as MessageScrollerPrimitive } from "@shadcn-svelte/primitives/message-scroller";
|
|
3
|
+
import { cn } from "@heyramzi/utils";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
ref = $bindable(null),
|
|
7
|
+
class: className,
|
|
8
|
+
scrollAnchor = false,
|
|
9
|
+
...restProps
|
|
10
|
+
}: MessageScrollerPrimitive.ItemProps = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<MessageScrollerPrimitive.Item
|
|
14
|
+
bind:ref
|
|
15
|
+
data-slot="message-scroller-item"
|
|
16
|
+
{scrollAnchor}
|
|
17
|
+
class={cn(
|
|
18
|
+
"min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]",
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...restProps}
|
|
22
|
+
/>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MessageScroller as MessageScrollerPrimitive } from "@shadcn-svelte/primitives/message-scroller";
|
|
3
|
+
|
|
4
|
+
let { ...restProps }: MessageScrollerPrimitive.ProviderProps = $props();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<MessageScrollerPrimitive.Provider {...restProps} />
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MessageScroller as MessageScrollerPrimitive } from "@shadcn-svelte/primitives/message-scroller";
|
|
3
|
+
import { cn } from "@heyramzi/utils";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
class: className,
|
|
7
|
+
ref = $bindable(null),
|
|
8
|
+
...restProps
|
|
9
|
+
}: MessageScrollerPrimitive.ViewportProps = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<MessageScrollerPrimitive.Viewport
|
|
13
|
+
bind:ref
|
|
14
|
+
data-slot="message-scroller-viewport"
|
|
15
|
+
class={cn(
|
|
16
|
+
"size-full min-h-0 min-w-0 scroll-fade-b scrollbar-thin scrollbar-gutter-stable overflow-y-auto overscroll-contain contain-content data-autoscrolling:scrollbar-thumb-transparent data-autoscrolling:scrollbar-track-transparent data-pending-scroll:invisible",
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
19
|
+
{...restProps}
|
|
20
|
+
/>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MessageScroller as MessageScrollerPrimitive } from "@shadcn-svelte/primitives/message-scroller";
|
|
3
|
+
import { cn } from "@heyramzi/utils";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
class: className,
|
|
7
|
+
ref = $bindable(null),
|
|
8
|
+
...restProps
|
|
9
|
+
}: MessageScrollerPrimitive.RootProps = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<MessageScrollerPrimitive.Root
|
|
13
|
+
bind:ref
|
|
14
|
+
data-slot="message-scroller"
|
|
15
|
+
class={cn(
|
|
16
|
+
"group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden",
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
19
|
+
{...restProps}
|
|
20
|
+
/>
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Tabs as TabsPrimitive } from "bits-ui";
|
|
3
3
|
import { cn } from "@heyramzi/utils";
|
|
4
|
+
import { slidingPill } from "../../lib/sliding-pill.js";
|
|
4
5
|
|
|
5
6
|
let {
|
|
6
7
|
ref = $bindable(null),
|
|
7
8
|
class: className,
|
|
8
9
|
size = "default",
|
|
10
|
+
children,
|
|
9
11
|
...restProps
|
|
10
12
|
}: TabsPrimitive.ListProps & {
|
|
11
13
|
/** Same steps as Button: sm 28, default 32, lg 36. */
|
|
@@ -18,8 +20,17 @@
|
|
|
18
20
|
data-slot="tabs-list"
|
|
19
21
|
data-size={size}
|
|
20
22
|
class={cn(
|
|
21
|
-
"bg-muted text-muted-foreground group/tabs-list inline-flex data-[size=sm]:h-7 data-[size=default]:h-8 data-[size=lg]:h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
|
23
|
+
"bg-muted text-muted-foreground group/tabs-list relative inline-flex data-[size=sm]:h-7 data-[size=default]:h-8 data-[size=lg]:h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
|
22
24
|
className,
|
|
23
25
|
)}
|
|
24
26
|
{...restProps}
|
|
25
|
-
|
|
27
|
+
>
|
|
28
|
+
<!-- Zero width until the attachment measures, so a server-rendered list
|
|
29
|
+
shows the trigger's own active background and never an empty pill. -->
|
|
30
|
+
<span
|
|
31
|
+
aria-hidden="true"
|
|
32
|
+
class="bg-background dark:border-input dark:bg-input/30 pointer-events-none absolute inset-y-[3px] left-0 z-0 w-0 rounded-md border border-transparent opacity-0 shadow-sm transition-[transform,width,opacity] duration-[var(--duration-fast,250ms)] ease-[var(--ease-smooth-out,cubic-bezier(0.22,1,0.36,1))] will-change-[transform,width] motion-reduce:transition-opacity"
|
|
33
|
+
{@attach slidingPill}
|
|
34
|
+
></span>
|
|
35
|
+
{@render children?.()}
|
|
36
|
+
</TabsPrimitive.List>
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
bind:ref
|
|
14
14
|
data-slot="tabs-trigger"
|
|
15
15
|
class={cn(
|
|
16
|
-
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground relative inline-flex h-full flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 text-sm group-data-[size=sm]/tabs-list:text-[0.8rem] font-medium whitespace-nowrap after:absolute after:top-1/2 after:left-0 after:h-[max(100%,2rem)] after:w-full after:-translate-y-1/2 any-pointer-coarse:after:h-[max(100%,2.75rem)] transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
16
|
+
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground group-data-[pill=on]/tabs-list:data-[state=active]:border-transparent group-data-[pill=on]/tabs-list:data-[state=active]:bg-transparent group-data-[pill=on]/tabs-list:data-[state=active]:shadow-none dark:group-data-[pill=on]/tabs-list:data-[state=active]:bg-transparent relative z-[1] inline-flex h-full flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 text-sm group-data-[size=sm]/tabs-list:text-[0.8rem] font-medium whitespace-nowrap after:absolute after:top-1/2 after:left-0 after:h-[max(100%,2rem)] after:w-full after:-translate-y-1/2 any-pointer-coarse:after:h-[max(100%,2.75rem)] transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
17
17
|
className,
|
|
18
18
|
)}
|
|
19
19
|
{...restProps}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import CollapsibleContent from "./trace-collapsible-content.svelte";
|
|
2
|
+
import CollapsibleTrigger from "./trace-collapsible-trigger.svelte";
|
|
3
|
+
import Collapsible from "./trace-collapsible.svelte";
|
|
4
|
+
import Description from "./trace-description.svelte";
|
|
5
|
+
import Icon from "./trace-icon.svelte";
|
|
6
|
+
import Title from "./trace-title.svelte";
|
|
7
|
+
import Root from "./trace.svelte";
|
|
8
|
+
import Line, { type TraceLineStatus } from "./trace-line.svelte";
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
Root,
|
|
12
|
+
Line,
|
|
13
|
+
Icon,
|
|
14
|
+
Title,
|
|
15
|
+
Description,
|
|
16
|
+
Collapsible,
|
|
17
|
+
CollapsibleTrigger,
|
|
18
|
+
CollapsibleContent,
|
|
19
|
+
type TraceLineStatus,
|
|
20
|
+
//
|
|
21
|
+
Root as Trace,
|
|
22
|
+
Line as TraceLine,
|
|
23
|
+
Icon as TraceIcon,
|
|
24
|
+
Title as TraceTitle,
|
|
25
|
+
Description as TraceDescription,
|
|
26
|
+
Collapsible as TraceCollapsible,
|
|
27
|
+
CollapsibleTrigger as TraceCollapsibleTrigger,
|
|
28
|
+
CollapsibleContent as TraceCollapsibleContent,
|
|
29
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Collapsible from "../collapsible/index.js";
|
|
3
|
+
import { cn, type WithoutChild } from "@heyramzi/utils";
|
|
4
|
+
import type { Collapsible as CollapsiblePrimitive } from "bits-ui";
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(null),
|
|
8
|
+
class: className,
|
|
9
|
+
children,
|
|
10
|
+
...restProps
|
|
11
|
+
}: WithoutChild<CollapsiblePrimitive.ContentProps> = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Collapsible.Content
|
|
15
|
+
bind:ref
|
|
16
|
+
data-slot="trace-collapsible-content"
|
|
17
|
+
class="duration-200 min-w-0 overflow-hidden [--bits-accordion-content-height:var(--bits-collapsible-content-height)] data-open:animate-accordion-down data-closed:animate-accordion-up"
|
|
18
|
+
{...restProps}
|
|
19
|
+
>
|
|
20
|
+
<div
|
|
21
|
+
data-slot="trace-collapsible-content-inner"
|
|
22
|
+
class={cn(
|
|
23
|
+
"mt-2 mb-1 ml-[calc(--spacing(2)_-_1px)] border-l pr-1 pl-4 leading-relaxed min-w-0 wrap-break-word text-muted-foreground",
|
|
24
|
+
className
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
27
|
+
{@render children?.()}
|
|
28
|
+
</div>
|
|
29
|
+
</Collapsible.Content>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Collapsible from "../collapsible/index.js";
|
|
3
|
+
import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
|
|
4
|
+
import { cn, type WithoutChild } from "@heyramzi/utils";
|
|
5
|
+
import TraceIcon from "./trace-icon.svelte";
|
|
6
|
+
import type { Collapsible as CollapsiblePrimitive } from "bits-ui";
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
ref = $bindable(null),
|
|
10
|
+
class: className,
|
|
11
|
+
children,
|
|
12
|
+
...restProps
|
|
13
|
+
}: WithoutChild<CollapsiblePrimitive.TriggerProps> = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<Collapsible.Trigger
|
|
17
|
+
bind:ref
|
|
18
|
+
data-slot="trace-collapsible-trigger"
|
|
19
|
+
class={cn(
|
|
20
|
+
"gap-1 rounded-md focus-visible:ring-3 focus-visible:ring-ring/50 group/trace-collapsible-trigger flex w-fit max-w-full min-w-0 cursor-pointer items-center text-left text-muted-foreground transition-colors outline-none hover:text-foreground has-[[data-status=error]]:text-destructive",
|
|
21
|
+
className
|
|
22
|
+
)}
|
|
23
|
+
{...restProps}
|
|
24
|
+
>
|
|
25
|
+
{@render children?.()}
|
|
26
|
+
<TraceIcon class="transition-transform group-aria-expanded/trace-collapsible-trigger:rotate-90">
|
|
27
|
+
<ChevronRightIcon />
|
|
28
|
+
</TraceIcon>
|
|
29
|
+
</Collapsible.Trigger>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Collapsible from "../collapsible/index.js";
|
|
3
|
+
import { cn } from "@heyramzi/utils";
|
|
4
|
+
import type { Collapsible as CollapsiblePrimitive } from "bits-ui";
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(null),
|
|
8
|
+
open = $bindable(false),
|
|
9
|
+
class: className,
|
|
10
|
+
...restProps
|
|
11
|
+
}: CollapsiblePrimitive.RootProps = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Collapsible.Root
|
|
15
|
+
bind:ref
|
|
16
|
+
bind:open
|
|
17
|
+
data-slot="trace-collapsible"
|
|
18
|
+
class={cn("flex w-full min-w-0 flex-col", className)}
|
|
19
|
+
{...restProps}
|
|
20
|
+
/>
|