@flikk/ui 1.0.0-beta.15 → 1.0.0-beta.16
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/README.md +52 -0
- package/dist/components/ai/StreamingResponse/AnimatedText.js +3 -3
- package/dist/components/ai/StreamingResponse/MarkdownRenderer.js +22 -22
- package/dist/components/ai/StreamingResponse/StreamingCursor.js +1 -1
- package/dist/components/ai/StreamingResponse/StreamingResponse.animations.js +10 -10
- package/dist/components/ai/StreamingResponse/StreamingResponse.js +3 -3
- package/dist/components/ai/StreamingResponse/WordAnimationContext.d.ts +1 -1
- package/dist/components/ai/StreamingResponse/WordAnimationContext.js +11 -11
- package/dist/components/ai/index.d.ts +0 -2
- package/dist/components/ai/index.js +0 -2
- package/dist/components/core/Progress/Progress.theme.js +2 -2
- package/dist/components/effects/GlassSurface/GlassSurface.js +7 -7
- package/dist/components/effects/GlassSurface/GlassSurface.types.d.ts +6 -0
- package/dist/components/effects/Neumorphic/InsetCircleButton.d.ts +2 -1
- package/dist/components/effects/Neumorphic/InsetCircleButton.js +2 -2
- package/dist/components/effects/Neumorphic/InsetPill.d.ts +2 -1
- package/dist/components/effects/Neumorphic/InsetPill.js +2 -2
- package/dist/components/forms/Slider/Slider.js +10 -3
- package/dist/components/forms/Slider/Slider.theme.js +3 -3
- package/dist/components/forms/Switch/Switch.js +10 -2
- package/dist/components/forms/Switch/Switch.theme.js +2 -2
- package/dist/components/forms/index.d.ts +0 -3
- package/dist/components/forms/index.js +0 -2
- package/dist/index.js +0 -2
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.animations.d.ts +0 -10
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.animations.js +0 -47
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.d.ts +0 -20
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.js +0 -44
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.theme.d.ts +0 -2
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.theme.js +0 -20
- package/dist/components/ai/ThinkingIndicator/ThinkingIndicator.types.d.ts +0 -67
- package/dist/components/ai/ThinkingIndicator/index.d.ts +0 -3
- package/dist/components/forms/TransferList/TransferList.animations.d.ts +0 -10
- package/dist/components/forms/TransferList/TransferList.animations.js +0 -32
- package/dist/components/forms/TransferList/TransferList.d.ts +0 -28
- package/dist/components/forms/TransferList/TransferList.js +0 -199
- package/dist/components/forms/TransferList/TransferList.theme.d.ts +0 -6
- package/dist/components/forms/TransferList/TransferList.theme.js +0 -60
- package/dist/components/forms/TransferList/TransferList.types.d.ts +0 -101
- package/dist/components/forms/TransferList/index.d.ts +0 -3
package/README.md
CHANGED
|
@@ -1 +1,53 @@
|
|
|
1
1
|
# Flikkui
|
|
2
|
+
|
|
3
|
+
A modern React component library built with TypeScript, Tailwind CSS v4, and Framer Motion. 150+ components following the shadcn philosophy with complete `className` override support.
|
|
4
|
+
|
|
5
|
+
## MCP Server
|
|
6
|
+
|
|
7
|
+
Flikkui ships with an MCP (Model Context Protocol) server that gives AI coding tools full knowledge of the component library — component APIs, props, theme tokens, and code generation.
|
|
8
|
+
|
|
9
|
+
### What It Does
|
|
10
|
+
|
|
11
|
+
| Tool | Description |
|
|
12
|
+
|------|-------------|
|
|
13
|
+
| `get_component` | Look up any component's full API — props, types, sub-components, theme tokens, and code examples |
|
|
14
|
+
| `search_components` | Find components by name, category (`core`, `forms`, `charts`, etc.), or pattern type (`compound`, `simple`, etc.) |
|
|
15
|
+
| `get_theme_tokens` | Get all CSS variables with correct Tailwind syntax (`bg-[var(--color-primary)]`) |
|
|
16
|
+
| `generate_code` | Generate production-ready Flikkui code from a description |
|
|
17
|
+
|
|
18
|
+
### Setup for Claude Code
|
|
19
|
+
|
|
20
|
+
Add the following to your project's `.mcp.json`:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"flikkui": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": ["@flikk/mcp"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or if you're working from a local clone of this repo:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"flikkui": {
|
|
39
|
+
"command": "node",
|
|
40
|
+
"args": ["./packages/mcp/dist/index.js"]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Building from Source
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cd packages/mcp
|
|
50
|
+
npm install
|
|
51
|
+
npm run extract # Parse component source files into registry.json
|
|
52
|
+
npm run build # Compile TypeScript
|
|
53
|
+
```
|
|
@@ -17,7 +17,7 @@ const tokenize = (text) => {
|
|
|
17
17
|
* For performance, only the last N tokens are animated with motion.span,
|
|
18
18
|
* while older tokens are rendered as static text.
|
|
19
19
|
*/
|
|
20
|
-
const AnimatedText = ({ text, isStreaming, animateLastN =
|
|
20
|
+
const AnimatedText = ({ text, isStreaming, animateLastN = 12, enabled = true, className, }) => {
|
|
21
21
|
const shouldReduceMotion = useReducedMotion();
|
|
22
22
|
const animate = enabled && !shouldReduceMotion;
|
|
23
23
|
// Track which tokens have already been seen/animated
|
|
@@ -37,9 +37,9 @@ const AnimatedText = ({ text, isStreaming, animateLastN = 6, enabled = true, cla
|
|
|
37
37
|
const animatedTokens = tokens.slice(settledCount);
|
|
38
38
|
if (!animate || !isStreaming) {
|
|
39
39
|
// No animation: render plain text
|
|
40
|
-
return (jsx("p", { className: className || 'whitespace-pre-wrap break-
|
|
40
|
+
return (jsx("p", { className: className || 'whitespace-pre-wrap wrap-break-word', children: text }));
|
|
41
41
|
}
|
|
42
|
-
return (jsxs("p", { className: className || 'whitespace-pre-wrap break-
|
|
42
|
+
return (jsxs("p", { className: className || 'whitespace-pre-wrap wrap-break-word', children: [settledText, animatedTokens.map((token, i) => (jsx(motion.span, { variants: tokenFadeIn, initial: "hidden", animate: "visible", transition: tokenTransition, style: { display: 'inline' }, children: token }, `${settledCount + i}-${token}`)))] }));
|
|
43
43
|
};
|
|
44
44
|
AnimatedText.displayName = 'AnimatedText';
|
|
45
45
|
|
|
@@ -51,13 +51,13 @@ const SkipWords = ({ children }) => {
|
|
|
51
51
|
* Supports GitHub Flavored Markdown (tables, task lists, strikethrough, etc.)
|
|
52
52
|
* Animates individual words during streaming with a fade-in + blur effect
|
|
53
53
|
*/
|
|
54
|
-
const MarkdownRenderer = ({ content, options = {}, isStreaming = false, animated = true, showCursor = true, animateLastN =
|
|
54
|
+
const MarkdownRenderer = ({ content, options = {}, isStreaming = false, animated = true, showCursor = true, animateLastN = 12, }) => {
|
|
55
55
|
const { allowHtml = false, syntaxTheme = 'light', renderCodeBlock } = options;
|
|
56
56
|
const shouldReduceMotion = useReducedMotion();
|
|
57
57
|
const shouldAnimate = animated && isStreaming && !shouldReduceMotion;
|
|
58
58
|
// Append cursor character to content so it renders inline within the last element
|
|
59
59
|
const displayContent = isStreaming && showCursor
|
|
60
|
-
? content + '
|
|
60
|
+
? content + ' ▏'
|
|
61
61
|
: content;
|
|
62
62
|
const markdownComponents = useMemo(() => ({
|
|
63
63
|
// Code blocks with syntax highlighting
|
|
@@ -73,75 +73,75 @@ const MarkdownRenderer = ({ content, options = {}, isStreaming = false, animated
|
|
|
73
73
|
return (jsxs(AnimatedBlock, { animate: shouldAnimate, children: [jsx(SkipWords, { children: children }), jsx(Prism, { style: syntaxTheme === 'dark' ? oneDark : oneLight, language: language, PreTag: "div", className: "rounded-lg my-3", ...props, children: String(children).replace(/\n$/, '') })] }));
|
|
74
74
|
}
|
|
75
75
|
// Inline code — skip word animation for code tokens
|
|
76
|
-
return (jsxs(Fragment, { children: [jsx(SkipWords, { children: children }), jsx("code", { className: "bg-
|
|
76
|
+
return (jsxs(Fragment, { children: [jsx(SkipWords, { children: children }), jsx("code", { className: "bg-(--color-background-tertiary) text-(--color-primary) px-1.5 py-0.5 rounded text-base font-mono", ...props, children: children })] }));
|
|
77
77
|
},
|
|
78
78
|
// Paragraphs — word-level animation
|
|
79
79
|
p({ children }) {
|
|
80
|
-
return (jsx(AnimatedProse, { as: "p", className: "mb-3 last:mb-0 text-
|
|
80
|
+
return (jsx(AnimatedProse, { as: "p", className: "mb-3 last:mb-0 text-(--color-text-primary) leading-relaxed", children: children }));
|
|
81
81
|
},
|
|
82
82
|
// Headings — word-level animation
|
|
83
83
|
h1({ children }) {
|
|
84
|
-
return (jsx(AnimatedProse, { as: "h1", className: "text-2xl font-bold mb-4 text-
|
|
84
|
+
return (jsx(AnimatedProse, { as: "h1", className: "text-2xl font-bold mb-4 text-(--color-text-primary) border-b border-(--color-border) pb-2", children: children }));
|
|
85
85
|
},
|
|
86
86
|
h2({ children }) {
|
|
87
|
-
return (jsx(AnimatedProse, { as: "h2", className: "text-2xl font-bold mb-3 text-
|
|
87
|
+
return (jsx(AnimatedProse, { as: "h2", className: "text-2xl font-bold mb-3 text-(--color-text-primary) border-b border-(--color-border) pb-2", children: children }));
|
|
88
88
|
},
|
|
89
89
|
h3({ children }) {
|
|
90
|
-
return (jsx(AnimatedProse, { as: "h3", className: "text-xl font-semibold mb-2 text-
|
|
90
|
+
return (jsx(AnimatedProse, { as: "h3", className: "text-xl font-semibold mb-2 text-(--color-text-primary)", children: children }));
|
|
91
91
|
},
|
|
92
92
|
h4({ children }) {
|
|
93
|
-
return (jsx(AnimatedProse, { as: "h4", className: "text-lg font-semibold mb-2 text-
|
|
93
|
+
return (jsx(AnimatedProse, { as: "h4", className: "text-lg font-semibold mb-2 text-(--color-text-primary)", children: children }));
|
|
94
94
|
},
|
|
95
95
|
h5({ children }) {
|
|
96
|
-
return (jsx(AnimatedProse, { as: "h5", className: "text-base font-semibold mb-2 text-
|
|
96
|
+
return (jsx(AnimatedProse, { as: "h5", className: "text-base font-semibold mb-2 text-(--color-text-primary)", children: children }));
|
|
97
97
|
},
|
|
98
98
|
h6({ children }) {
|
|
99
|
-
return (jsx(AnimatedProse, { as: "h6", className: "text-base font-semibold mb-2 text-
|
|
99
|
+
return (jsx(AnimatedProse, { as: "h6", className: "text-base font-semibold mb-2 text-(--color-text-secondary)", children: children }));
|
|
100
100
|
},
|
|
101
101
|
// Lists — word-level animation on li
|
|
102
102
|
ul({ children }) {
|
|
103
|
-
return (jsx("ul", { className: "list-disc list-inside mb-3 space-y-1 text-
|
|
103
|
+
return (jsx("ul", { className: "list-disc list-inside mb-3 space-y-1 text-(--color-text-primary)", children: children }));
|
|
104
104
|
},
|
|
105
105
|
ol({ children }) {
|
|
106
|
-
return (jsx("ol", { className: "list-decimal list-inside mb-3 space-y-1 text-
|
|
106
|
+
return (jsx("ol", { className: "list-decimal list-inside mb-3 space-y-1 text-(--color-text-primary)", children: children }));
|
|
107
107
|
},
|
|
108
108
|
li({ children }) {
|
|
109
109
|
return (jsx(AnimatedProse, { as: "li", className: "ml-4", children: children }));
|
|
110
110
|
},
|
|
111
111
|
// Blockquotes — word-level animation
|
|
112
112
|
blockquote({ children }) {
|
|
113
|
-
return (jsx("blockquote", { className: "border-l-4 border-
|
|
113
|
+
return (jsx("blockquote", { className: "border-l-4 border-(--color-primary) pl-4 py-2 my-3 bg-(--color-background-secondary) italic text-(--color-text-secondary)", children: children }));
|
|
114
114
|
},
|
|
115
115
|
// Links
|
|
116
116
|
a({ href, children }) {
|
|
117
|
-
return (jsx("a", { href: href, className: "text-
|
|
117
|
+
return (jsx("a", { href: href, className: "text-(--color-primary) hover:text-(--color-primary-700) underline transition-colors", target: "_blank", rel: "noopener noreferrer", children: children }));
|
|
118
118
|
},
|
|
119
119
|
// Tables — block-level slide-in, skip word animation
|
|
120
120
|
table({ children }) {
|
|
121
|
-
return (jsxs(AnimatedBlock, { animate: shouldAnimate, children: [jsx(SkipWords, { children: children }), jsx("div", { className: "overflow-x-auto my-3", children: jsx("table", { className: "min-w-full border-collapse border border-
|
|
121
|
+
return (jsxs(AnimatedBlock, { animate: shouldAnimate, children: [jsx(SkipWords, { children: children }), jsx("div", { className: "overflow-x-auto my-3", children: jsx("table", { className: "min-w-full border-collapse border border-(--color-border)", children: children }) })] }));
|
|
122
122
|
},
|
|
123
123
|
thead({ children }) {
|
|
124
|
-
return jsx("thead", { className: "bg-
|
|
124
|
+
return jsx("thead", { className: "bg-(--color-background-secondary)", children: children });
|
|
125
125
|
},
|
|
126
126
|
tbody({ children }) {
|
|
127
127
|
return jsx("tbody", { children: children });
|
|
128
128
|
},
|
|
129
129
|
tr({ children }) {
|
|
130
|
-
return jsx("tr", { className: "border-b border-
|
|
130
|
+
return jsx("tr", { className: "border-b border-(--color-border)", children: children });
|
|
131
131
|
},
|
|
132
132
|
th({ children }) {
|
|
133
|
-
return (jsx("th", { className: "px-4 py-2 text-left font-semibold text-
|
|
133
|
+
return (jsx("th", { className: "px-4 py-2 text-left font-semibold text-(--color-text-primary) border border-(--color-border)", children: children }));
|
|
134
134
|
},
|
|
135
135
|
td({ children }) {
|
|
136
|
-
return (jsx("td", { className: "px-4 py-2 text-
|
|
136
|
+
return (jsx("td", { className: "px-4 py-2 text-(--color-text-primary) border border-(--color-border)", children: children }));
|
|
137
137
|
},
|
|
138
138
|
// Horizontal rule
|
|
139
139
|
hr() {
|
|
140
|
-
return jsx("hr", { className: "my-4 border-t border-
|
|
140
|
+
return jsx("hr", { className: "my-4 border-t border-(--color-border)" });
|
|
141
141
|
},
|
|
142
142
|
// Strong/Bold — pass through (word animation handles inline elements)
|
|
143
143
|
strong({ children }) {
|
|
144
|
-
return jsx("strong", { className: "font-semibold text-
|
|
144
|
+
return jsx("strong", { className: "font-semibold text-(--color-text-primary)", children: children });
|
|
145
145
|
},
|
|
146
146
|
// Emphasis/Italic
|
|
147
147
|
em({ children }) {
|
|
@@ -149,7 +149,7 @@ const MarkdownRenderer = ({ content, options = {}, isStreaming = false, animated
|
|
|
149
149
|
},
|
|
150
150
|
// Strikethrough (from remarkGfm)
|
|
151
151
|
del({ children }) {
|
|
152
|
-
return jsx("del", { className: "line-through text-
|
|
152
|
+
return jsx("del", { className: "line-through text-(--color-text-secondary)", children: children });
|
|
153
153
|
},
|
|
154
154
|
}), [shouldAnimate, syntaxTheme, renderCodeBlock]);
|
|
155
155
|
return (jsx(WordAnimationProvider, { content: displayContent, enabled: shouldAnimate, animateLastN: animateLastN, hasCursor: isStreaming && showCursor, children: jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], skipHtml: !allowHtml, components: markdownComponents, children: displayContent }) }));
|
|
@@ -4,7 +4,7 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
4
4
|
* StreamingCursor renders a blinking caret that indicates active streaming.
|
|
5
5
|
* Uses a simple CSS pulse animation — no framer motion, no layout shifts.
|
|
6
6
|
*/
|
|
7
|
-
const StreamingCursor = ({ visible, enabled = true, cursor = "
|
|
7
|
+
const StreamingCursor = ({ visible, enabled = true, cursor = "▏", className, }) => {
|
|
8
8
|
if (!visible)
|
|
9
9
|
return null;
|
|
10
10
|
return (jsx("span", { className: className || `font-extralight ml-0.5 ${enabled ? "animate-pulse" : ""}`, "aria-hidden": "true", children: cursor }));
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
const tokenFadeIn = {
|
|
10
10
|
hidden: {
|
|
11
11
|
opacity: 0,
|
|
12
|
-
y:
|
|
13
|
-
filter: 'blur(
|
|
12
|
+
y: 4,
|
|
13
|
+
filter: 'blur(1.5px)',
|
|
14
14
|
},
|
|
15
15
|
visible: {
|
|
16
16
|
opacity: 1,
|
|
@@ -19,8 +19,8 @@ const tokenFadeIn = {
|
|
|
19
19
|
},
|
|
20
20
|
};
|
|
21
21
|
const tokenTransition = {
|
|
22
|
-
duration: 0.
|
|
23
|
-
ease: [0.
|
|
22
|
+
duration: 0.25,
|
|
23
|
+
ease: [0.2, 0.8, 0.2, 1], // snappy easing
|
|
24
24
|
};
|
|
25
25
|
/**
|
|
26
26
|
* Block slide-in animation
|
|
@@ -29,7 +29,7 @@ const tokenTransition = {
|
|
|
29
29
|
const blockSlideIn = {
|
|
30
30
|
hidden: {
|
|
31
31
|
opacity: 0,
|
|
32
|
-
y:
|
|
32
|
+
y: 6,
|
|
33
33
|
},
|
|
34
34
|
visible: {
|
|
35
35
|
opacity: 1,
|
|
@@ -37,8 +37,8 @@ const blockSlideIn = {
|
|
|
37
37
|
},
|
|
38
38
|
};
|
|
39
39
|
const blockTransition = {
|
|
40
|
-
duration: 0.
|
|
41
|
-
ease: [0.
|
|
40
|
+
duration: 0.35,
|
|
41
|
+
ease: [0.2, 0.8, 0.2, 1],
|
|
42
42
|
};
|
|
43
43
|
/**
|
|
44
44
|
* Streaming cursor (caret) animation
|
|
@@ -62,7 +62,7 @@ const cursorPulse = {
|
|
|
62
62
|
const inlineTokenFadeIn = {
|
|
63
63
|
hidden: {
|
|
64
64
|
opacity: 0,
|
|
65
|
-
filter: 'blur(
|
|
65
|
+
filter: 'blur(1.5px)',
|
|
66
66
|
},
|
|
67
67
|
visible: {
|
|
68
68
|
opacity: 1,
|
|
@@ -70,8 +70,8 @@ const inlineTokenFadeIn = {
|
|
|
70
70
|
},
|
|
71
71
|
};
|
|
72
72
|
const inlineTokenTransition = {
|
|
73
|
-
duration: 0.
|
|
74
|
-
ease: [0.
|
|
73
|
+
duration: 0.25,
|
|
74
|
+
ease: [0.2, 0.8, 0.2, 1],
|
|
75
75
|
};
|
|
76
76
|
/**
|
|
77
77
|
* Container animation for staggered children
|
|
@@ -39,7 +39,7 @@ onToken, onComplete, onError, onStart, onAbort,
|
|
|
39
39
|
// Display options
|
|
40
40
|
typingSpeed = 100, enableTypewriter = true, enableMarkdown = true, markdownOptions,
|
|
41
41
|
// Animation
|
|
42
|
-
animated = true, showCursor = true, animateLastN =
|
|
42
|
+
animated = true, showCursor = true, animateLastN = 12,
|
|
43
43
|
// Message component props
|
|
44
44
|
role = 'assistant', avatar, showTimestamp = true, showActions = true, onCopy, onRegenerate,
|
|
45
45
|
// Error handling
|
|
@@ -80,11 +80,11 @@ className, }) => {
|
|
|
80
80
|
}
|
|
81
81
|
else if (enableTypewriter && isComplete && accumulatedText) {
|
|
82
82
|
// Use typewriter animation after streaming completes
|
|
83
|
-
messageContent = (jsx(TypeWriter, { text: accumulatedText, speed: typingSpeed, enabled: true, className: "whitespace-pre-wrap break-
|
|
83
|
+
messageContent = (jsx(TypeWriter, { text: accumulatedText, speed: typingSpeed, enabled: true, className: "whitespace-pre-wrap wrap-break-word" }));
|
|
84
84
|
}
|
|
85
85
|
else {
|
|
86
86
|
// Show raw text (streaming complete, typewriter disabled)
|
|
87
|
-
messageContent = (jsx("p", { className: "whitespace-pre-wrap break-
|
|
87
|
+
messageContent = (jsx("p", { className: "whitespace-pre-wrap wrap-break-word", children: accumulatedText }));
|
|
88
88
|
}
|
|
89
89
|
// Render with Message component
|
|
90
90
|
return (jsx(Message, { role: role, content: messageContent, avatar: avatar, timestamp: startTimeRef.current, showTimestamp: showTimestamp, isStreaming: isStreaming, showActions: showActions && !error, onCopy: onCopy, onRegenerate: onRegenerate, className: className }));
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* inside markdown-rendered content. Works like AnimatedText but across
|
|
5
5
|
* all markdown elements (paragraphs, headings, lists, blockquotes, etc.).
|
|
6
6
|
*/
|
|
7
|
-
import React from
|
|
7
|
+
import React from "react";
|
|
8
8
|
interface WordAnimationContextValue {
|
|
9
9
|
/** Process children of a prose element, animating recent words */
|
|
10
10
|
processChildren: (children: React.ReactNode) => React.ReactNode;
|
|
@@ -18,7 +18,7 @@ const tokenize = (text) => {
|
|
|
18
18
|
const countWordsInChildren = (children) => {
|
|
19
19
|
let count = 0;
|
|
20
20
|
React__default.Children.forEach(children, (child) => {
|
|
21
|
-
if (typeof child ===
|
|
21
|
+
if (typeof child === "string") {
|
|
22
22
|
count += tokenize(child).length;
|
|
23
23
|
}
|
|
24
24
|
else if (React__default.isValidElement(child)) {
|
|
@@ -30,12 +30,12 @@ const countWordsInChildren = (children) => {
|
|
|
30
30
|
});
|
|
31
31
|
return count;
|
|
32
32
|
};
|
|
33
|
-
const WordAnimationProvider = ({ children, content, enabled, animateLastN =
|
|
33
|
+
const WordAnimationProvider = ({ children, content, enabled, animateLastN = 12, hasCursor = false, }) => {
|
|
34
34
|
const settledCountRef = useRef(0);
|
|
35
35
|
// Count total prose words in the raw content
|
|
36
36
|
const totalWords = useMemo(() => {
|
|
37
37
|
// Strip the cursor character before counting
|
|
38
|
-
const cleanContent = hasCursor ? content.replace(/\s
|
|
38
|
+
const cleanContent = hasCursor ? content.replace(/\s*▏\s*$/, "") : content;
|
|
39
39
|
return tokenize(cleanContent).length;
|
|
40
40
|
}, [content, hasCursor]);
|
|
41
41
|
// Update settled count — words that have aged out of the animation window
|
|
@@ -59,7 +59,7 @@ const WordAnimationProvider = ({ children, content, enabled, animateLastN = 6, h
|
|
|
59
59
|
*/
|
|
60
60
|
const processChildren = (children) => {
|
|
61
61
|
return React__default.Children.map(children, (child) => {
|
|
62
|
-
if (typeof child ===
|
|
62
|
+
if (typeof child === "string") {
|
|
63
63
|
return processTextNode(child);
|
|
64
64
|
}
|
|
65
65
|
if (React__default.isValidElement(child)) {
|
|
@@ -82,18 +82,18 @@ const WordAnimationProvider = ({ children, content, enabled, animateLastN = 6, h
|
|
|
82
82
|
if (tokens.length === 0)
|
|
83
83
|
return text;
|
|
84
84
|
const result = [];
|
|
85
|
-
let staticBuffer =
|
|
85
|
+
let staticBuffer = "";
|
|
86
86
|
for (const token of tokens) {
|
|
87
87
|
const currentIndex = wordIndexRef.current;
|
|
88
88
|
wordIndexRef.current++;
|
|
89
89
|
// Check if this is the cursor character
|
|
90
|
-
if (token.trim() ===
|
|
90
|
+
if (token.trim() === "▏") {
|
|
91
91
|
// Flush static buffer
|
|
92
92
|
if (staticBuffer) {
|
|
93
93
|
result.push(staticBuffer);
|
|
94
|
-
staticBuffer =
|
|
94
|
+
staticBuffer = "";
|
|
95
95
|
}
|
|
96
|
-
result.push(jsx("span", { className: "animate-pulse font-light", "aria-hidden": "true", children: "\
|
|
96
|
+
result.push(jsx("span", { className: "animate-pulse font-light", "aria-hidden": "true", children: "\u258F" }, "streaming-cursor"));
|
|
97
97
|
continue;
|
|
98
98
|
}
|
|
99
99
|
if (currentIndex < settledCount) {
|
|
@@ -104,10 +104,10 @@ const WordAnimationProvider = ({ children, content, enabled, animateLastN = 6, h
|
|
|
104
104
|
// Flush static buffer before animated tokens
|
|
105
105
|
if (staticBuffer) {
|
|
106
106
|
result.push(staticBuffer);
|
|
107
|
-
staticBuffer =
|
|
107
|
+
staticBuffer = "";
|
|
108
108
|
}
|
|
109
109
|
// Animated word
|
|
110
|
-
result.push(jsx(motion.span, { variants: inlineTokenFadeIn, initial: "hidden", animate: "visible", transition: inlineTokenTransition, style: { display:
|
|
110
|
+
result.push(jsx(motion.span, { variants: inlineTokenFadeIn, initial: "hidden", animate: "visible", transition: inlineTokenTransition, style: { display: "inline" }, children: token }, `word-${currentIndex}-${token.trim()}`));
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
// Flush any remaining static buffer
|
|
@@ -129,6 +129,6 @@ const WordAnimationProvider = ({ children, content, enabled, animateLastN = 6, h
|
|
|
129
129
|
}, [enabled, settledCount, totalWords]);
|
|
130
130
|
return (jsx(WordAnimationContext.Provider, { value: contextValue, children: children }));
|
|
131
131
|
};
|
|
132
|
-
WordAnimationProvider.displayName =
|
|
132
|
+
WordAnimationProvider.displayName = "WordAnimationProvider";
|
|
133
133
|
|
|
134
134
|
export { WordAnimationProvider, useWordAnimation };
|
|
@@ -2,8 +2,6 @@ export { Message, messageTheme } from "../core/Message";
|
|
|
2
2
|
export type { MessageProps, MessageRole, MessageVariant, MessageAvatarProps, MessageTheme, MessageThemeOverrides, } from "../core/Message";
|
|
3
3
|
export { PromptInput, promptInputTheme } from "./PromptInput";
|
|
4
4
|
export type { PromptInputProps, PromptInputState, ModelOption, PromptInputTheme, PromptInputThemeOverrides, } from "./PromptInput";
|
|
5
|
-
export { ThinkingIndicator, thinkingIndicatorTheme } from "./ThinkingIndicator";
|
|
6
|
-
export type { ThinkingIndicatorProps, ThinkingIndicatorSize, ThinkingIndicatorTheme, ThinkingIndicatorThemeOverrides, } from "./ThinkingIndicator";
|
|
7
5
|
export { TokenCounter, tokenCounterTheme, estimateTokens, calculateCost, formatCost, formatTokenCount, MODEL_CONFIGS, } from "./TokenCounter";
|
|
8
6
|
export type { TokenCounterProps, TokenCounterModel, TokenCounterSize, TokenCounterTheme, TokenCounterThemeOverrides, ModelConfig, } from "./TokenCounter";
|
|
9
7
|
export { PromptSuggestion, promptSuggestionTheme } from "./PromptSuggestions";
|
|
@@ -12,8 +12,6 @@ import '@heroicons/react/24/outline';
|
|
|
12
12
|
import '@heroicons/react/24/solid';
|
|
13
13
|
export { PromptInput } from './PromptInput/PromptInput.js';
|
|
14
14
|
export { promptInputTheme } from './PromptInput/PromptInput.theme.js';
|
|
15
|
-
export { ThinkingIndicator } from './ThinkingIndicator/ThinkingIndicator.js';
|
|
16
|
-
export { thinkingIndicatorTheme } from './ThinkingIndicator/ThinkingIndicator.theme.js';
|
|
17
15
|
export { TokenCounter } from './TokenCounter/TokenCounter.js';
|
|
18
16
|
export { tokenCounterTheme } from './TokenCounter/TokenCounter.theme.js';
|
|
19
17
|
export { MODEL_CONFIGS, calculateCost, estimateTokens, formatCost, formatTokenCount } from './TokenCounter/tokenUtils.js';
|
|
@@ -18,8 +18,8 @@ const progressTheme = {
|
|
|
18
18
|
md: "h-2.5",
|
|
19
19
|
lg: "h-4",
|
|
20
20
|
},
|
|
21
|
-
// Indeterminate animation styles
|
|
22
|
-
indeterminateStyle: "animate-[progress-indeterminate_1.8s_linear_infinite]
|
|
21
|
+
// Indeterminate animation styles
|
|
22
|
+
indeterminateStyle: "animate-[progress-indeterminate_1.8s_linear_infinite]",
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
export { progressTheme };
|
|
@@ -23,7 +23,7 @@ const useDarkMode = () => {
|
|
|
23
23
|
* Creates a realistic chromatic aberration glass effect using SVG filters.
|
|
24
24
|
* Works as a wrapper for any content.
|
|
25
25
|
*/
|
|
26
|
-
const GlassSurface = React__default.forwardRef(({ children, width, height, borderRadius = 20, borderWidth = 0.07, brightness: brightnessProp, opacity: opacityProp, blur: blurProp, displace: displaceProp, backgroundOpacity: backgroundOpacityProp, backgroundColor, saturation: saturationProp, distortionScale: distortionScaleProp, redOffset = 0, greenOffset = 10, blueOffset = 20, xChannel = "R", yChannel = "G", mixBlendMode: mixBlendModeProp, colorScheme = "auto", frosted = false, className = "", style = {}, }, forwardedRef) => {
|
|
26
|
+
const GlassSurface = React__default.forwardRef(({ children, width, height, borderRadius = 20, borderWidth = 0.07, brightness: brightnessProp, opacity: opacityProp, blur: blurProp, displace: displaceProp, backgroundOpacity: backgroundOpacityProp, backgroundColor, saturation: saturationProp, distortionScale: distortionScaleProp, redOffset = 0, greenOffset = 10, blueOffset = 20, xChannel = "R", yChannel = "G", mixBlendMode: mixBlendModeProp, colorScheme = "auto", backdropBrightness = 1, frosted = false, className = "", style = {}, }, forwardedRef) => {
|
|
27
27
|
const uniqueId = useId().replace(/:/g, "-");
|
|
28
28
|
const filterId = `glass-filter-${uniqueId}`;
|
|
29
29
|
const redGradId = `red-grad-${uniqueId}`;
|
|
@@ -66,11 +66,11 @@ const GlassSurface = React__default.forwardRef(({ children, width, height, borde
|
|
|
66
66
|
<svg viewBox="0 0 ${actualWidth} ${actualHeight}" xmlns="http://www.w3.org/2000/svg">
|
|
67
67
|
<defs>
|
|
68
68
|
<linearGradient id="${redGradId}" x1="100%" y1="0%" x2="0%" y2="0%">
|
|
69
|
-
<stop offset="0%" stop-color="#
|
|
69
|
+
<stop offset="0%" stop-color="#000"/>
|
|
70
70
|
<stop offset="100%" stop-color="red"/>
|
|
71
71
|
</linearGradient>
|
|
72
72
|
<linearGradient id="${blueGradId}" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
73
|
-
<stop offset="0%" stop-color="#
|
|
73
|
+
<stop offset="0%" stop-color="#000"/>
|
|
74
74
|
<stop offset="100%" stop-color="blue"/>
|
|
75
75
|
</linearGradient>
|
|
76
76
|
</defs>
|
|
@@ -186,8 +186,8 @@ const GlassSurface = React__default.forwardRef(({ children, width, height, borde
|
|
|
186
186
|
return {
|
|
187
187
|
...baseStyles,
|
|
188
188
|
background: getBackgroundWithOpacity(),
|
|
189
|
-
backdropFilter: `url(#${filterId}) ${frostedBlur} saturate(${saturation})`,
|
|
190
|
-
WebkitBackdropFilter: `url(#${filterId}) ${frostedBlur} saturate(${saturation})`,
|
|
189
|
+
backdropFilter: `url(#${filterId}) ${frostedBlur} brightness(${backdropBrightness}) saturate(${saturation})`,
|
|
190
|
+
WebkitBackdropFilter: `url(#${filterId}) ${frostedBlur} brightness(${backdropBrightness}) saturate(${saturation})`,
|
|
191
191
|
...(!resolvedDark && { border: "1px solid rgba(0, 0, 0, 0.06)" }),
|
|
192
192
|
...(hasCustomShadow
|
|
193
193
|
? {}
|
|
@@ -246,7 +246,7 @@ const GlassSurface = React__default.forwardRef(({ children, width, height, borde
|
|
|
246
246
|
};
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
|
-
}, [style, width, height, borderRadius, frosted, svgSupported, backgroundColor, resolvedDark, backgroundOpacity, filterId, saturation, hasCustomShadow, supportsBackdrop]);
|
|
249
|
+
}, [style, width, height, borderRadius, frosted, svgSupported, backgroundColor, resolvedDark, backgroundOpacity, filterId, backdropBrightness, saturation, hasCustomShadow, supportsBackdrop]);
|
|
250
250
|
const focusVisibleClasses = resolvedDark
|
|
251
251
|
? "focus-visible:outline-2 focus-visible:outline-[#0A84FF] focus-visible:outline-offset-2"
|
|
252
252
|
: "focus-visible:outline-2 focus-visible:outline-[#007AFF] focus-visible:outline-offset-2";
|
|
@@ -257,7 +257,7 @@ const GlassSurface = React__default.forwardRef(({ children, width, height, borde
|
|
|
257
257
|
else if (forwardedRef)
|
|
258
258
|
forwardedRef.current = node;
|
|
259
259
|
}, [forwardedRef]);
|
|
260
|
-
return (jsxs("div", { ref: mergedRef, className: cn("relative transition-opacity duration-[260ms] ease-out", focusVisibleClasses, className), style: containerStyles, children: [jsx("svg", { className: "w-full h-full pointer-events-none absolute inset-0 opacity-0 -z-10", xmlns: "http://www.w3.org/2000/svg", children: jsxs("defs", { children: [jsxs("filter", { id: filterId, colorInterpolationFilters: "sRGB", x: "0%", y: "0%", width: "100%", height: "100%", children: [jsx("feImage", { ref: feImageRef, x: "0", y: "0", width: "100%", height: "100%", preserveAspectRatio: "none", result: "map" }), jsx("feDisplacementMap", { ref: redChannelRef, in: "SourceGraphic", in2: "map",
|
|
260
|
+
return (jsxs("div", { ref: mergedRef, className: cn("relative transition-opacity duration-[260ms] ease-out", focusVisibleClasses, className), style: containerStyles, children: [jsx("svg", { className: "w-full h-full pointer-events-none absolute inset-0 opacity-0 -z-10", xmlns: "http://www.w3.org/2000/svg", children: jsxs("defs", { children: [jsxs("filter", { id: filterId, colorInterpolationFilters: "sRGB", x: "0%", y: "0%", width: "100%", height: "100%", children: [jsx("feImage", { ref: feImageRef, x: "0", y: "0", width: "100%", height: "100%", preserveAspectRatio: "none", result: "map" }), jsx("feDisplacementMap", { ref: redChannelRef, in: "SourceGraphic", in2: "map", result: "dispRed" }), jsx("feColorMatrix", { in: "dispRed", type: "matrix", values: "1 0 0 0 0\n 0 0 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0", result: "red" }), jsx("feDisplacementMap", { ref: greenChannelRef, in: "SourceGraphic", in2: "map", result: "dispGreen" }), jsx("feColorMatrix", { in: "dispGreen", type: "matrix", values: "0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0", result: "green" }), jsx("feDisplacementMap", { ref: blueChannelRef, in: "SourceGraphic", in2: "map", result: "dispBlue" }), jsx("feColorMatrix", { in: "dispBlue", type: "matrix", values: "0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0", result: "blue" }), jsx("feBlend", { in: "red", in2: "green", mode: "screen", result: "rg" }), jsx("feBlend", { in: "rg", in2: "blue", mode: "screen", result: "output" }), jsx("feGaussianBlur", { ref: gaussianBlurRef, in: "output", stdDeviation: "0.7" })] }), jsx("filter", { id: noiseFilterId, x: "0%", y: "0%", width: "100%", height: "100%", children: jsx("feTurbulence", { type: "fractalNoise", baseFrequency: "0.65", numOctaves: "3", stitchTiles: "stitch" }) })] }) }), jsx("div", { className: "relative z-10 h-full rounded-[inherit]", children: children }), jsx("div", { className: "absolute inset-0 pointer-events-none rounded-[inherit] overflow-hidden z-20", children: frosted && (jsx("div", { className: "absolute inset-0 opacity-10 mix-blend-overlay", style: { filter: `url(#${noiseFilterId})` } })) })] }));
|
|
261
261
|
});
|
|
262
262
|
GlassSurface.displayName = "GlassSurface";
|
|
263
263
|
|
|
@@ -48,6 +48,12 @@ export interface GlassSurfaceProps {
|
|
|
48
48
|
* @default 'auto'
|
|
49
49
|
*/
|
|
50
50
|
colorScheme?: "auto" | "dark" | "light";
|
|
51
|
+
/**
|
|
52
|
+
* Brightness multiplier for the backdrop-filter chain.
|
|
53
|
+
* Values > 1 brighten, < 1 darken. Only applies when SVG filters are supported.
|
|
54
|
+
* @default 1
|
|
55
|
+
*/
|
|
56
|
+
backdropBrightness?: number;
|
|
51
57
|
/**
|
|
52
58
|
* Enable frosted glass effect with noise texture
|
|
53
59
|
* @default false
|
|
@@ -5,5 +5,6 @@ export interface InsetCircleButtonProps {
|
|
|
5
5
|
className?: string;
|
|
6
6
|
classNameDisc?: string;
|
|
7
7
|
classNameHover?: string;
|
|
8
|
+
onClick?: () => void;
|
|
8
9
|
}
|
|
9
|
-
export declare function InsetCircleButton({ children, size, className, classNameDisc, classNameHover, }: InsetCircleButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function InsetCircleButton({ children, size, className, classNameDisc, classNameHover, onClick, }: InsetCircleButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,8 +3,8 @@ import { motion } from 'motion/react';
|
|
|
3
3
|
import { cn } from '../../../utils/cn.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
6
|
-
function InsetCircleButton({ children, size = 44, className, classNameDisc, classNameHover, }) {
|
|
7
|
-
return (jsx("div", { className: cn("neu-circle-groove group shrink-0 cursor-pointer bg-neutral-200/80 dark:bg-neutral-900", className), style: { width: size, height: size }, children: jsxs(motion.div, { className: cn("neu-circle-disc bg-linear-to-br from-neutral-100 to-neutral-300 dark:from-neutral-700 dark:to-neutral-900", classNameDisc), whileHover: { scale: 1 }, whileTap: { scale: 0.975 }, transition: { type: "spring", stiffness: 200, damping: 20 }, children: [jsx("div", { className: cn("absolute inset-0 rounded-full bg-linear-to-br from-neutral-300 to-neutral-200 dark:from-neutral-900 dark:to-neutral-700 opacity-0 group-hover:opacity-100 transition-opacity duration-300", classNameHover) }), jsx("div", { className: "relative z-2", children: children })] }) }));
|
|
6
|
+
function InsetCircleButton({ children, size = 44, className, classNameDisc, classNameHover, onClick, }) {
|
|
7
|
+
return (jsx("div", { className: cn("neu-circle-groove group shrink-0 cursor-pointer bg-neutral-200/80 dark:bg-neutral-900", className), style: { width: size, height: size }, onClick: onClick, children: jsxs(motion.div, { className: cn("neu-circle-disc bg-linear-to-br from-neutral-100 to-neutral-300 dark:from-neutral-700 dark:to-neutral-900", classNameDisc), whileHover: { scale: 1 }, whileTap: { scale: 0.975 }, transition: { type: "spring", stiffness: 200, damping: 20 }, children: [jsx("div", { className: cn("absolute inset-0 rounded-full bg-linear-to-br from-neutral-300 to-neutral-200 dark:from-neutral-900 dark:to-neutral-700 opacity-0 group-hover:opacity-100 transition-opacity duration-300", classNameHover) }), jsx("div", { className: "relative z-2", children: children })] }) }));
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export { InsetCircleButton };
|
|
@@ -3,5 +3,6 @@ export interface InsetPillProps {
|
|
|
3
3
|
children: React.ReactNode;
|
|
4
4
|
className?: string;
|
|
5
5
|
padding?: string;
|
|
6
|
+
onClick?: () => void;
|
|
6
7
|
}
|
|
7
|
-
export declare function InsetPill({ children, className, padding, }: InsetPillProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function InsetPill({ children, className, padding, onClick, }: InsetPillProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
|
|
3
|
-
function InsetPill({ children, className, padding = "10px 18px", }) {
|
|
4
|
-
return (jsx("div", { className: `neu-inset inline-flex items-center gap-2 cursor-pointer rounded-full bg-neutral-200/60 dark:bg-neutral-800/80 ${className !== null && className !== void 0 ? className : ""}`, style: { padding }, children: jsx("div", { className: "relative z-2 flex items-center gap-2", children: children }) }));
|
|
3
|
+
function InsetPill({ children, className, padding = "10px 18px", onClick, }) {
|
|
4
|
+
return (jsx("div", { className: `neu-inset inline-flex items-center gap-2 cursor-pointer rounded-full bg-neutral-200/60 dark:bg-neutral-800/80 ${className !== null && className !== void 0 ? className : ""}`, style: { padding }, onClick: onClick, children: jsx("div", { className: "relative z-2 flex items-center gap-2", children: children }) }));
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export { InsetPill };
|
|
@@ -216,18 +216,25 @@ const Slider = React__default.forwardRef(({ state = "default", className = "", l
|
|
|
216
216
|
}
|
|
217
217
|
return `${currentValue}${unit}`;
|
|
218
218
|
};
|
|
219
|
-
|
|
219
|
+
const filterId = `slider-liquid-lens-${sliderId}`;
|
|
220
|
+
return (jsxs("div", { className: cn(mergedTheme.wrapperStyle, wrapperClassName), ref: ref, ...props, children: [jsx("svg", { width: "0", height: "0", className: "absolute", "aria-hidden": "true", children: jsx("defs", { children: jsxs("filter", { id: filterId, children: [jsx("feGaussianBlur", { in: "SourceGraphic", stdDeviation: "1", result: "blur" }), jsx("feColorMatrix", { in: "blur", type: "matrix", values: "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7", result: "goo" }), jsx("feComposite", { in: "SourceGraphic", in2: "goo", operator: "atop" })] }) }) }), label && (jsx(FormLabel, { htmlFor: sliderId, required: required, className: cn(mergedTheme.labelStyle, labelClassName), children: label })), jsxs("div", { className: "flex items-center gap-4", children: [iconStart && (jsx("div", { className: "flex-shrink-0 text-[var(--color-text-muted)]", children: iconStart })), showMinMax && (jsx("span", { className: cn(mergedTheme.minMaxLabelStyle), children: min })), jsxs("div", { className: cn(mergedTheme.rootStyle, className), "data-disabled": isDisabled || undefined, "data-invalid": isInvalid || undefined, "data-orientation": "horizontal", children: [jsxs("div", { ref: trackRef, className: mergedTheme.trackStyle, onPointerDown: handleTrackClick, role: "presentation", children: [jsx("div", { className: mergedTheme.rangeStyle, style: getFilledTrackStyle() }), showTicks &&
|
|
220
221
|
ticks.map((tick) => {
|
|
221
222
|
const percentage = getPercentage(tick);
|
|
222
223
|
return (jsx("div", { className: mergedTheme.tickStyle, style: { left: `${percentage}%` } }, tick));
|
|
223
224
|
})] }), values.map((val, index) => {
|
|
224
225
|
const percentage = getPercentage(val);
|
|
225
|
-
return (
|
|
226
|
+
return (jsxs("div", { className: cn(mergedTheme.thumbStyle, "outline-[2px] outline-[var(--color-border)]/80 ring-0 shadow-lg p-0"), style: {
|
|
226
227
|
left: `${percentage}%`,
|
|
227
228
|
transform: "translate(-50%, -50%)",
|
|
228
229
|
position: "absolute",
|
|
229
230
|
top: "50%",
|
|
230
|
-
}, onPointerDown: (e) => handlePointerDown(e, index), onKeyDown: (e) => handleKeyDown(e, index), role: "slider", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": val, "aria-orientation": "horizontal", "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (range ? `Slider thumb ${index + 1}` : "Slider"), "aria-labelledby": ariaLabelledby, "aria-describedby": ariaDescribedby !== null && ariaDescribedby !== void 0 ? ariaDescribedby : helperTextId, tabIndex: isDisabled ? -1 : 0, "data-disabled": isDisabled || undefined, "data-invalid": isInvalid || undefined
|
|
231
|
+
}, onPointerDown: (e) => handlePointerDown(e, index), onKeyDown: (e) => handleKeyDown(e, index), role: "slider", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": val, "aria-orientation": "horizontal", "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (range ? `Slider thumb ${index + 1}` : "Slider"), "aria-labelledby": ariaLabelledby, "aria-describedby": ariaDescribedby !== null && ariaDescribedby !== void 0 ? ariaDescribedby : helperTextId, tabIndex: isDisabled ? -1 : 0, "data-disabled": isDisabled || undefined, "data-invalid": isInvalid || undefined, children: [jsx("div", { className: "absolute inset-0 z-0 rounded-full", style: {
|
|
232
|
+
backdropFilter: "blur(0.6px)",
|
|
233
|
+
WebkitBackdropFilter: "blur(0.6px)",
|
|
234
|
+
filter: `url(#${filterId})`,
|
|
235
|
+
}, "aria-hidden": "true" }), jsx("div", { className: "absolute inset-0 z-[1] rounded-full bg-[var(--color-surface)]/90", "aria-hidden": "true" }), jsx("div", { className: "absolute inset-0 z-[2] rounded-full", style: {
|
|
236
|
+
boxShadow: "inset 1px 1px 0 rgba(255,255,255,0.35), inset 1px 3px 0 rgba(0,0,0,0.03), inset 0 0 14px rgba(255,255,255,0.25), inset -1px -1px 0 rgba(0,0,0,0.06)",
|
|
237
|
+
}, "aria-hidden": "true" })] }, index));
|
|
231
238
|
}), name && (jsx("input", { type: "hidden", name: name, value: Array.isArray(currentValue)
|
|
232
239
|
? currentValue.join(",")
|
|
233
240
|
: currentValue }))] }), showMinMax && (jsx("span", { className: cn(mergedTheme.minMaxLabelStyle), children: max })), showValue && (jsx("div", { className: cn(mergedTheme.valueDisplayStyle), children: formatValueDisplay() })), iconEnd && (jsx("div", { className: "flex-shrink-0 text-[var(--color-text-muted)]", children: iconEnd }))] }), helperText && (jsx("div", { id: helperTextId, className: cn(mergedTheme.helperTextStyle, helperTextClassName), children: helperText }))] }));
|
|
@@ -10,17 +10,17 @@ const sliderTheme = {
|
|
|
10
10
|
// Root container with layout
|
|
11
11
|
rootStyle: "relative flex items-center w-full touch-none select-none data-[orientation=vertical]:flex-col data-[orientation=vertical]:h-full",
|
|
12
12
|
// Track (background)
|
|
13
|
-
trackStyle: "relative w-full h-2 grow rounded-full bg-[var(--color-background-tertiary)] overflow-hidden data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[orientation=vertical]:w-2 data-[orientation=vertical]:h-full",
|
|
13
|
+
trackStyle: "relative w-full h-2 grow rounded-full bg-[var(--color-background-tertiary)] overflow-hidden data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[orientation=vertical]:w-2 data-[orientation=vertical]:h-full shadow-inner",
|
|
14
14
|
// Range (filled portion) - rounded to match track clipping
|
|
15
15
|
rangeStyle: "absolute h-full bg-gradient-to-r from-[var(--color-primary-500)] to-[var(--color-primary-700)] transition-all rounded-full data-[disabled]:bg-[var(--color-background-disabled)] data-[invalid]:bg-[var(--color-danger)]",
|
|
16
16
|
// Thumb (draggable handle)
|
|
17
|
-
thumbStyle: "block h-5 w-
|
|
17
|
+
thumbStyle: "block h-5 w-7 rounded-full bg-transparent overflow-hidden cursor-grab active:cursor-grabbing active:scale-x-110 active:scale-y-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border)] focus-visible:ring-offset-2 transition-all hover:scale-110 data-[disabled]:cursor-not-allowed data-[disabled]:hover:scale-100 data-[invalid]:focus-visible:ring-[var(--color-danger)]",
|
|
18
18
|
// Value display
|
|
19
19
|
valueDisplayStyle: "text-base font-medium text-[var(--color-text-secondary)] w-fit min-w-12",
|
|
20
20
|
// Min/max labels
|
|
21
21
|
minMaxLabelStyle: "text-base font-medium text-[var(--color-text-muted)]",
|
|
22
22
|
// Tick marks
|
|
23
|
-
tickStyle: "absolute w-0.5 h-2 bg-
|
|
23
|
+
tickStyle: "absolute w-0.5 h-2 bg-[var(--color-border)] -translate-x-0.5 pointer-events-none",
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
export { sliderTheme };
|